diff --git a/phpgwapi/inc/class.sessions_php4.inc.php b/phpgwapi/inc/class.sessions_php4.inc.php index 6c48f74f0c..6c8eb9d30e 100644 --- a/phpgwapi/inc/class.sessions_php4.inc.php +++ b/phpgwapi/inc/class.sessions_php4.inc.php @@ -1,326 +1,339 @@ - * @author Joseph Engo - * @author Ralf Becker - * @copyright © 1998-2000 NetUSE AG Boris Erdmann, Kristian Koehntopp
© 2003 FreeSoftware Foundation - * @license LGPL - * @version $Id$ - */ + /** +* eGW's Session Management +* +* This allows eGroupWare to use php or database sessions +* +* @link www.egroupware.org +* @author NetUSE AG Boris Erdmann, Kristian Koehntopp +* @author Dan Kuykendall +* @author Joseph Engo +* @author Ralf Becker +* @copyright © 1998-2000 NetUSE AG Boris Erdmann, Kristian Koehntopp
© 2003 FreeSoftware Foundation +* @license LGPL +* @version $Id$ +*/ - define('EGW_SESSION_VAR','egw_session'); // where to store our session-data $_SESSION[EGW_SESSION_VAR] +define('EGW_SESSION_VAR','egw_session'); // where to store our session-data $_SESSION[EGW_SESSION_VAR] + +/** +* Session Management via php sessions +* +* @package api +* @subpackage sessions +*/ +class sessions extends sessions_ +{ + var $save_session_vars_start; + + function sessions($domain_names=null) + { + $this->save_session_vars_start = $_SESSION; // store already set session vars + + $this->sessions_($domain_names); + //controls the time out for php4 sessions - skwashd 18-May-2003 + ini_set('session.gc_maxlifetime', $GLOBALS['egw_info']['server']['sessions_timeout']); + session_name('sessionid'); + } /** - * Session Management via php sessions + * commit the sessiondata to the filesystem * - * @package api - * @subpackage sessions + * @return bool */ - class sessions extends sessions_ + function commit_session() { + session_write_close(); + return true; + } - function sessions($domain_names=null) + function read_session() + { + if (!$this->sessionid) { - $this->sessions_($domain_names); - //controls the time out for php4 sessions - skwashd 18-May-2003 - ini_set('session.gc_maxlifetime', $GLOBALS['egw_info']['server']['sessions_timeout']); - session_name('sessionid'); + return False; + } + session_id($this->sessionid); + session_start(); + return $_SESSION[EGW_SESSION_VAR]; + } + + /** + * Set paramaters for cookies - only implemented in PHP4 sessions + * + * @param string $domain domain name to use in cookie + * @param string $path='/' path to use in cookie + */ + function set_cookie_params($domain,$path='/') + { + session_set_cookie_params(0,$path,$domain); + } + + /** + * Create a new session id, called by session::create() + * + * Reimplemented to use php session-id + * + * @return string a new session id + */ + function new_session_id() + { + session_start(); + + return session_id(); + } + + function register_session($login,$user_ip,$now,$session_flags) + { + // restore session vars set before session was started + if ($this->save_session_vars_start && is_array($this->save_session_vars_start)) + { + foreach($this->save_session_vars_start as $name => &$value) + { + //error_log(__METHOD__."() added $name=".array2string($value)); + $_SESSION[$name] =& $value; + } + unset($this->save_session_vars_start); + } + $_SESSION[EGW_SESSION_VAR]['session_id'] = $this->sessionid; + $_SESSION[EGW_SESSION_VAR]['session_lid'] = $login; + $_SESSION[EGW_SESSION_VAR]['session_ip'] = $user_ip; + $_SESSION[EGW_SESSION_VAR]['session_logintime'] = $now; + $_SESSION[EGW_SESSION_VAR]['session_dla'] = $now; + $_SESSION[EGW_SESSION_VAR]['session_action'] = $_SERVER['PHP_SELF']; + $_SESSION[EGW_SESSION_VAR]['session_flags'] = $session_flags; + // we need the install-id to differ between serveral installs shareing one tmp-dir + $_SESSION[EGW_SESSION_VAR]['session_install_id'] = $GLOBALS['egw_info']['server']['install_id']; + } + + // This will update the DateLastActive column, so the login does not expire + function update_dla() + { + if (@isset($_GET['menuaction'])) + { + $action = $_GET['menuaction']; + } + else + { + $action = $_SERVER['PHP_SELF']; } - /** - * commit the sessiondata to the filesystem - * - * @return bool - */ - function commit_session() { - session_write_close(); - return true; + // This way XML-RPC users aren't always listed as + // xmlrpc.php + if ($this->xmlrpc_method_called) + { + $action = $this->xmlrpc_method_called; } - function read_session() + $_SESSION[EGW_SESSION_VAR]['session_dla'] = time(); + $_SESSION[EGW_SESSION_VAR]['session_action'] = $action; + + return True; + } + + function destroy($sessionid, $kp3) + { + if (!$sessionid && $kp3) { - if (!$this->sessionid) - { - return False; - } - session_id($this->sessionid); - session_start(); - return $_SESSION[EGW_SESSION_VAR]; + return False; } - /** - * Set paramaters for cookies - only implemented in PHP4 sessions - * - * @param string $domain domain name to use in cookie - * @param string $path='/' path to use in cookie - */ - function set_cookie_params($domain,$path='/') + $this->log_access($this->sessionid); // log logout-time + + // Only do the following, if where working with the current user + if ($sessionid == $GLOBALS['egw_info']['user']['sessionid']) { - session_set_cookie_params(0,$path,$domain); + session_unset(); + //echo "

