297 lines
8.2 KiB
PHP
297 lines
8.2 KiB
PHP
<?php
|
|
/**
|
|
* This class provides the interface to the session storage backend.
|
|
*
|
|
* Copyright 2002-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information (LGPL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
|
|
*
|
|
* @author Michael Slusarz <slusarz@horde.org>
|
|
* @category Horde
|
|
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
|
|
* @package SessionHandler
|
|
*/
|
|
class Horde_SessionHandler
|
|
{
|
|
/**
|
|
* If true, indicates the session data has changed.
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $changed = false;
|
|
|
|
/**
|
|
* Has a connection been made to the backend?
|
|
*
|
|
* @var boolean
|
|
*/
|
|
protected $_connected = false;
|
|
|
|
/**
|
|
* A logger instance.
|
|
*
|
|
* @var Horde_Log_Logger
|
|
*/
|
|
protected $_logger;
|
|
|
|
/**
|
|
* Configuration parameters.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_params = array();
|
|
|
|
/**
|
|
* Initial session data signature.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_sig;
|
|
|
|
/**
|
|
* The storage object.
|
|
*
|
|
* @var Horde_SessionHandler_Storage
|
|
*/
|
|
protected $_storage;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param Horde_SessionHandler_Storage $storage The storage object.
|
|
* @param array $params Configuration parameters:
|
|
* <pre>
|
|
* - logger: (Horde_Log_Logger) A logger instance.
|
|
* DEFAULT: No logging
|
|
* - no_md5: (boolean) If true, does not do MD5 signatures of the
|
|
* session to determine if the session has changed (calling
|
|
* code is responsible for marking $changed as true when the
|
|
* session data has changed).
|
|
* DEFAULT: false
|
|
* - noset: (boolean) If true, don't set the save handler.
|
|
* DEFAULT: false
|
|
* - parse: (callback) A callback function that parses session
|
|
* information into an array. Is passed the raw session data
|
|
* as the only argument; expects either false or an array of
|
|
* session data as a return.
|
|
* DEFAULT: No
|
|
* </pre>
|
|
*/
|
|
public function __construct(Horde_SessionHandler_Storage $storage,
|
|
array $params = array())
|
|
{
|
|
$params = array_merge($this->_params, $params);
|
|
|
|
$this->_logger = isset($params['logger'])
|
|
? $params['logger']
|
|
: new Horde_Support_Stub();
|
|
unset($params['logger']);
|
|
|
|
$this->_params = $params;
|
|
$this->_storage = $storage;
|
|
|
|
if (empty($this->_params['noset'])) {
|
|
session_set_save_handler(
|
|
array($this, 'open'),
|
|
array($this, 'close'),
|
|
array($this, 'read'),
|
|
array($this, 'write'),
|
|
array($this, 'destroy'),
|
|
array($this, 'gc')
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
/* This is necessary as of PHP 5.0.5 because objects are not available
|
|
* when the write() handler is called at the end of a session
|
|
* access. */
|
|
session_write_close();
|
|
}
|
|
|
|
/**
|
|
* Open the backend.
|
|
*
|
|
* @param string $save_path The path to the session object.
|
|
* @param string $session_name The name of the session.
|
|
*
|
|
* @return boolean True on success, false otherwise.
|
|
*/
|
|
public function open($save_path = null, $session_name = null)
|
|
{
|
|
if (!$this->_connected) {
|
|
try {
|
|
$this->_storage->open($save_path, $session_name);
|
|
} catch (Horde_SessionHandler_Exception $e) {
|
|
$this->_logger->log($e, 'ERR');
|
|
return false;
|
|
}
|
|
|
|
$this->_connected = true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Close the backend.
|
|
*
|
|
* @return boolean True on success, false otherwise.
|
|
*/
|
|
public function close()
|
|
{
|
|
try {
|
|
$this->_storage->close();
|
|
} catch (Horde_SessionHandler_Exception $e) {
|
|
$this->_logger->log($e, 'ERR');
|
|
}
|
|
|
|
$this->_connected = false;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Read the data for a particular session identifier from the backend.
|
|
* This method should only be called internally by PHP via
|
|
* session_set_save_handler().
|
|
*
|
|
* @param string $id The session identifier.
|
|
*
|
|
* @return string The session data.
|
|
*/
|
|
public function read($id)
|
|
{
|
|
if (($result = $this->_storage->read($id)) == '') {
|
|
$this->_logger->log('Error retrieving session data (' . $id . ')', 'DEBUG');
|
|
} else {
|
|
$this->_logger->log('Read session data (' . $id . ')', 'DEBUG');
|
|
}
|
|
|
|
if (empty($this->_params['no_md5'])) {
|
|
$this->_sig = md5($result);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Write session data to the backend.
|
|
* This method should only be called internally by PHP via
|
|
* session_set_save_handler().
|
|
*
|
|
* @param string $id The session identifier.
|
|
* @param string $session_data The session data.
|
|
*
|
|
* @return boolean True on success, false otherwise.
|
|
*/
|
|
public function write($id, $session_data)
|
|
{
|
|
if ($this->changed ||
|
|
(empty($this->_params['no_md5']) &&
|
|
($this->_sig != md5($session_data)))) {
|
|
if (!$this->_storage->write($id, $session_data)) {
|
|
$this->_logger->log('Failed to write session data (' . $id . ')', 'DEBUG');
|
|
return false;
|
|
}
|
|
$this->_logger->log('Wrote session data (' . $id . ')', 'DEBUG');
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Destroy the data for a particular session identifier in the backend.
|
|
* This method should only be called internally by PHP via
|
|
* session_set_save_handler().
|
|
*
|
|
* @param string $id The session identifier.
|
|
*
|
|
* @return boolean True on success, false otherwise.
|
|
*/
|
|
public function destroy($id)
|
|
{
|
|
if ($this->_storage->destroy($id)) {
|
|
$this->_logger->log('Session data destroyed (' . $id . ')', 'DEBUG');
|
|
return true;
|
|
}
|
|
|
|
$this->_logger->log('Failed to destroy session data (' . $id . ')', 'DEBUG');
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Garbage collect stale sessions from the backend.
|
|
* This method should only be called internally by PHP via
|
|
* session_set_save_handler().
|
|
*
|
|
* @param integer $maxlifetime The maximum age of a session.
|
|
*
|
|
* @return boolean True on success, false otherwise.
|
|
*/
|
|
public function gc($maxlifetime = 300)
|
|
{
|
|
return $this->_storage->gc($maxlifetime);
|
|
}
|
|
|
|
/**
|
|
* Get a list of the valid session identifiers.
|
|
*
|
|
* @return array A list of valid session identifiers.
|
|
* @throws Horde_SessionHandler_Exception
|
|
*/
|
|
public function getSessionIDs()
|
|
{
|
|
return $this->_storage->getSessionIDs();
|
|
}
|
|
|
|
/**
|
|
* Returns a list of authenticated users and data about their session.
|
|
*
|
|
* @return array For authenticated users, the sessionid as a key and the
|
|
* session information as value. If no parsing function
|
|
* was provided, will always return an empty array.
|
|
* @throws Horde_SessionHandler_Exception
|
|
*/
|
|
public function getSessionsInfo()
|
|
{
|
|
$info = array();
|
|
|
|
if (empty($this->_params['parse']) ||
|
|
!is_callable($this->_params['parse'])) {
|
|
return $info;
|
|
}
|
|
|
|
/* Explicitly do garbage collection call here to make sure session
|
|
* data is correct. */
|
|
$this->gc(ini_get('session.gc_maxlifetime'));
|
|
|
|
$sessions = $this->getSessionIDs();
|
|
|
|
$this->_storage->readonly = true;
|
|
|
|
foreach ($sessions as $id) {
|
|
try {
|
|
$data = $this->read($id);
|
|
$this->close();
|
|
} catch (Horde_SessionHandler_Exception $e) {
|
|
continue;
|
|
}
|
|
|
|
$data = call_user_func($this->_params['parse'], $data);
|
|
if ($data !== false) {
|
|
$info[$id] = $data;
|
|
}
|
|
}
|
|
|
|
$this->_storage->readonly = false;
|
|
|
|
return $info;
|
|
}
|
|
|
|
}
|