mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 06:30:59 +01:00
moved egw_session class to Api\Session and removed unused egw_session_(files|memcache) as listing sessions is done now via egw_sessions table in db and memcache has its own session handler
This commit is contained in:
parent
7989d702dd
commit
aeb9c93b55
@ -13,15 +13,13 @@
|
||||
|
||||
namespace EGroupware\Api;
|
||||
|
||||
use egw_session;
|
||||
|
||||
/**
|
||||
* Class to manage caching in eGroupware.
|
||||
*
|
||||
* It allows to cache on 4 levels:
|
||||
* a) tree: for all instances/domains runining on a certain source path
|
||||
* b) instance: for all sessions on a given instance
|
||||
* c) session: for all requests of a session, same as egw_session::appsession()
|
||||
* c) session: for all requests of a session, same as deprecated egw_session::appsession()
|
||||
* d) request: just for this request (same as using a static variable)
|
||||
*
|
||||
* There's a get, a set and a unset method for each level: eg. getTree() or setInstance(),
|
||||
@ -371,12 +369,12 @@ class Cache
|
||||
static public function setSession($app,$location,$data,$expiration=0)
|
||||
{
|
||||
unset($expiration); // not used, but required by function signature
|
||||
if (isset($_SESSION[egw_session::EGW_SESSION_ENCRYPTED]))
|
||||
if (isset($_SESSION[Session::EGW_SESSION_ENCRYPTED]))
|
||||
{
|
||||
if (egw_session::ERROR_LOG_DEBUG) error_log(__METHOD__.' called after session was encrypted --> ignored!');
|
||||
if (Session::ERROR_LOG_DEBUG) error_log(__METHOD__.' called after session was encrypted --> ignored!');
|
||||
return false; // can no longer store something in the session, eg. because commit_session() was called
|
||||
}
|
||||
$_SESSION[egw_session::EGW_APPSESSION_VAR][$app][$location] = $data;
|
||||
$_SESSION[Session::EGW_APPSESSION_VAR][$app][$location] = $data;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -396,16 +394,16 @@ class Cache
|
||||
static public function &getSession($app,$location,$callback=null,array $callback_params=array(),$expiration=0)
|
||||
{
|
||||
unset($expiration); // not used, but required by function signature
|
||||
if (isset($_SESSION[egw_session::EGW_SESSION_ENCRYPTED]))
|
||||
if (isset($_SESSION[Session::EGW_SESSION_ENCRYPTED]))
|
||||
{
|
||||
if (egw_session::ERROR_LOG_DEBUG) error_log(__METHOD__.' called after session was encrypted --> ignored!');
|
||||
if (Session::ERROR_LOG_DEBUG) error_log(__METHOD__.' called after session was encrypted --> ignored!');
|
||||
return null; // can no longer store something in the session, eg. because commit_session() was called
|
||||
}
|
||||
if (!isset($_SESSION[egw_session::EGW_APPSESSION_VAR][$app][$location]) && !is_null($callback))
|
||||
if (!isset($_SESSION[Session::EGW_APPSESSION_VAR][$app][$location]) && !is_null($callback))
|
||||
{
|
||||
$_SESSION[egw_session::EGW_APPSESSION_VAR][$app][$location] = call_user_func_array($callback,$callback_params);
|
||||
$_SESSION[Session::EGW_APPSESSION_VAR][$app][$location] = call_user_func_array($callback,$callback_params);
|
||||
}
|
||||
return $_SESSION[egw_session::EGW_APPSESSION_VAR][$app][$location];
|
||||
return $_SESSION[Session::EGW_APPSESSION_VAR][$app][$location];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -417,16 +415,16 @@ class Cache
|
||||
*/
|
||||
static public function unsetSession($app,$location)
|
||||
{
|
||||
if (isset($_SESSION[egw_session::EGW_SESSION_ENCRYPTED]))
|
||||
if (isset($_SESSION[Session::EGW_SESSION_ENCRYPTED]))
|
||||
{
|
||||
if (egw_session::ERROR_LOG_DEBUG) error_log(__METHOD__.' called after session was encrypted --> ignored!');
|
||||
if (Session::ERROR_LOG_DEBUG) error_log(__METHOD__.' called after session was encrypted --> ignored!');
|
||||
return false; // can no longer store something in the session, eg. because commit_session() was called
|
||||
}
|
||||
if (!isset($_SESSION[egw_session::EGW_APPSESSION_VAR][$app][$location]))
|
||||
if (!isset($_SESSION[Session::EGW_APPSESSION_VAR][$app][$location]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
unset($_SESSION[egw_session::EGW_APPSESSION_VAR][$app][$location]);
|
||||
unset($_SESSION[Session::EGW_APPSESSION_VAR][$app][$location]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
1727
api/src/Session.php
Normal file
1727
api/src/Session.php
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,154 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare API: File based php sessions
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage session
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2003-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* File based php sessions or all other build in handlers configures via session_module_name() or php.ini: session.save_handler
|
||||
*
|
||||
* Contains static methods to list or count 'files' sessions (does not work under Debian, were session.save_path is not searchable!)
|
||||
*/
|
||||
class egw_session_files
|
||||
{
|
||||
/**
|
||||
* Initialise the session-handler (session_set_save_handler()), if necessary
|
||||
*/
|
||||
public static function init_session_handler()
|
||||
{
|
||||
// nothing to do for 'files' or other stock handlers
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $_SESSION['egw_files_session_cache']
|
||||
*
|
||||
* @param int $start
|
||||
* @param string $sort='session_dla' session_lid, session_id, session_started, session_logintime, session_action, or (default) session_dla
|
||||
* @param string $order='DESC' ASC or DESC
|
||||
* @param boolean $all_no_sort=False skip sorting and limiting to maxmatchs if set to true
|
||||
* @return array with sessions (values for keys as in $sort) or array() if not supported by session-handler
|
||||
*/
|
||||
public static function session_list($start,$sort='DESC',$order='session_dla',$all_no_sort=False)
|
||||
{
|
||||
if (session_module_name() != 'files')
|
||||
{
|
||||
return array();
|
||||
}
|
||||
//echo '<p>'.__METHOD__."($start,sort='$sort',order='$order',$all)</p>\n".function_backtrace();
|
||||
$session_cache =& $_SESSION['egw_files_session_cache'];
|
||||
|
||||
$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';
|
||||
if($max_session_size > 0)
|
||||
{
|
||||
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} == '.') continue;
|
||||
if ($max_session_size > 0 && filesize($path.'/'.$file) >= $max_session_size) continue;
|
||||
|
||||
if (substr($file,0,5) != 'sess_' || $session_cache[$file] === false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//echo "<p>$path/$file: ".substr(file_get_contents($path . '/' . $file,'r'),0,256)."</p>\n";
|
||||
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
|
||||
}
|
||||
unset($session);
|
||||
list(,$session) = explode(egw_session::EGW_SESSION_VAR.'|',file_get_contents($path . '/' . $file,'r'));
|
||||
if (!$session || !($session = unserialize($session)))
|
||||
{
|
||||
$session_cache[$file] = false; // dont try reading it again
|
||||
continue;
|
||||
}
|
||||
unset($session[egw_session::EGW_APPSESSION_VAR]); // 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 !!!<br>\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'=<pre>"; print_r($session); echo "</pre>";
|
||||
$values[$session['session_id']] = $session;
|
||||
}
|
||||
closedir($dir);
|
||||
|
||||
if(!$all_no_sort)
|
||||
{
|
||||
if(!$order || !in_array($order,array('session_lid','session_ip','session_logintime','session_action','session_dla')))
|
||||
{
|
||||
$order = 'session_dla';
|
||||
}
|
||||
uasort($values,create_function('$a,$b','return '.(!strcasecmp($sort,'ASC') ? '' : '-').'strcasecmp($a['.$order.'],$b['.$order.']);'));
|
||||
return array_slice($values,(int)$start,$maxmatchs);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* get number of normal / non-anonymous sessions
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function session_count()
|
||||
{
|
||||
return count(self::session_list(0,'','',True));
|
||||
}
|
||||
}
|
@ -1,292 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare API - memcache session handler
|
||||
*
|
||||
* Fixes a problem of the buildin session handler of the memcache pecl extension,
|
||||
* which can NOT work with sessions > 1MB. This handler splits the session-data
|
||||
* in 1MB chunk, so memcache can handle them. For the first chunk we use an identical
|
||||
* key (just the session-id) as the original memcache session handler. For the further
|
||||
* chunks we add -2, -3, ... so other code (eg. the SyncML code from Horde) can
|
||||
* open the session, if it's size is < 1MB.
|
||||
*
|
||||
* To enable it, you need to set session.save_handler to 'memcache',
|
||||
* session.save_path to 'tcp://host:port[,tcp://host2:port,...]',
|
||||
* as you have to do it with the original handler PLUS adding the following
|
||||
* to your header.inc.php:
|
||||
*
|
||||
* $GLOBALS['egw_info']['server']['session_handler'] = 'egw_session_memcache';
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package api
|
||||
* @subpackage session
|
||||
* @copyright (c) 2007-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
// needed for check_load_extension (session-handler gets included before regular include via the header.inc.php)
|
||||
require_once(EGW_API_INC.'/common_functions.inc.php');
|
||||
|
||||
/**
|
||||
* File based php sessions or all other build in handlers configures via session_module_name() or php.ini: session.save_handler
|
||||
*
|
||||
* Contains static methods to list or count 'files' sessions (does not work under Debian, were session.save_path is not searchable!)
|
||||
*/
|
||||
class egw_session_memcache
|
||||
{
|
||||
/**
|
||||
* Debug level: 0 = none, 1 = some, 2 = all
|
||||
*/
|
||||
const DEBUG = 0;
|
||||
/**
|
||||
* Instance of Memcache
|
||||
*
|
||||
* @var Memcache
|
||||
*/
|
||||
private static $memcache;
|
||||
|
||||
/**
|
||||
* are the string functions overloaded by their mbstring variants
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private static $mbstring_func_overload;
|
||||
|
||||
/**
|
||||
* Initialise the session-handler (session_set_save_handler()), if necessary
|
||||
*/
|
||||
public static function init_session_handler()
|
||||
{
|
||||
self::$mbstring_func_overload = @extension_loaded('mbstring') && (ini_get('mbstring.func_overload') & 2);
|
||||
|
||||
// session needs to be closed before objects get destroyed, as this session-handler is an object ;-)
|
||||
register_shutdown_function('session_write_close');
|
||||
}
|
||||
|
||||
/**
|
||||
* Open session
|
||||
*
|
||||
* @param string $save_path
|
||||
* @param string $session_name
|
||||
* @return boolean
|
||||
*/
|
||||
public static function open($save_path, $session_name)
|
||||
{
|
||||
check_load_extension('memcache',true); // true = throw exception if not loadable
|
||||
|
||||
self::$memcache = new Memcache;
|
||||
foreach(explode(',',$save_path) as $path)
|
||||
{
|
||||
$parts = parse_url($path);
|
||||
self::$memcache->addServer($parts['host'],$parts['port']); // todo parse query
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close session
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function close()
|
||||
{
|
||||
return is_object(self::$memcache) ? self::$memcache->close() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Size of a single memcache junk
|
||||
*
|
||||
* 1024*1024 is too big, maybe some account-info needs to be added
|
||||
*/
|
||||
const MEMCACHED_MAX_JUNK = 1024000;
|
||||
|
||||
/**
|
||||
* Read session data
|
||||
*
|
||||
* According to a commentary on php.net (session_set_save_handler) this function has to return
|
||||
* a string, if the session-id is NOT found, not false. Returning false terminates the script
|
||||
* with a fatal error!
|
||||
*
|
||||
* @param string $id
|
||||
* @return string|boolean false on error, '' for not found session otherwise session data
|
||||
*/
|
||||
public static function read($id)
|
||||
{
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." READ start $id:");
|
||||
|
||||
if (!self::_acquire_and_wait($id)) return false;
|
||||
|
||||
for($data='',$n=0; ($read = self::$memcache->get($id.($n?'-'.$n:''))); ++$n)
|
||||
{
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." read $id:$n:".print_r(self::_bytes($read),true));
|
||||
$data .= $read;
|
||||
}
|
||||
self::_release($id);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write session data
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $sess_data
|
||||
* @return boolean
|
||||
*/
|
||||
public static function write($id, $sess_data)
|
||||
{
|
||||
$lifetime = (int)ini_get('session.gc_maxlifetime');
|
||||
|
||||
if ($id == 'no-session')
|
||||
{
|
||||
return true; // no need to save
|
||||
}
|
||||
// give anon sessions only a lifetime of 10min
|
||||
if (is_object($GLOBALS['egw']->session) && $GLOBALS['egw']->session->session_flags == 'A' ||
|
||||
$GLOBALS['egw_info']['flags']['currentapp'] == 'groupdav')
|
||||
{
|
||||
$lifetime = 600;
|
||||
}
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." WRITE start $id:");
|
||||
|
||||
if (!self::_acquire_and_wait($id)) return false;
|
||||
|
||||
for($n=$i=0,$len=self::_bytes($sess_data); $i < $len; $i += self::MEMCACHED_MAX_JUNK,++$n)
|
||||
{
|
||||
if (self::DEBUG > 1) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." in :$n write $id:$i:".print_r(self::_bytes($sess_data),true));
|
||||
|
||||
if (!self::$memcache->set($id.($n?'-'.$n:''),self::_cut_bytes($sess_data,$i,self::MEMCACHED_MAX_JUNK),0,$lifetime)) {
|
||||
self::_release($id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." DELETE :$n");
|
||||
for($n=$n; self::$memcache->delete($id.($n?'-'.$n:'')); ++$n) ;
|
||||
|
||||
self::_release($id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* semaphore to gard against conflicting writes, destroying the session-data
|
||||
*
|
||||
* @param string $id
|
||||
* @return boolean
|
||||
*/
|
||||
private static function _acquire_and_wait($id)
|
||||
{
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." ACQUIRE :$id");
|
||||
|
||||
$i=0;
|
||||
// Acquire lock for 3 seconds, after that i should have done my job
|
||||
while(!self::$memcache->add($id.'-lock',1,0,3))
|
||||
{
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." ACQUIRE Lock Loop :$id:$i");
|
||||
usleep(100000);
|
||||
$i++;
|
||||
if ($i > 40)
|
||||
{
|
||||
if (self::DEBUG > 1) error_log("\n memcache ".print_r(getenv('HOSTNAME'),true).$_SERVER["REQUEST_TIME"]." blocked :$id");
|
||||
// Could not acquire lock after 3 seconds, Continue, and pretend the locking process get stuck
|
||||
// return false;A
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($i > 1)
|
||||
{
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." ACQUIRE LOOP $i :$id");
|
||||
}
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".print_r(getenv('HOSTNAME'),true).$_SERVER["REQUEST_TIME"]." Lock ACQUIRED $i:$id");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release semaphore
|
||||
*
|
||||
* @param string $id
|
||||
* @return boolean
|
||||
*/
|
||||
private static function _release($id)
|
||||
{
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." RELEASE :$id");
|
||||
|
||||
return self::$memcache->delete($id.'-lock');
|
||||
}
|
||||
|
||||
/**
|
||||
* mbstring.func_overload safe strlen
|
||||
*
|
||||
* @param string $data
|
||||
* @return int
|
||||
*/
|
||||
private static function _bytes(&$data)
|
||||
{
|
||||
return self::$mbstring_func_overload ? mb_strlen($data,'ascii') : strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mbstring.func_overload safe substr
|
||||
*
|
||||
* @param string $data
|
||||
* @param int $offset
|
||||
* @param int $len
|
||||
* @return string
|
||||
*/
|
||||
private static function _cut_bytes(&$data,$offset,$len=null)
|
||||
{
|
||||
if (self::DEBUG > 1) error_log("\n memcache in cutbyte mb $id:$n:".print_r(mb_substr($data,$offset,$len,'ascii'),true));
|
||||
if (self::DEBUG > 1) error_log("\n memcache in cutbyte norm $id:$n:".print_r(substr($data,$offset,$len),true));
|
||||
|
||||
if (is_null($len))
|
||||
{
|
||||
return self::$mbstring_func_overload ? mb_substr($data,$offset,self::_bytes($data),'ascii') : substr($data,$offset);
|
||||
}
|
||||
return self::$mbstring_func_overload ? mb_substr($data,$offset,$len,'ascii') : substr($data,$offset,$len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a session
|
||||
*
|
||||
* @param string $id
|
||||
* @return boolean
|
||||
*/
|
||||
public static function destroy($id)
|
||||
{
|
||||
if (!self::_acquire_and_wait($id)) return false;
|
||||
|
||||
for($n=0; self::$memcache->delete($id.($n?'-'.$n:'')); ++$n)
|
||||
{
|
||||
if (self::DEBUG > 0) error_log("******* memcache destroy $id:$n:");
|
||||
}
|
||||
self::_release($id);
|
||||
|
||||
return $n > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run garbade collection
|
||||
*
|
||||
* @param int $maxlifetime
|
||||
*/
|
||||
public static function gc($maxlifetime)
|
||||
{
|
||||
// done by memcached itself
|
||||
}
|
||||
}
|
||||
|
||||
function init_session_handler()
|
||||
{
|
||||
$ses = 'egw_session_memcache';
|
||||
$ret = session_set_save_handler(
|
||||
array($ses,'open'),
|
||||
array($ses,'close'),
|
||||
array($ses,'read'),
|
||||
array($ses,'write'),
|
||||
array($ses,'destroy'),
|
||||
array($ses,'gc'));
|
||||
if (!$ret) error_log(__METHOD__.'() session_set_save_handler(...)='.(int)$ret.', session_module_name()='.session_module_name().' *******************************');
|
||||
}
|
||||
init_session_handler();
|
Loading…
Reference in New Issue
Block a user