Source for file SessionUtil.class.php
Documentation is available at SessionUtil.class.php
* Zikula Application Framework
* @copyright (c) 2001, Zikula Development Team
* @link http://www.zikula.org
* @version $Id: SessionUtil.class.php 24342 2008-06-06 12:03:14Z markwest $
* @license GNU/GPL - http://www.gnu.org/copyleft/gpl.html
* @subpackage SessionUtil
* @subpackage SessionUtil
* Set up session handling
* Set all PHP options for Zikula session handling
} elseif (substr($path, - 1, 1) != '/') {
if (($pos= strpos($host, ':')) !== false) {
$host = substr($host, 0, $pos);
// PHP configuration variables
ini_set('session.use_trans_sid', 0); // Stop adding SID to URLs
@ini_set('url_rewriter.tags', ''); // some environments dont allow this value to be set causing an error that prevents installation
ini_set('session.serialize_handler', 'php'); // How to store data
ini_set('session.use_cookies', 1); // Use cookie to store the session ID
ini_set('session.auto_start', 1); // Auto-start session
// Set lifetime of session cookie
// Session lasts duration of browser
// ini_set('session.referer_check', $host.$path);
ini_set('session.referer_check', $host);
// Session lasts set number of days
// Session lasts unlimited number of days (well, lots, anyway)
// (Currently set to 25 years)
ini_set('session.cookie_lifetime', $lifetime);
// domain and path settings for session cookie
// if (pnConfigGetVar('intranet') == false) {
ini_set('session.cookie_path', $path);
ini_set('session.gc_divisor', 10000);
ini_set('session.gc_maxlifetime', pnConfigGetVar('secinactivemins') * 60); // Inactivity timeout for user sessions
// change session hash length according to PHP version
// (uncommend this line after 0.8.0.0 is released - ini_set('session.hash_function', (((float)phpversion() >= 5) ? 1 : 0));
ini_set('session.hash_function', 0);
// Set custom session handlers
ini_set('session.save_handler', 'user');
// Do not call any of these functions directly. Marked as private with _
'_SessionUtil__Write', /* use session_write_close(); */
'_SessionUtil__Destroy', /* use session_destroy(); */
// First thing we do is ensure that there is no attempted pollution
// of the session namespace
foreach($GLOBALS as $k => $v) {
if (substr($k, 0, 4) == 'PNSV') {
// create IP finger print
/* -- feature for after 0.8 release - drak
// todo - add dropdown option for sessionipcheckmask for /32, /24, /16 CIDR
$ipmask = pnConfigGetVar('sessionipcheckmask');
// since we're not a /32 we need to handle in case multiple ips returned
if ($_HTTP_X_FORWARDED_FOR && strstr($_HTTP_X_FORWARDED_FOR, ', ')) {
$_ips = explode(', ', $_HTTP_X_FORWARDED_FOR);
$_HTTP_X_FORWARDED_FOR = $_ips[0];
// apply CIDR mask to allow IP checks on clients assigned
// dynamic IP addresses - e.g. A O *cough* L
$_REMOTE_ADDR = preg_replace('/[^.]+.$/', '*', $_REMOTE_ADDR);
$_HTTP_X_FORWARDED_FOR = ($_HTTP_X_FORWARDED_FOR ? preg_replace('/[^.]+.$/', '*', $_HTTP_X_FORWARDED_FOR) : '');
} else if ($ipmask == 16) {
$_REMOTE_ADDR = preg_replace('/[0-9]*.\.[^.]+.$/', '*', $_REMOTE_ADDR);
$_HTTP_X_FORWARDED_FOR = ($_HTTP_X_FORWARDED_FOR ? preg_replace('/[0-9]*.\.[^.]+.$/', '*', $fullhost) : '');
} else { // must be a /32 CIDR
// create the ip fingerprint
$current_ipaddr = md5($_REMOTE_ADDR. $_HTTP_X_FORWARDED_FOR);
// start session check expiry and ip fingerprint if required
if (session_start() && isset ($GLOBALS['_PNSession']['obj']) && $GLOBALS['_PNSession']['obj']) {
// check if session has expired or not
$lastused = strtotime ($GLOBALS['_PNSession']['obj']['lastused']);
$uid = $GLOBALS['_PNSession']['obj']['uid'];
$ipaddr = $GLOBALS['_PNSession']['obj']['ipaddr'];
if ($ipaddr !== $current_ipaddr) {
// Low security - users stay logged in permanently
// no special check necessary
// Medium security - delete session info if session cookie has
// expired or user decided not to remember themself and inactivity timeout
// OR max number of days have elapsed without logging back in
if ((!$rememberme && $lastused < $inactive) || ($lastused < $daysold) || ($uid == '0' && $lastused < $inactive))
// High security - delete session info if user is inactive
if ($rememberme && ($lastused < $inactive)) {
// *must* regenerate new session otherwise the default sessid will be
// taken from any session cookie that was submitted (bad bad bad)
if (isset ($_SESSION['_PNSession']['obj'])) {
unset ($_SESSION['_PNSession']['obj']);
* @param sessid $ the session ID
* @param ipaddr $ the IP address of the host with this session
function _createNew($sessid, $ipaddr)
$obj = array('sessid' => $sessid,
$GLOBALS['_PNSession']['obj'] = $obj;
$GLOBALS['_PNSession']['new'] = true;
// Generate a random number, used for some authentication (using prime numer bounds)
// write hash of useragent into the session for later validation
// init status & error message arrays
* @param sring $name of the session variable to get
* @param string $default the default value to return if the requested session variable is not set
* @param autocreate $autocreate whether or not to autocreate the supplied path (optional) (default=true)
* @param overwriteExistingVar $overwriteExistingVar whether or not to overwrite existing/set variable entries which the given path requires to be arrays (optional) (default=false)
* @return string session variable requested
function getVar($name, $default= false, $path= '/', $autocreate= true, $overwriteExistingVar= false)
if ($path == '/' || $path === '') {
if (isset ($_SESSION['PNSV' . $name])) {
return $_SESSION['PNSV' . $name];
$parent = & SessionUtil::_resolvePath ($path, $autocreate, $overwriteExistingVar);
if ($parent === false) { // path + autocreate or overwriteExistingVar Error
if (isset ($parent[$name])) {
$parent[$name] = $default;
* @param string $name of the session variable to set
* @param value $value to set the named session variable
* @param path $path to traverse to reach the element we wish to return (optional) (default='/')
* @param autocreate $autocreate whether or not to autocreate the supplied path (optional) (default=true)
* @param overwriteExistingVar $overwriteExistingVar whether or not to overwrite existing/set variable entries which the given path requires to be arrays (optional) (default=false)
* @return bool true upon success, false upon failure
function setVar($name, $value, $path= '/', $autocreate= true, $overwriteExistingVar= false)
if (($name == 'errormsg' || $name == 'statusmsg' || $name == '_PNErrorMsg' || $name == '_PNStatusMsg') && !is_array($value)) {
if ($PNConfig['System']['development']) {
LogUtil::log ('This use of SessionUtil::setVar() is no longer valid ... please use the LogUtil API to manipulate status/error messages');
if ($name == '_PNErrorMsg' || $name == 'errormsg') {
if ($name == '_PNStatusMsg' || $name == 'statusmsg') {
// temporary fix for bug #3770
// $value = str_replace('\\', '/', $value);
// cause session on regeration on uid change
if ($path == '/' || $path === '') {
$_SESSION['PNSV' . $name] = $value;
$parent = & SessionUtil::_resolvePath ($path, $autocreate, $overwriteExistingVar);
if ($parent === false) { // path + autocreate or overwriteExistingVar Error
* Delete a session variable
* @param string $name of the session variable to delete
* @param string $default the default value to return if the requested session variable is not set
* @param path $path to traverse to reach the element we wish to return (optional) (default='/')
function delVar($name, $default= false, $path= '/')
if ($path == '/' || $path === '') {
if (isset ($_SESSION['PNSV' . $name])) {
$value = $_SESSION['PNSV' . $name];
unset ($_SESSION['PNSV' . $name]);
$parent = & SessionUtil::_resolvePath ($path, false, false);
if ($parent === false) { // path + autocreate or overwriteExistingVar Error
if (isset ($parent[$name])) {
// unset if registerglobals are on
unset ($GLOBALS['PNSV' . $name]);
* Traverse the session data structure according to the path given and return a reference to last object in the path
* @param path $path to traverse to reach the element we wish to return
* @param autocreate $autocreate whether or not to autocreate the supplied path (optional) (default=true)
* @param overwriteExistingVar $overwriteExistingVar whether or not to overwrite existing/set variable entries which the given path requires to be arrays (optional) (default=false)
* @return mixed array upon successful location/creation of path element(s), false upon failure
function &_resolvePath ($path, $autocreate= true, $overwriteExistingVar= false)
// now traverse down the path and set the var
if ($path == '/' || !$path) {
// remove leading '/' so that explode doesn't deliver an empty 1st element
if (strpos($path, '/') === 0) {
$pFixed = ($c== 0 ? 'PNSV' . $p : $p);
if (!isset ($parent[$pFixed])) {
$parent[$pFixed] = array();
$parent = & $parent[$pFixed];
if ($overwriteExistingVar) {
$parent[$pFixed] = array();
$parent = & $parent[$pFixed];
* Starts a session or terminates loading.
// check if we need to create a session
// session initialization failed so display templated error
header('HTTP/1.1 503 Service Unavailable');
if (file_exists('config/templates/sessionfailed.htm')) {
* Let session expire nicely
// no need to do anything for guests without sessions
// no need to display expiry for anon users with sessions since it's invisible anyway
// handle expired sessions differently
// session is not new, remove flag
unset ($GLOBALS['_PNSession']['new']);
// for all logged in users with session destroy session and set flag
$GLOBALS['_PNSession']['expired'] = true;
* Check if a session has expired or not
if (isset ($GLOBALS['_PNSession']['expired']) && $GLOBALS['_PNSession']['expired']) {
unset ($GLOBALS['_PNSession']);
* @param bool $force default false force regeneration
// only regenerate if set in admin
// there is no point changing a newly generated session.
if (isset ($GLOBALS['_PNSession']['new']) && $GLOBALS['_PNSession']['new'] == true) {
// dont allow multiple regerations
if (isset ($GLOBALS['_PNSession']['regenerated']) && $GLOBALS['_PNSession']['regenerated'] == true) {
$GLOBALS['_PNSession']['sessid_old'] = session_id(); // save old session id
// need to handle php < 4.3.3 bug that doesnt issue
// session cookie to browser after regeneration [drak]
$GLOBALS['_PNSession']['obj']['sessid'] = session_id(); // commit new sessid
$GLOBALS['_PNSession']['regenerated'] = true; // flag regeneration
* Regenerate session according to probability set by admin
* Define the name of our session cookie
// Include number of dots in session name such that we use a different session for
// www.domain.xx and domain.xx. Otherwise we run into problems with both cookies for
// www.domain.xx as well as domain.xx being sent to www.domain.xx simultaneously!
// emulate session_regenerate_id function if missing
* @return string session_id
$len = (ini_get('session.hash_function') == 0) ? 32 : 40;
/* Following _Session__* API are for internal class use. Do not call directly */
* PHP function to start the session
function _SessionUtil__Start($path, $name)
* PHP function to close the session
function _SessionUtil__Close()
* PHP function to read a set of session variables
* @param string $sessid session id
* @return mixed bool of false or string session variable if true
function _SessionUtil__Read($sessid)
// if (pnConfigGetVar('anonymoussessions') == '0') {
if (is_array($result) && isset ($result['sessid'])) {
$GLOBALS['_PNSession']['obj'] = array('sessid' => $result['sessid'],
'ipaddr' => $result['ipaddr'],
'lastused' => $result['lastused']);
// security feature to change session id's periodically
return (isset ($result['vars']) ? $result['vars'] : '');
* PHP function to write a set of session variables
* DO NOT CALL THIS DIRECTLY use session_write_close()
* @param string $sessid session id
* @param string $vars session variables
function _SessionUtil__Write($sessid, $vars)
$obj = $GLOBALS['_PNSession']['obj'];
$obj['lastused'] = date('Y-m-d H:i:s', time());
// if session was regenerate, delete it first
if (isset ($GLOBALS['_PNSession']['regenerated']) && $GLOBALS['_PNSession']['regenerated'] == true) {
if ($fp = @fopen("$path/$sessid", "w")) {
if (isset ($GLOBALS['_PNSession']['new']) && $GLOBALS['_PNSession']['new'] == true) {
unset ($GLOBALS['_PNSession']['new']);
// check for regenerated session and update ID in database
if (isset ($GLOBALS['_PNSession']['regenerated']) && $GLOBALS['_PNSession']['regenerated'] == true) {
$columns = $sessiontable['session_info_column'];
* PHP function to destroy a session
* DO NOT CALL THIS FUNCTION DIRECTLY use session_destory();
* @param string $sessid session id
function _SessionUtil__Destroy($sessid)
if (isset ($GLOBALS['_PNSession'])) {
unset ($GLOBALS['_PNSession']);
// can exit if anon user and anon session disabled
// ensure we delete the stored session (not a regenerated one)
if (isset ($GLOBALS['_PNSession']['regenerated']) && $GLOBALS['_PNSession']['regenerated'] == true) {
$sessid = $GLOBALS['_PNSession']['sessid_old'];
return unlink("$path/$sessid");
* PHP function to garbage collect session information
* @param int $maxlifetime maxlifetime of the session
function _SessionUtil__GC($maxlifetime)
// find the hash length dynamically
$hash = ini_get('session.hash_function');
if (empty($hash) || $hash == 0) {
while (false !== ($file = readdir($handle))) {
if ($file != '.' && $file != '..' && strlen($file) == $sessionlength) {
// filename, created, last modified
$files[] = array('name' => $file,
// check we have something to do
if (count($files) == 0) {
// Low security - delete session info if user decided not to
// remember themself and session is inactive
foreach ($files as $file) {
$lastused = $file['lastused'];
if ($lastused < $inactive && !isset ($session['PNSVrememberme'])) {
// Medium security - delete session info if session cookie has
// expired or user decided not to remember themself and inactivity timeout
// OR max number of days have elapsed without logging back in
foreach ($files as $file) {
$lastused = $file['lastused'];
if ($lastused < $inactive && !isset ($session['PNSVrememberme'])) {
if (($lastused < $daysold)) {
// High security - delete session info if user is inactive
foreach ($files as $file) {
$lastused = $file['lastused'];
if ($lastused < $inactive) {
$sessioninfocolumn = $pntable['session_info_column'];
// Low security - delete session info if user decided not to
// remember themself and inactivity timeout
$where = "WHERE $sessioninfocolumn[remember] = 0
AND $sessioninfocolumn[lastused] < '$inactive'";
// Medium security - delete session info if session cookie has
// expired or user decided not to remember themself and inactivity timeout
// OR max number of days have elapsed without logging back in
$where = "WHERE ($sessioninfocolumn[remember] = 0
AND $sessioninfocolumn[lastused] < '$inactive')
OR ($sessioninfocolumn[lastused] < '$daysold')
OR ($sessioninfocolumn[uid] = 0 AND $sessioninfocolumn[lastused] < '$inactive')";
// High security - delete session info if user is inactive
$where = "WHERE $sessioninfocolumn[lastused] < '$inactive'";
/* Legacy APIs to be removed at a later date */
* @see SessionUtil::getVar
* @param sring $name of the session variable to get
* @param string $default the default value to return if the requested session variable is not set
* @return string session variable requested
* @see SessionUtil::setVar
* @param string $name of the session variable to set
* @param value $value to set the named session variable
* Delete a session variable
* @see SessionUtil::delVar
* @param string $name of the session variable to delete
|