sessions_php4::destroy: session_destroy() returned ".(session_destroy() ? 'True' : 'False')."

\n"; + @session_destroy(); + if ($GLOBALS['egw_info']['server']['usecookies']) + { + $this->egw_setcookie(session_name()); + } + } + else + { + $sessions = $this->list_sessions(0,'','',True); + + if (isset($sessions[$sessionid])) + { + //echo "

session_php4::destroy($session_id): unlink('".$sessions[$sessionid]['php_session_file']."')

\n"; + @unlink($sessions[$sessionid]['php_session_file']); + } } - /** - * Create a new session id, called by session::create() - * - * Reimplemented to use php session-id - * - * @return string a new session id - */ - function new_session_id() - { - session_start(); + return True; + } - return session_id(); + /*************************************************************************\ + * Functions for appsession data and session cache * + \*************************************************************************/ + function delete_cache($accountid='') + { + $account_id = get_account_id($accountid,$this->account_id); + + $_SESSION[EGW_SESSION_VAR]['app_sessions']['phpgwapi']['phpgw_info_cache'] = ''; + } + + function appsession($location = 'default', $appname = '', $data = '##NOTHING##') + { + if (! $appname) + { + $appname = $GLOBALS['egw_info']['flags']['currentapp']; } - function register_session($login,$user_ip,$now,$session_flags) + /* This allows the user to put '' as the value. */ + if ($data === '##NOTHING##') { - // session_start() is now called in new_session_id() !!! - $_SESSION[EGW_SESSION_VAR]['session_id'] = $this->sessionid; - $_SESSION[EGW_SESSION_VAR]['session_lid'] = $login; - $_SESSION[EGW_SESSION_VAR]['session_ip'] = $user_ip; - $_SESSION[EGW_SESSION_VAR]['session_logintime'] = $now; - $_SESSION[EGW_SESSION_VAR]['session_dla'] = $now; - $_SESSION[EGW_SESSION_VAR]['session_action'] = $_SERVER['PHP_SELF']; - $_SESSION[EGW_SESSION_VAR]['session_flags'] = $session_flags; - // we need the install-id to differ between serveral installs shareing one tmp-dir - $_SESSION[EGW_SESSION_VAR]['session_install_id'] = $GLOBALS['egw_info']['server']['install_id']; + /* do not decrypt and return if no data (decrypt returning garbage) */ + if($_SESSION[EGW_SESSION_VAR]['app_sessions'][$appname][$location]) + { + return $GLOBALS['egw']->crypto->decrypt($_SESSION[EGW_SESSION_VAR]['app_sessions'][$appname][$location]); + } + return false; } + $_SESSION[EGW_SESSION_VAR]['app_sessions'][$appname][$location] = $GLOBALS['egw']->crypto->encrypt($data); - // This will update the DateLastActive column, so the login does not expire - function update_dla() + return $data; + } + + function session_sort($a,$b) + { + $sign = strcasecmp($GLOBALS['egw']->session->sort_order,'ASC') ? 1 : -1; + + return strcasecmp( + $a[$GLOBALS['egw']->session->sort_by], + $b[$GLOBALS['egw']->session->sort_by] + ) * $sign; + } + + /** + * get list of normal / non-anonymous sessions (works only for session.handler = files!, but that's the default) + * + * The data from the session-files get cached in the app_session phpgwapi/php4_session_cache + * + * @author RalfBecker-AT-outdoor-training.de + */ + function list_sessions($start,$order,$sort,$all_no_sort = False) + { + //echo "

