mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-03-03 17:51:54 +01:00
Refractured session handling in eGW:
- DONT UPDATE ON A PROCUDTION SYSTEM (for the next few days)! - eGW support from now on only php session handling - custom session handlers (like the memcache one) can now be implemented as classes and dont need to change any other code - the class get's autoloaded and the name need to be configured eg. in the header.inc.php as $egw_info[server][session_handler] - session restore is now enabled by default (it's way faster and works well with php5.1+) - a db-bases session handler follows soon
This commit is contained in:
parent
e568a02b2e
commit
907e24d227
@ -74,7 +74,7 @@ class egw extends egw_minimal
|
||||
function setup($domain_names,$createsessionobject=True)
|
||||
{
|
||||
// create the DB-object
|
||||
$this->db = new egw_db();
|
||||
$this->db = new egw_db($GLOBALS['egw_info']['server']);
|
||||
if ($this->debug)
|
||||
{
|
||||
$this->db->Debug = 1;
|
||||
@ -83,14 +83,7 @@ class egw extends egw_minimal
|
||||
|
||||
// check if eGW is already setup, if not redirect to setup/
|
||||
try {
|
||||
$this->db->connect(
|
||||
$GLOBALS['egw_info']['server']['db_name'],
|
||||
$GLOBALS['egw_info']['server']['db_host'],
|
||||
$GLOBALS['egw_info']['server']['db_port'],
|
||||
$GLOBALS['egw_info']['server']['db_user'],
|
||||
$GLOBALS['egw_info']['server']['db_pass'],
|
||||
$GLOBALS['egw_info']['server']['db_type']
|
||||
);
|
||||
$this->db->connect();
|
||||
}
|
||||
catch(Exception $e) {
|
||||
//echo "<pre>Connection to DB failed (".$e->getMessage().")!\n".$e->getTraceAsString();
|
||||
@ -138,7 +131,7 @@ class egw extends egw_minimal
|
||||
*/
|
||||
if($createsessionobject)
|
||||
{
|
||||
$this->session = new sessions($domain_names);
|
||||
$this->session = new egw_session($domain_names);
|
||||
}
|
||||
$this->preferences = new preferences();
|
||||
$this->applications = new applications();
|
||||
@ -520,7 +513,8 @@ class egw_minimal
|
||||
'js' => 'javascript',
|
||||
'link' => 'bolink', // depricated use static egw_link methods
|
||||
'datetime' => 'egw_datetime',
|
||||
'session' => 'sessions',
|
||||
// 'session' => 'sessions',
|
||||
'session' => 'egw_session',
|
||||
'framework' => true, // special handling in __get()
|
||||
'template' => 'Template',
|
||||
);
|
||||
|
@ -299,14 +299,13 @@ class egw_framework
|
||||
}
|
||||
|
||||
// current users for admins
|
||||
$var['current_users'] = $this->_current_users();
|
||||
$var['current_users'] = $this->_current_users();
|
||||
|
||||
// quick add selectbox
|
||||
$var['quick_add'] = $this->_get_quick_add();
|
||||
|
||||
$var['user_info'] = $this->_user_time_info();
|
||||
|
||||
|
||||
if($GLOBALS['egw_info']['user']['lastpasswd_change'] == 0)
|
||||
{
|
||||
$api_messages = lang('You are required to change your password during your first login').'<br />'.
|
||||
@ -362,7 +361,8 @@ class egw_framework
|
||||
{
|
||||
if( $GLOBALS['egw_info']['user']['apps']['admin'] && $GLOBALS['egw_info']['user']['preferences']['common']['show_currentusers'])
|
||||
{
|
||||
$current_users = '<a href="' . $GLOBALS['egw']->link('/index.php','menuaction=admin.uicurrentsessions.list_sessions') . '">' . lang('Current users') . ': ' . $GLOBALS['egw']->session->total() . '</a>';
|
||||
$current_users = '<a href="' . $GLOBALS['egw']->link('/index.php','menuaction=admin.uicurrentsessions.list_sessions') . '">' .
|
||||
lang('Current users') . ': ' . $GLOBALS['egw']->session->session_count() . '</a>';
|
||||
return $current_users;
|
||||
}
|
||||
}
|
||||
|
1191
phpgwapi/inc/class.egw_session.inc.php
Normal file
1191
phpgwapi/inc/class.egw_session.inc.php
Normal file
File diff suppressed because it is too large
Load Diff
150
phpgwapi/inc/class.egw_session_files.inc.php
Normal file
150
phpgwapi/inc/class.egw_session_files.inc.php
Normal file
@ -0,0 +1,150 @@
|
||||
<?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
|
||||
*/
|
||||
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='ASC' ASC or DESC
|
||||
* @return array with sessions (values for keys as in $sort) or array() if not supported by session-handler
|
||||
*/
|
||||
function session_list($start,$sort='ASC',$order='session_dla',$all_no_sort = False)
|
||||
{
|
||||
if (session_module_name() != 'files')
|
||||
{
|
||||
return array();
|
||||
}
|
||||
//echo '<p>'.__METHOD__."($start,'$order','$sort',$all)</p>\n";
|
||||
$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';
|
||||
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 !!!<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)
|
||||
{
|
||||
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
|
||||
*/
|
||||
function session_count()
|
||||
{
|
||||
return count(self::session_list(0,'','',True));
|
||||
}
|
||||
}
|
264
phpgwapi/inc/class.egw_session_memcache.inc.php
Normal file
264
phpgwapi/inc/class.egw_session_memcache.inc.php
Normal file
@ -0,0 +1,264 @@
|
||||
<?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' and
|
||||
* session.save_path to 'tcp://host:port[,tcp://host2:port,...]',
|
||||
* as you have to do it with the original handler.
|
||||
*
|
||||
* @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$
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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_set_save_handler(
|
||||
array(__CLASS__,'open'),
|
||||
array(__CLASS__,'close'),
|
||||
array(__CLASS__,'read'),
|
||||
array(__CLASS__,'write'),
|
||||
array(__CLASS__,'destroy'),
|
||||
array(__CLASS__,'gc'));
|
||||
|
||||
// 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)
|
||||
{
|
||||
self::$memchache = new Memcache;
|
||||
foreach(explode(',',ini_get('session.save_path')) as $path)
|
||||
{
|
||||
$parts = parse_url($path);
|
||||
self::$memchache->addServer($parts['host'],$parts['port']); // todo parse query
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close session
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function close()
|
||||
{
|
||||
return is_object(self::$memchache) ? self::$memchache->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;
|
||||
|
||||
/**
|
||||
* Enter description here...
|
||||
*
|
||||
* @param string $id
|
||||
* @return string|boolean
|
||||
*/
|
||||
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=false,$n=0; ($read = self::$memchache->get($id.($n?'-'.$n:''))); ++$n)
|
||||
{
|
||||
if (self::DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." read $id:$n:".print_r(_bytes($read),true));
|
||||
$data .= $read;
|
||||
}
|
||||
self::_release($id);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write session
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $sess_data
|
||||
* @return boolean
|
||||
*/
|
||||
public static function write($id, $sess_data)
|
||||
{
|
||||
$lifetime = (int)ini_get('session.gc_maxlifetime');
|
||||
|
||||
// give anon sessions only a lifetime of 10min
|
||||
if (is_object($GLOBALS['egw']->session) && $GLOBALS['egw']->session->session_flags == 'A')
|
||||
{
|
||||
$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=_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(_bytes($sess_data),true));
|
||||
|
||||
if (!self::$memchache->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::$memchache->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::$memchache->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::$memchache->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));
|
||||
|
||||
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;
|
||||
|
||||
error_log("\n memcache destroy $id:$n:");
|
||||
for($n=0; self::$memchache->delete($id.($n?'-'.$n:'')); ++$n) ;
|
||||
|
||||
self::_release($id);
|
||||
|
||||
return $n > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run garbade collection
|
||||
*
|
||||
* @param int $maxlifetime
|
||||
*/
|
||||
public static function gc($maxlifetime)
|
||||
{
|
||||
// done by memcached itself
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,336 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* 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 <seek3r@phpgroupware.org>
|
||||
* @author Joseph Engo <jengo@phpgroupware.org>
|
||||
* @author Ralf Becker <ralfbecker@outdoor-training.de>
|
||||
* @copyright © 1998-2000 NetUSE AG Boris Erdmann, Kristian Koehntopp <br> © 2003 FreeSoftware Foundation
|
||||
* @license LGPL
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
/**
|
||||
* commit the sessiondata to the filesystem
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function commit_session()
|
||||
{
|
||||
session_write_close();
|
||||
return true;
|
||||
}
|
||||
|
||||
function read_session()
|
||||
{
|
||||
if (!$this->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'];
|
||||
}
|
||||
|
||||
// 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 (!parent::destroy($sessionid,$kp3))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Only do the following, if where working with the current user
|
||||
if ($sessionid == $GLOBALS['egw_info']['user']['sessionid'])
|
||||
{
|
||||
session_unset();
|
||||
//echo "<p>sessions_php4::destroy: session_destroy() returned ".(session_destroy() ? 'True' : 'False')."</p>\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 "<p>session_php4::destroy($session_id): unlink('".$sessions[$sessionid]['php_session_file']."')</p>\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 "<p>session_php4::list_sessions($start,'$order','$sort',$all)</p>\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 !!!<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)
|
||||
{
|
||||
$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));
|
||||
}
|
||||
}
|
@ -52,16 +52,13 @@ if (!isset($GLOBALS['egw_info']['flags']['currentapp']))
|
||||
|
||||
include_once(EGW_API_INC.'/common_functions.inc.php');
|
||||
|
||||
if (extension_loaded('memcache') && ini_get('session.save_handler') == 'memcache')
|
||||
{
|
||||
include_once(EGW_API_INC.'/memcache.inc.php');
|
||||
}
|
||||
// init eGW's sessions-handler
|
||||
egw_session::init_handler();
|
||||
|
||||
// check if we can restore the eGW enviroment from the php-session
|
||||
if ($GLOBALS['egw_info']['server']['sessions_type'] == 'php4-restore' && $_REQUEST['sessionid'])
|
||||
if ($_REQUEST[egw_session::EGW_SESSION_NAME])
|
||||
{
|
||||
session_name('sessionid');
|
||||
ini_set('session.use_cookies',0); // disable the automatic use of cookies, as it uses the path / by default
|
||||
session_id($_REQUEST['sessionid']);
|
||||
session_id($_REQUEST[egw_session::EGW_SESSION_NAME]);
|
||||
session_start();
|
||||
|
||||
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && $GLOBALS['egw_info']['flags']['currentapp'] != 'logout')
|
||||
@ -114,79 +111,27 @@ print_debug('sane environment','messageonly','api');
|
||||
/****************************************************************************\
|
||||
* Multi-Domain support *
|
||||
\****************************************************************************/
|
||||
$GLOBALS['egw_info']['user']['domain'] = egw_session::search_instance($_POST['login'],$_REQUEST['domain'],
|
||||
$GLOBALS['egw_info']['server']['default_domain'],$_SERVER['SERVER_NAME'],$GLOBALS['egw_domain']);
|
||||
|
||||
if (!isset($GLOBALS['egw_info']['server']['default_domain']) || // allow to overwrite the default domain
|
||||
!isset($GLOBALS['egw_domain'][$GLOBALS['egw_info']['server']['default_domain']]))
|
||||
{
|
||||
if(isset($GLOBALS['egw_domain'][$_SERVER['SERVER_NAME']]))
|
||||
{
|
||||
$GLOBALS['egw_info']['server']['default_domain'] = $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$domain_part = explode('.',$_SERVER['SERVER_NAME']);
|
||||
array_shift($domain_part);
|
||||
$domain_part = implode('.',$domain_part);
|
||||
if(isset($GLOBALS['egw_domain'][$domain_part]))
|
||||
{
|
||||
$GLOBALS['egw_info']['server']['default_domain'] = $domain_part;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset($GLOBALS['egw_domain']);
|
||||
list($GLOBALS['egw_info']['server']['default_domain']) = each($GLOBALS['egw_domain']);
|
||||
}
|
||||
unset($domain_part);
|
||||
}
|
||||
}
|
||||
if (isset($_POST['login'])) // on login
|
||||
{
|
||||
$GLOBALS['login'] = $_POST['login'];
|
||||
if (strpos($GLOBALS['login'],'@') === False || count($GLOBALS['egw_domain']) == 1)
|
||||
{
|
||||
$GLOBALS['login'] .= '@' . get_var('logindomain',array('POST'),$GLOBALS['egw_info']['server']['default_domain']);
|
||||
}
|
||||
$parts = explode('@',$GLOBALS['login']);
|
||||
$GLOBALS['egw_info']['user']['domain'] = array_pop($parts);
|
||||
}
|
||||
else // on "normal" pageview
|
||||
{
|
||||
$GLOBALS['egw_info']['user']['domain'] = get_var('domain',array('GET','COOKIE'),false);
|
||||
}
|
||||
if (@isset($GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]))
|
||||
{
|
||||
$GLOBALS['egw_info']['server']['db_host'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_host'];
|
||||
$GLOBALS['egw_info']['server']['db_port'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_port'];
|
||||
$GLOBALS['egw_info']['server']['db_name'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_name'];
|
||||
$GLOBALS['egw_info']['server']['db_user'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_user'];
|
||||
$GLOBALS['egw_info']['server']['db_pass'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_pass'];
|
||||
$GLOBALS['egw_info']['server']['db_type'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_type'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$GLOBALS['egw_info']['server']['db_host'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['server']['default_domain']]['db_host'];
|
||||
$GLOBALS['egw_info']['server']['db_port'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['server']['default_domain']]['db_port'];
|
||||
$GLOBALS['egw_info']['server']['db_name'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['server']['default_domain']]['db_name'];
|
||||
$GLOBALS['egw_info']['server']['db_user'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['server']['default_domain']]['db_user'];
|
||||
$GLOBALS['egw_info']['server']['db_pass'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['server']['default_domain']]['db_pass'];
|
||||
$GLOBALS['egw_info']['server']['db_type'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['server']['default_domain']]['db_type'];
|
||||
}
|
||||
$GLOBALS['egw_info']['server']['db_host'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_host'];
|
||||
$GLOBALS['egw_info']['server']['db_port'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_port'];
|
||||
$GLOBALS['egw_info']['server']['db_name'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_name'];
|
||||
$GLOBALS['egw_info']['server']['db_user'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_user'];
|
||||
$GLOBALS['egw_info']['server']['db_pass'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_pass'];
|
||||
$GLOBALS['egw_info']['server']['db_type'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_type'];
|
||||
print_debug('domain',@$GLOBALS['egw_info']['user']['domain'],'api');
|
||||
|
||||
// the egw-object instanciates all sub-classes (eg. $GLOBALS['egw']->db) and the egw_info array
|
||||
$GLOBALS['egw'] = new egw(array_keys($GLOBALS['egw_domain']));
|
||||
|
||||
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login')
|
||||
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && !$GLOBALS['egw_info']['server']['show_domain_selectbox'])
|
||||
{
|
||||
if (!$GLOBALS['egw_info']['server']['show_domain_selectbox'])
|
||||
{
|
||||
unset ($GLOBALS['egw_domain']); // we kill this for security reasons
|
||||
}
|
||||
//printf("<p style=\"position: absolute; right: 0px; top: 0px;\">egw-enviroment new created in %d ms</p>\n",1000*(perfgetmicrotime()-$GLOBALS['egw_info']['flags']['page_start_time']));
|
||||
unset ($GLOBALS['egw_domain']); // we kill this for security reasons
|
||||
}
|
||||
|
||||
// saving the the egw_info array and the egw-object in the session
|
||||
if ($GLOBALS['egw_info']['server']['sessions_type'] == 'php4-restore' && $GLOBALS['egw_info']['flags']['currentapp'] != 'login')
|
||||
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login')
|
||||
{
|
||||
$_SESSION['egw_info_cache'] = $GLOBALS['egw_info'];
|
||||
unset($_SESSION['egw_info_cache']['flags']); // dont save the flags, they change on each request
|
||||
|
@ -1,173 +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' and
|
||||
* session.save_path to 'tcp://host:port[,tcp://host2:port,...]',
|
||||
* as you have to do it with the original handler.
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package api
|
||||
* @subpackage session
|
||||
* @copyright (c) 2007 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
define('DEBUG',0);
|
||||
define('DEBUGALL',0);
|
||||
|
||||
function egw_memcache_open($save_path, $session_name)
|
||||
{
|
||||
global $egw_memcache_obj;
|
||||
$egw_memcache_obj = new Memcache;
|
||||
foreach(explode(',',ini_get('session.save_path')) as $path)
|
||||
{
|
||||
$parts = parse_url($path);
|
||||
$egw_memcache_obj->addServer($parts['host'],$parts['port']); // todo parse query
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
function egw_memcache_close()
|
||||
{
|
||||
global $egw_memcache_obj;
|
||||
|
||||
return is_object($egw_memcache_obj) ? $egw_memcache_obj->close() : false;
|
||||
}
|
||||
|
||||
define('MEMCACHED_MAX_JUNK',1024*1000); // 1024*1024 is too big, maybe some account-info needs to be added
|
||||
|
||||
function egw_memcache_read($id)
|
||||
{
|
||||
global $egw_memcache_obj;
|
||||
|
||||
if (DEBUG > 0 && DEBUGALL>0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." READ start $id:");
|
||||
|
||||
if (!_acquire_and_wait($id)) return false;
|
||||
|
||||
for($data=false,$n=0; ($read = $egw_memcache_obj->get($id.($n?'-'.$n:''))); ++$n)
|
||||
{
|
||||
if (DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." read $id:$n:".print_r(_bytes($read),true));
|
||||
$data .= $read;
|
||||
}
|
||||
_release($id);
|
||||
return $data;
|
||||
}
|
||||
|
||||
function egw_memcache_write($id, $sess_data)
|
||||
{
|
||||
global $egw_memcache_obj;
|
||||
|
||||
$lifetime = (int)ini_get('session.gc_maxlifetime');
|
||||
// give anon sessions only a lifetime of 10min
|
||||
if (is_object($GLOBALS['egw']->session) && $GLOBALS['egw']->session->session_flags == 'A')
|
||||
{
|
||||
$lifetime = 600;
|
||||
}
|
||||
if (DEBUG > 0 && DEBUGALL>0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." WRITE start $id:");
|
||||
|
||||
if (!_acquire_and_wait($id)) return false;
|
||||
|
||||
for($n=$i=0,$len=_bytes($sess_data); $i < $len; $i += MEMCACHED_MAX_JUNK,++$n)
|
||||
{
|
||||
if (DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." in :$n write $id:$i:".print_r(_bytes($sess_data),true));
|
||||
|
||||
if (!$egw_memcache_obj->set($id.($n?'-'.$n:''),_cut_bytes($sess_data,$i,MEMCACHED_MAX_JUNK),0,$lifetime)) {
|
||||
_release($id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." DELETE :$n");
|
||||
for($n=$n; $egw_memcache_obj->delete($id.($n?'-'.$n:'')); ++$n) ;
|
||||
|
||||
_release($id);
|
||||
return true;
|
||||
}
|
||||
|
||||
function _acquire_and_wait($id)
|
||||
{
|
||||
global $egw_memcache_obj;
|
||||
|
||||
if (DEBUG > 0 && DEBUGALL>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(!$egw_memcache_obj->add($id.'-lock',1,0,3)) {
|
||||
if (DEBUG > 0 && DEBUGALL>0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." ACQUIRE Lock Loop :$id:$i");
|
||||
usleep(100000);
|
||||
$i++;
|
||||
if ($i > 40) {
|
||||
if (DEBUG > 0) 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 (DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." ACQUIRE LOOP $i :$id");
|
||||
}
|
||||
if (DEBUG > 0) error_log("\n memcache ".print_r(getenv('HOSTNAME'),true).$_SERVER["REQUEST_TIME"]." Lock ACQUIRED $i:$id");
|
||||
return true;
|
||||
}
|
||||
|
||||
function _release($id)
|
||||
{
|
||||
global $egw_memcache_obj;
|
||||
|
||||
if (DEBUG > 0) error_log("\n memcache ".$_SERVER["REQUEST_TIME"]." RELEASE :$id");
|
||||
return $egw_memcache_obj->delete($id.'-lock');
|
||||
}
|
||||
|
||||
function _test_mbstring_func_overload()
|
||||
{
|
||||
return @extension_loaded('mbstring') && (ini_get('mbstring.func_overload') & 2);
|
||||
}
|
||||
|
||||
function _bytes(&$data)
|
||||
{
|
||||
global $mbstring_func_overload;
|
||||
|
||||
if (is_null($mbstring_func_overload)) $mbstring_func_overload=_test_mbstring_func_overload();
|
||||
|
||||
return $mbstring_func_overload ? mb_strlen($data,'ascii') : strlen($data);
|
||||
}
|
||||
|
||||
function _cut_bytes(&$data,$offset,$len=null)
|
||||
{
|
||||
global $mbstring_func_overload;
|
||||
|
||||
if (is_null($mbstring_func_overload)) $mbstring_func_overload=_test_mbstring_func_overload();
|
||||
if (DEBUG > 0 && DEBUGALL>0) error_log("\n memcache in cutbyte mb $id:$n:".print_r(mb_substr($data,$offset,$len,'ascii'),true));
|
||||
if (DEBUG > 0 && DEBUGALL>0) error_log("\n memcache in cutbyte norm $id:$n:".print_r(substr($data,$offset,$len),true));
|
||||
|
||||
return $mbstring_func_overload ? mb_substr($data,$offset,$len,'ascii') : substr($data,$offset,$len);
|
||||
}
|
||||
|
||||
function egw_memcache_destroy($id)
|
||||
{
|
||||
global $egw_memcache_obj;
|
||||
|
||||
if (!_acquire_and_wait($id)) return false;
|
||||
|
||||
error_log("\n memcache destroy $id:$n:");
|
||||
for($n=0; $egw_memcache_obj->delete($id.($n?'-'.$n:'')); ++$n) ;
|
||||
|
||||
_release($id);
|
||||
return $n > 0;
|
||||
}
|
||||
|
||||
function egw_memcache_gc($maxlifetime)
|
||||
{
|
||||
}
|
||||
|
||||
session_set_save_handler("egw_memcache_open", "egw_memcache_close", "egw_memcache_read", "egw_memcache_write", "egw_memcache_destroy", "egw_memcache_gc");
|
Loading…
Reference in New Issue
Block a user