session_php4::list_sessions($start,'$order','$sort',$all)

\n"; + $session_cache = $this->appsession('php4_session_cache','phpgwapi'); + + $values = array(); + $maxmatchs = $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs']; + $dir = @opendir($path = ini_get('session.save_path')); + if (!$dir || !@file_exists($path.'/.')) // eg. openbasedir restrictions, or dir not listable { - if (@isset($_GET['menuaction'])) - { - $action = $_GET['menuaction']; - } - else - { - $action = $_SERVER['PHP_SELF']; - } - - // This way XML-RPC users aren't always listed as - // xmlrpc.php - if ($this->xmlrpc_method_called) - { - $action = $this->xmlrpc_method_called; - } - - $_SESSION[EGW_SESSION_VAR]['session_dla'] = time(); - $_SESSION[EGW_SESSION_VAR]['session_action'] = $action; - - return True; - } - - function destroy($sessionid, $kp3) - { - if (!$sessionid && $kp3) - { - return False; - } - - $this->log_access($this->sessionid); // log logout-time - - // Only do the following, if where working with the current user - if ($sessionid == $GLOBALS['egw_info']['user']['sessionid']) - { - session_unset(); - //echo "

sessions_php4::destroy: session_destroy() returned ".(session_destroy() ? 'True' : 'False')."

\n"; - @session_destroy(); - if ($GLOBALS['egw_info']['server']['usecookies']) - { - $this->egw_setcookie(session_name()); - } - } - else - { - $sessions = $this->list_sessions(0,'','',True); - - if (isset($sessions[$sessionid])) - { - //echo "

session_php4::destroy($session_id): unlink('".$sessions[$sessionid]['php_session_file']."')

\n"; - @unlink($sessions[$sessionid]['php_session_file']); - } - } - - return True; - } - - /*************************************************************************\ - * Functions for appsession data and session cache * - \*************************************************************************/ - function delete_cache($accountid='') - { - $account_id = get_account_id($accountid,$this->account_id); - - $_SESSION[EGW_SESSION_VAR]['app_sessions']['phpgwapi']['phpgw_info_cache'] = ''; - } - - function appsession($location = 'default', $appname = '', $data = '##NOTHING##') - { - if (! $appname) - { - $appname = $GLOBALS['egw_info']['flags']['currentapp']; - } - - /* This allows the user to put '' as the value. */ - if ($data === '##NOTHING##') - { - /* do not decrypt and return if no data (decrypt returning garbage) */ - if($_SESSION[EGW_SESSION_VAR]['app_sessions'][$appname][$location]) - { - return $GLOBALS['egw']->crypto->decrypt($_SESSION[EGW_SESSION_VAR]['app_sessions'][$appname][$location]); - } - return false; - } - $_SESSION[EGW_SESSION_VAR]['app_sessions'][$appname][$location] = $GLOBALS['egw']->crypto->encrypt($data); - - return $data; - } - - function session_sort($a,$b) - { - $sign = strcasecmp($GLOBALS['egw']->session->sort_order,'ASC') ? 1 : -1; - - return strcasecmp( - $a[$GLOBALS['egw']->session->sort_by], - $b[$GLOBALS['egw']->session->sort_by] - ) * $sign; - } - - /** - * get list of normal / non-anonymous sessions (works only for session.handler = files!, but that's the default) - * - * The data from the session-files get cached in the app_session phpgwapi/php4_session_cache - * - * @author RalfBecker-AT-outdoor-training.de - */ - function list_sessions($start,$order,$sort,$all_no_sort = False) - { - //echo "

session_php4::list_sessions($start,'$order','$sort',$all)

\n"; - $session_cache = $this->appsession('php4_session_cache','phpgwapi'); - - $values = array(); - $maxmatchs = $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs']; - $dir = @opendir($path = ini_get('session.save_path')); - if (!$dir || !@file_exists($path.'/.')) // eg. openbasedir restrictions, or dir not listable - { - return $values; - } - if (!($max_session_size = ini_get('memory_limit'))) $max_session_size = '16M'; - switch(strtoupper(substr($max_session_size,-1))) - { - case 'M': $max_session_size *= 1024*1024; break; - case 'K': $max_session_size *= 1024; break; - } - $max_session_size /= 4; // use at max 1/4 of the memory_limit to read sessions, the others get ignored - - while (($file = readdir($dir))) - { - if ($file{0} == '.' || filesize($path.'/'.$file) >= $max_session_size) continue; - - if (substr($file,0,5) != 'sess_' || $session_cache[$file] === false) - { - continue; - } - if (isset($session_cache[$file]) && !$session_cache[$file]) // session is marked as not to list (not ours or anonymous) - { - continue; - } - if (isset($session_cache[$file])) // use copy from cache - { - $session = $session_cache[$file]; - - if (!$all_no_sort || // we need the up-to-date data --> unset and reread it - $session['session_dla'] <= (time() - $GLOBALS['egw_info']['server']['sessions_timeout'])) // cached dla is timeout - { - unset($session_cache[$file]); - } - } - if (!isset($session_cache[$file])) // not in cache, read and cache it - { - if (!is_readable($path. '/' . $file)) - { - $session_cache[$file] = false; // dont try reading it again - continue; // happens if webserver runs multiple user-ids - } - $session = ''; - if (($fd = fopen ($path . '/' . $file,'r'))) - { - $session = ($size = filesize ($path . '/' . $file)) ? fread ($fd, $size) : 0; - fclose ($fd); - } - if (substr($session,0,1+strlen(EGW_SESSION_VAR)) != EGW_SESSION_VAR.'|') - { - $session_cache[$file] = false; // dont try reading it again - continue; - } - $session = unserialize(substr($session,1+strlen(EGW_SESSION_VAR))); - unset($session['app_sessions']); // not needed, saves memory - $session['php_session_file'] = $path . '/' . $file; - $session_cache[$file] = $session; - - if($session['session_flags'] == 'A' || !$session['session_id'] || - $session['session_install_id'] != $GLOBALS['egw_info']['server']['install_id']) - { - $session_cache[$file] = false; // dont try reading it again - continue; // no anonymous sessions or other domains or installations - } - // check for and terminate sessions which are timed out ==> destroy them - // this should be not necessary if php is configured right, but I'm sick of the questions on the list - if ($session['session_dla'] <= (time() - $GLOBALS['egw_info']['server']['sessions_timeout'])) - { - //echo "session $session[session_id] is timed out !!!
\n"; - @unlink($path . '/' . $file); - $session_cache[$file] = false; - continue; - } - } - // ignore (empty) login sessions created by IE and konqueror, when clicking on [login] (double submission of the form) - if ($session['session_action'] == $GLOBALS['egw_info']['server']['webserver_url'].'/login.php') continue; - - //echo "file='$file'=
"; print_r($session); echo "
"; - $values[$session['session_id']] = $session; - } - closedir($dir); - - if(!$all_no_sort) - { - $GLOBALS['egw']->session->sort_by = $sort; - $GLOBALS['egw']->session->sort_order = $order; - - uasort($values,array('sessions','session_sort')); - - $i = 0; - $start = (int)$start; - foreach($values as $id => $data) - { - if($i < $start || $i > $start+$maxmatchs) - { - unset($values[$id]); - } - ++$i; - } - reset($values); - } - $this->appsession('php4_session_cache','phpgwapi',$session_cache); - return $values; } - - /** - * get number of normal / non-anonymous sessions - * - * @author RalfBecker-AT-outdoor-training.de - */ - function total() + if (!($max_session_size = ini_get('memory_limit'))) $max_session_size = '16M'; + switch(strtoupper(substr($max_session_size,-1))) { - return count($this->list_sessions(0,'','',True)); + case 'M': $max_session_size *= 1024*1024; break; + case 'K': $max_session_size *= 1024; break; } + $max_session_size /= 4; // use at max 1/4 of the memory_limit to read sessions, the others get ignored + + while (($file = readdir($dir))) + { + if ($file{0} == '.' || filesize($path.'/'.$file) >= $max_session_size) continue; + + if (substr($file,0,5) != 'sess_' || $session_cache[$file] === false) + { + continue; + } + if (isset($session_cache[$file]) && !$session_cache[$file]) // session is marked as not to list (not ours or anonymous) + { + continue; + } + if (isset($session_cache[$file])) // use copy from cache + { + $session = $session_cache[$file]; + + if (!$all_no_sort || // we need the up-to-date data --> unset and reread it + $session['session_dla'] <= (time() - $GLOBALS['egw_info']['server']['sessions_timeout'])) // cached dla is timeout + { + unset($session_cache[$file]); + } + } + if (!isset($session_cache[$file])) // not in cache, read and cache it + { + if (!is_readable($path. '/' . $file)) + { + $session_cache[$file] = false; // dont try reading it again + continue; // happens if webserver runs multiple user-ids + } + $session = ''; + if (($fd = fopen ($path . '/' . $file,'r'))) + { + $session = ($size = filesize ($path . '/' . $file)) ? fread ($fd, $size) : 0; + fclose ($fd); + } + if (substr($session,0,1+strlen(EGW_SESSION_VAR)) != EGW_SESSION_VAR.'|') + { + $session_cache[$file] = false; // dont try reading it again + continue; + } + $session = unserialize(substr($session,1+strlen(EGW_SESSION_VAR))); + unset($session['app_sessions']); // not needed, saves memory + $session['php_session_file'] = $path . '/' . $file; + $session_cache[$file] = $session; + + if($session['session_flags'] == 'A' || !$session['session_id'] || + $session['session_install_id'] != $GLOBALS['egw_info']['server']['install_id']) + { + $session_cache[$file] = false; // dont try reading it again + continue; // no anonymous sessions or other domains or installations + } + // check for and terminate sessions which are timed out ==> destroy them + // this should be not necessary if php is configured right, but I'm sick of the questions on the list + if ($session['session_dla'] <= (time() - $GLOBALS['egw_info']['server']['sessions_timeout'])) + { + //echo "session $session[session_id] is timed out !!!
\n"; + @unlink($path . '/' . $file); + $session_cache[$file] = false; + continue; + } + } + // ignore (empty) login sessions created by IE and konqueror, when clicking on [login] (double submission of the form) + if ($session['session_action'] == $GLOBALS['egw_info']['server']['webserver_url'].'/login.php') continue; + + //echo "file='$file'=
"; print_r($session); echo "
"; + $values[$session['session_id']] = $session; + } + closedir($dir); + + if(!$all_no_sort) + { + $GLOBALS['egw']->session->sort_by = $sort; + $GLOBALS['egw']->session->sort_order = $order; + + uasort($values,array('sessions','session_sort')); + + $i = 0; + $start = (int)$start; + foreach($values as $id => $data) + { + if($i < $start || $i > $start+$maxmatchs) + { + unset($values[$id]); + } + ++$i; + } + reset($values); + } + $this->appsession('php4_session_cache','phpgwapi',$session_cache); + + return $values; } + + /** + * get number of normal / non-anonymous sessions + * + * @author RalfBecker-AT-outdoor-training.de + */ + function total() + { + return count($this->list_sessions(0,'','',True)); + } +}