* Abstracted memcache persistent-backend code into 'Stack' driver.
* Renamed 'none' driver to 'Builtin'.
* Now throws Horde_SessionHandler_Exception.
* Split driver code into abstract class.
* Use horde/Db to access SQL databases.
* Do not rely on Horde::logMessage() (or any of Core).
{
global $conf;
- $driver = empty($conf['sessionhandler']['type'])
- ? 'None'
- : $conf['sessionhandler']['type'];
-
+ if (empty($conf['sessionhandler']['type'])) {
+ $driver = 'Builtin';
+ } else {
+ $driver = $conf['sessionhandler']['type'];
+ if (strcasecmp($driver, 'None')) {
+ $driver = 'Builtin';
+ }
+ }
$params = Horde::getDriverConfig('sessionhandler', $driver);
if (strcasecmp($driver, 'Sql') === 0) {
- $write_db = $injector->getInstance('Horde_Db_Pear')->getOb();
-
- /* Check if we need to set up the read DB connection
- * separately. */
- if (empty($params['splitread'])) {
- $params['db'] = $write_db;
- } else {
- $params['write_db'] = $write_db;
- $params['db'] = $injector->getInstance('Horde_Db_Pear')->getOb('read');
- }
+ $params['db'] = $injector->getInstance('Horde_Db_Adapter_Base');
}
- if (!empty($conf['sessionhandler']['memcache'])) {
- $params['memcache'] = $injector->getInstance('Horde_Memcache');
+ $logger = $injector->getInstance('Horde_Log_Logger');
+
+ if (!empty($conf['sessionhandler']['memcache']) &&
+ (strcasecmp($driver, 'Builtin') != 0) &&
+ (strcasecmp($driver, 'Memcache') != 0)) {
+ $params = array(
+ 'stack' => array(
+ array(
+ 'driver' => 'Memcache',
+ 'params' => array(
+ 'memcache' => $injector->getInstance('Horde_Memcache'),
+ 'logger' => $logger
+ )
+ ),
+ array(
+ 'driver' => $driver,
+ 'params' => array_merge($params, array(
+ 'logger' => $logger
+ ))
+ )
+ )
+ );
+ $driver = 'Stack';
}
+ $params['logger'] = $logger;
+
return Horde_SessionHandler::factory($driver, $params);
}
if (!empty($conf['session']['use_only_cookies'])) {
ini_set('session.use_only_cookies', 1);
if (!empty($conf['cookie']['domain']) &&
- strpos($conf['server']['name'], '.') === false) {
+ (strpos($conf['server']['name'], '.') === false)) {
throw new Horde_Exception('Session cookies will not work without a FQDN and with a non-empty cookie domain. Either use a fully qualified domain name like "http://www.example.com" instead of "http://example" only, or set the cookie domain in the Horde configuration to an empty value, or enable non-cookie (url-based) sessions in the Horde configuration.');
}
}
- session_set_cookie_params($conf['session']['timeout'],
- $conf['cookie']['path'], $conf['cookie']['domain'], $conf['use_ssl'] == 1 ? 1 : 0);
+ session_set_cookie_params(
+ $conf['session']['timeout'],
+ $conf['cookie']['path'],
+ $conf['cookie']['domain'],
+ $conf['use_ssl'] == 1 ? 1 : 0
+ );
session_cache_limiter(is_null($this->initParams['session_cache_limiter']) ? $conf['session']['cache_limiter'] : $this->initParams['session_cache_limiter']);
session_name(urlencode($conf['session']['name']));
- $type = empty($conf['sessionhandler']['type'])
- ? 'none'
- : $conf['sessionhandler']['type'];
-
- if ($type == 'external') {
- $calls = $conf['sessionhandler']['params'];
- session_set_save_handler(
- $calls['open'],
- $calls['close'],
- $calls['read'],
- $calls['write'],
- $calls['destroy'],
- $calls['gc']
- );
- } elseif ($type != 'none') {
- $this->sessionHandler = $GLOBALS['injector']->getInstance('Horde_SessionHandler');
- }
+ /* We want to create an instance here, not get, since we may be
+ * destroying the previous instances in the page. */
+ $this->sessionHandler = $GLOBALS['injector']->createInstance('Horde_SessionHandler');
}
/**
* Horde_SessionHandler:: defines an API for implementing custom PHP session
* handlers.
*
- * Optional parameters:<pre>
- * 'memcache' - (Horde_Memcache) If set, uses memcache to cache session
- * data.
- * </pre>
- *
* Copyright 2002-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
- * @author Mike Cochrane <mike@graftonhall.co.nz>
- * @author Michael Slusarz <slusarz@curecanti.org>
- * @package Horde_SessionHandler
+ * @author Mike Cochrane <mike@graftonhall.co.nz>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package SessionHandler
*/
class Horde_SessionHandler
{
/**
- * Hash containing connection parameters.
- *
- * @var array
- */
- protected $_params = array();
-
- /**
- * Initial session data signature.
- *
- * @var string
- */
- protected $_sig;
-
- /**
- * Force saving the session data?
- *
- * @var boolean
- */
- protected $_force = false;
-
- /**
- * Has a connection been made to the backend?
- *
- * @var boolean
- */
- protected $_connected = false;
-
- /**
- * Attempts to return a concrete Horde_SessionHandler instance based on
- * $driver.
+ * Attempts to return a concrete instance based on $driver.
*
* @param string $driver The type of concrete subclass to return
* (case-insensitive).
* @param array $params A hash containing any additional configuration or
* connection parameters a subclass might need.
*
- * @return Horde_SessionHandler The newly created concrete instance.
- * @throws Horde_Exception
+ * @return Horde_SessionHandler_Driver The newly created concrete
+ * instance.
+ * @throws Horde_SessionHandler_Exception
*/
- static public function factory($driver, $params = array())
+ static public function factory($driver, array $params = array())
{
$driver = basename(strtolower($driver));
- $persistent_params = array();
-
- if ($driver == 'memcached') {
- // Trap for old driver name.
- $driver = 'memcache';
- } elseif (($driver != 'memcache') && !empty($params['memcache'])) {
- $p_params = $params;
- unset($p_params['memcache']);
-
- $persistent_params = array(
- 'persistent_driver' => $driver,
- 'persistent_params' => $p_params
- );
-
- $driver = 'memcache';
- }
-
$class = __CLASS__ . '_' . ucfirst($driver);
if (class_exists($class)) {
- if (empty($params)) {
- $params = Horde::getDriverConfig('sessionhandler', $driver);
- }
- return new $class(array_merge($params, $persistent_params));
- }
-
- throw new Horde_Exception('Driver "' . $driver . '" not found.');
- }
-
- /**
- * Constructor.
- *
- * @param array $params A hash containing connection parameters.
- *
- * @throws Horde_Exception
- */
- protected function __construct($params = array())
- {
- $this->_params = $params;
-
- register_shutdown_function(array($this, 'shutdown'));
-
- ini_set('session.save_handler', 'user');
- 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();
- }
-
- /**
- * Shutdown function.
- *
- * Used to determine if we need to write the session to avoid a session
- * timeout, even though the session is unchanged.
- * Theory: On initial login, set the current time plus half of the max
- * lifetime in the session. Then check this timestamp before saving.
- * If we exceed, force a write of the session and set a new timestamp.
- * Why half the maxlifetime? It guarantees that if we are accessing the
- * server via a periodic mechanism (think folder refreshing in IMP) that
- * we will catch this refresh.
- */
- public function shutdown()
- {
- $curr_time = time();
-
- if (!isset($_SESSION['sessionhandler']) ||
- ($curr_time >= $_SESSION['sessionhandler'])) {
- $_SESSION['sessionhandler'] = $curr_time + (ini_get('session.gc_maxlifetime') / 2);
- $this->_force = true;
- }
- }
-
- /**
- * 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->_open($save_path, $session_name);
- } catch (Horde_Exception $e) {
- Horde::logMessage($e, 'ERR');
- return false;
- }
-
- $this->_connected = true;
- }
-
- return true;
- }
-
- /**
- * Open the backend.
- *
- * @param string $save_path The path to the session object.
- * @param string $session_name The name of the session.
- *
- * @throws Horde_Exception
- */
- protected function _open($save_path = null, $session_name = null)
- {
- }
-
- /**
- * Close the backend.
- *
- * @return boolean True on success, false otherwise.
- */
- public function close()
- {
- try {
- $this->_close();
- } catch (Horde_Exception $e) {
- Horde::logMessage($e, 'ERR');
- return false;
- }
-
- $this->_connected = false;
- return true;
- }
-
- /**
- * Close the backend.
- *
- * @throws Horde_Exception
- */
- protected function _close()
- {
- }
-
- /**
- * 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)
- {
- $result = $this->_read($id);
- $this->_sig = md5($result);
- return $result;
- }
-
- /**
- * Read the data for a particular session identifier from the backend.
- *
- * @param string $id The session identifier.
- *
- * @return string The session data.
- */
- protected function _read($id)
- {
- return '';
- }
-
- /**
- * 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->_force && ($this->_sig == md5($session_data))) {
- Horde::logMessage('Session data unchanged (id = ' . $id . ')', 'DEBUG');
- return true;
- }
-
- return $this->_write($id, $session_data);
- }
-
- /**
- * Write session data to the backend.
- *
- * @param string $id The session identifier.
- * @param string $session_data The session data.
- *
- * @return boolean True on success, false otherwise.
- */
- protected function _write($id, $session_data)
- {
- return false;
- }
-
- /**
- * 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)
- {
- 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 false;
- }
-
- /**
- * Get session data read-only.
- *
- * @param string $id The session identifier.
- *
- * @return string The session data.
- */
- protected function _readOnly($id)
- {
- return $this->read($id);
- }
-
- /**
- * Get a list of the valid session identifiers.
- *
- * @return array A list of valid session identifiers.
- * @throws Horde_Exception
- */
- public function getSessionIDs()
- {
- throw new Horde_Exception(_("Not supported."));
- }
-
- /**
- * Returns a list of authenticated users and data about their session.
- *
- * @return array For authenticated users, the sessionid as a key and the
- * information returned from Horde_Auth::readSessionData()
- * as values.
- * @throws Horde_Exception
- */
- public function getSessionsInfo()
- {
- $sessions = $this->getSessionIDs();
-
- $info = array();
-
- foreach ($sessions as $id) {
- try {
- $data = $this->_readOnly($id);
- } catch (Horde_Exception $e) {
- continue;
- }
- $data = Horde_Auth::readSessionData($data, true);
- if ($data !== false) {
- $info[$id] = $data;
- }
+ return new $class($params);
}
- return $info;
+ throw new Horde_SessionHandler_Exception('Driver not found: ' . $driver);
}
}
--- /dev/null
+<?php
+/**
+ * SessionHandler:: implementation for PHP's built-in session handler.
+ * This doesn't do any session handling itself - instead, it exists to allow
+ * utility features to be used with the built-in PHP handler.
+ *
+ * Copyright 2005-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Matt Selsky <selsky@columbia.edu>
+ * @category Horde
+ * @package SessionHandler
+ */
+class Horde_SessionHandler_Builtin extends Horde_SessionHandler_Driver
+{
+ /**
+ * Constructor.
+ *
+ * @param array $params Parameters.
+ */
+ public function __construct(array $params = array())
+ {
+ parent::__construct(array_merge($params, array(
+ 'noset' => true
+ )));
+ }
+
+ /**
+ * Open the backend.
+ *
+ * @param string $save_path The path to the session object.
+ * @param string $session_name The name of the session.
+ */
+ protected function _open($save_path = null, $session_name = null)
+ {
+ }
+
+ /**
+ * Close the backend.
+ *
+ * @throws Horde_Exception
+ */
+ protected function _close()
+ {
+ }
+
+ /**
+ * Read the data for a particular session identifier from the backend.
+ *
+ * @param string $id The session identifier.
+ *
+ * @return string The session data.
+ */
+ protected function _read($id)
+ {
+ $file = session_save_path() . DIRECTORY_SEPARATOR . 'sess_' . $id;
+ $session_data = @file_get_contents($file);
+ if (($session_data === false) && $this->_logger) {
+ $this->_logger->log('Unable to read file: ' . $file, 'ERR');
+ }
+
+ return strval($session_data);
+ }
+
+ /**
+ * Write session data to the backend.
+ *
+ * @param string $id The session identifier.
+ * @param string $session_data The session data.
+ *
+ * @return boolean True on success, false otherwise.
+ */
+ protected function _write($id, $session_data)
+ {
+ return false;
+ }
+
+ /**
+ * 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)
+ {
+ 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 false;
+ }
+
+ /**
+ * Get a list of the valid session identifiers.
+ *
+ * @return array A list of valid session identifiers.
+ */
+ public function getSessionIDs()
+ {
+ $sessions = array();
+
+ $path = session_save_path();
+
+ try {
+ $di = new DirectoryIterator(empty($path) ? Horde_Util::getTempDir() : $path);
+ } catch (UnexpectedValueException $e) {
+ return $sessions;
+ }
+
+ foreach ($di as $key => $val) {
+ /* Make sure we're dealing with files that start with sess_. */
+ if ($val->isFile() && (strpos($key, 'sess_') === 0)) {
+ $sessions[] = substr($entry, strlen('sess_'));
+ }
+ }
+
+ return $sessions;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Horde_SessionHandler_Driver:: is the abstract class that all drivers
+ * inherit from.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package SessionHandler
+ */
+abstract class Horde_SessionHandler_Driver
+{
+ /**
+ * Hash containing connection parameters.
+ *
+ * @var array
+ */
+ protected $_params = array();
+
+ /**
+ * Initial session data signature.
+ *
+ * @var string
+ */
+ protected $_sig;
+
+ /**
+ * Force saving the session data?
+ *
+ * @var boolean
+ */
+ protected $_force = false;
+
+ /**
+ * Has a connection been made to the backend?
+ *
+ * @var boolean
+ */
+ protected $_connected = false;
+
+ /**
+ * A logger instance.
+ *
+ * @var Horde_Log_Logger
+ */
+ protected $_logger;
+
+ /**
+ * Session variable name.
+ *
+ * @var string
+ */
+ protected $_session = 'horde_sh';
+
+ /**
+ * Constructor.
+ *
+ * @param array $params Parameters:
+ * <pre>
+ * 'logger' - (Horde_Log_Logger) A logger instance.
+ * DEFAULT: No logging
+ * 'noset' - (boolean) If true, don't set the save handler.
+ * DEFAULT: false
+ * </pre>
+ */
+ public function __construct(array $params = array())
+ {
+ $params = array_merge($this->_params, $params);
+
+ if (isset($params['logger'])) {
+ $this->_logger = $params['logger'];
+ unset($params['logger']);
+ }
+
+ $this->_params = $params;
+
+ register_shutdown_function(array($this, 'shutdown'));
+
+ if (empty($this->_params['noset'])) {
+ ini_set('session.save_handler', 'user');
+ 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();
+ }
+
+ /**
+ * Shutdown function.
+ *
+ * Used to determine if we need to write the session to avoid a session
+ * timeout, even though the session is unchanged.
+ * Theory: On initial login, set the current time plus half of the max
+ * lifetime in the session. Then check this timestamp before saving.
+ * If we exceed, force a write of the session and set a new timestamp.
+ * Why half the maxlifetime? It guarantees that if we are accessing the
+ * server via a periodic mechanism (think folder refreshing in IMP) that
+ * we will catch this refresh.
+ */
+ public function shutdown()
+ {
+ $curr_time = time();
+
+ if (!isset($_SESSION[$this->_session]) ||
+ ($curr_time >= $_SESSION[$this->_session])) {
+ $_SESSION[$this->_session] = $curr_time + (ini_get('session.gc_maxlifetime') / 2);
+ $this->_force = true;
+ }
+ }
+
+ /**
+ * 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->_open($save_path, $session_name);
+ } catch (Horde_SessionHandler_Exception $e) {
+ if ($this->_logger) {
+ $this->_logger->log($e, 'ERR');
+ }
+ return false;
+ }
+
+ $this->_connected = true;
+ }
+
+ return true;
+ }
+
+ /**
+ * Open the backend.
+ *
+ * @param string $save_path The path to the session object.
+ * @param string $session_name The name of the session.
+ *
+ * @throws Horde_SessionHandler_Exception
+ */
+ abstract protected function _open($save_path = null, $session_name = null);
+
+ /**
+ * Close the backend.
+ *
+ * @return boolean True on success, false otherwise.
+ */
+ public function close()
+ {
+ try {
+ $this->_close();
+ } catch (Horde_SessionHandler_Exception $e) {
+ if ($this->_logger) {
+ $this->_logger->log($e, 'ERR');
+ }
+ return false;
+ }
+
+ $this->_connected = false;
+ return true;
+ }
+
+ /**
+ * Close the backend.
+ *
+ * @throws Horde_SessionHandler_Exception
+ */
+ abstract protected function _close();
+
+ /**
+ * 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)
+ {
+ $result = $this->_read($id);
+ $this->_sig = md5($result);
+ return $result;
+ }
+
+ /**
+ * Read the data for a particular session identifier from the backend.
+ *
+ * @param string $id The session identifier.
+ *
+ * @return string The session data.
+ */
+ abstract protected function _read($id);
+
+ /**
+ * 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->_force && ($this->_sig == md5($session_data))) {
+ if ($this->_logger) {
+ $this->_logger->log('Session data unchanged (id = ' . $id . ')', 'DEBUG');
+ }
+ return true;
+ }
+
+ return $this->_write($id, $session_data);
+ }
+
+ /**
+ * Write session data to the backend.
+ *
+ * @param string $id The session identifier.
+ * @param string $session_data The session data.
+ *
+ * @return boolean True on success, false otherwise.
+ */
+ abstract protected function _write($id, $session_data);
+
+ /**
+ * 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.
+ */
+ abstract public function destroy($id);
+
+ /**
+ * 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.
+ */
+ abstract public function gc($maxlifetime = 300);
+
+ /**
+ * Get session data read-only.
+ *
+ * @param string $id The session identifier.
+ *
+ * @return string The session data.
+ */
+ protected function _readOnly($id)
+ {
+ return $this->read($id);
+ }
+
+ /**
+ * Get a list of the valid session identifiers.
+ *
+ * @return array A list of valid session identifiers.
+ * @throws Horde_SessionHandler_Exception
+ */
+ abstract public function getSessionIDs();
+
+ /**
+ * Returns a list of authenticated users and data about their session.
+ *
+ * @return array For authenticated users, the sessionid as a key and the
+ * information returned from Horde_Auth::readSessionData()
+ * as values.
+ * @throws Horde_SessionHandler_Exception
+ */
+ public function getSessionsInfo()
+ {
+ $sessions = $this->getSessionIDs();
+
+ $info = array();
+
+ foreach ($sessions as $id) {
+ try {
+ $data = $this->_readOnly($id);
+ } catch (Horde_SessionHandler_Exception $e) {
+ continue;
+ }
+ $data = Horde_Auth::readSessionData($data, true);
+ if ($data !== false) {
+ $info[$id] = $data;
+ }
+ }
+
+ return $info;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Exception handler for the SessionHandler package.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package SessionHandler
+ */
+class Horde_SessionHandler_Exception extends Horde_Exception_Prior
+{
+}
--- /dev/null
+<?php
+/**
+ * Horde_SessionHandler_External:: implements an external save handler defined
+ * via driver configuration parameters.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package SessionHandler
+ */
+class Horde_SessionHandler_External extends Horde_SessionHandler_Driver
+{
+ /**
+ * Constructor.
+ *
+ * @param array $params Required parameters:
+ * <pre>
+ * 'close' - (callback) See session_set_save_handler().
+ * 'destroy' - (callback) See session_set_save_handler().
+ * 'gc' - (callback) See session_set_save_handler().
+ * 'open' - (callback) See session_set_save_handler().
+ * 'read' - (callback) See session_set_save_handler().
+ * 'write' - (callback) See session_set_save_handler().
+ * </pre>
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $params = array())
+ {
+ foreach (array('open', 'close', 'read', 'write', 'destroy', 'gc') as $val) {
+ if (!isset($params[$val])) {
+ throw new InvalidArgumentException('Missing parameter: ' . $val);
+ }
+ }
+
+ parent::__construct($params);
+ }
+
+ /**
+ * Open the backend.
+ *
+ * @param string $save_path The path to the session object.
+ * @param string $session_name The name of the session.
+ */
+ protected function _open($save_path = null, $session_name = null)
+ {
+ call_user_func($this->_params['open'], $save_path, $session_name);
+ }
+
+ /**
+ * Close the backend.
+ */
+ protected function _close()
+ {
+ call_user_func($this->_params['close']);
+ }
+
+ /**
+ * Read the data for a particular session identifier from the backend.
+ *
+ * @param string $id The session identifier.
+ *
+ * @return string The session data.
+ */
+ protected function _read($id)
+ {
+ return call_user_func($this->_params['read']);
+ }
+
+ /**
+ * Write session data to the backend.
+ *
+ * @param string $id The session identifier.
+ * @param string $session_data The session data.
+ *
+ * @return boolean True on success, false otherwise.
+ */
+ protected function _write($id, $session_data)
+ {
+ return call_user_func($this->_params['write'], $id, $session_data);
+ }
+
+ /**
+ * 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)
+ {
+ return call_user_func($this->_params['destroy'], $id);
+ }
+
+ /**
+ * 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 call_user_func($this->_params['gc'], $maxlifetime);
+ }
+
+ /**
+ * Get a list of the valid session identifiers.
+ *
+ * @throws Horde_SessionHandler_Exception
+ */
+ public function getSessionIDs()
+ {
+ throw new Horde_SessionHandler_Exception('Driver does not support listing session IDs.');
+ }
+
+}
<?php
/**
- * Horde_SessionHandler:: implementation for LDAP directories.
- *
- * Required parameters:<pre>
- * 'hostspec' - (string) The hostname of the ldap server.
- * 'port' - (integer) The port number of the ldap server.
- * 'dn' - (string) The bind DN.
- * 'password' - (string) The bind password.
- * </pre>
+ * SessionHandler implementation for LDAP directories.
*
* This code is adapted from the comments at
* http://www.php.net/session-set-save-handler.
*
+ * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
+ *
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
- * @package Horde_SessionHandler
+ * @category Horde
+ * @package SessionHandler
*/
-class Horde_SessionHandler_Ldap extends Horde_SessionHandler
+class Horde_SessionHandler_Ldap extends Horde_SessionHandler_Driver
{
/**
* Handle for the current database connection.
protected $_conn;
/**
+ * Constructor.
+ *
+ * @param array $params Parameters:
+ * <pre>
+ * 'dn' - (string) The bind DN.
+ * 'hostspec' - (string) The hostname of the ldap server.
+ * 'password' - (string) The bind password.
+ * 'port' - (integer) The port number of the ldap server.
+ * 'version' - (integer) [OPTIONAL] TODO
+ * </pre>
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $params = array())
+ {
+ foreach (array('dn', 'hostspec', 'password', 'port') as $val) {
+ if (!isset($params[$val])) {
+ throw new InvalidArgumentException('Missing ' . $val . ' parameter.');
+ }
+ }
+
+ parent::__construct($params);
+ }
+
+ /**
* Open the backend.
*
* @param string $save_path The path to the session object.
* @param string $session_name The name of the session.
*
- * @throws Horde_Exception
+ * @throws Horde_SessionHandler_Exception
*/
protected function _open($save_path = null, $session_name = null)
{
$this->_conn = @ldap_connect($this->_params['hostspec'], $this->_params['port']);
// Set protocol version if necessary.
- if (isset($this->_params['version'])) {
- if (!@ldap_set_option($this->_ds, LDAP_OPT_PROTOCOL_VERSION, $this->_params['version'])) {
- throw new Horde_Exception(sprintf('Set LDAP protocol version to %d failed: [%d] %s', $this->_params['version'], ldap_errno($conn), ldap_error($conn)));
- }
+ if (isset($this->_params['version']) &&
+ !@ldap_set_option($this->_ds, LDAP_OPT_PROTOCOL_VERSION, $this->_params['version'])) {
+ throw new Horde_SessionHandler_Exception(sprintf('Set LDAP protocol version to %d failed: [%d] %s', $this->_params['version'], ldap_errno($conn), ldap_error($conn)));
}
if (!@ldap_bind($this->_conn, $this->_params['dn'], $this->_params['password'])) {
- throw new Horde_Exception('Could not bind to LDAP server.');
+ throw new Horde_SessionHandler_Exception('Could not bind to LDAP server.');
}
}
*/
protected function _close()
{
- if (!@ldap_close($this->_conn)) {
- throw new Horde_Exception('Could not unbind from LDAP server.');
+ if (!@ldap_close($this->_conn) && $this->_logger) {
+ $this->_logger->log('Could not unbind from LDAP server.', 'INFO');
}
}
{
$sr = @ldap_search($this->_conn, $this->_params['dn'], "(cn=$id)");
$info = @ldap_get_entries($this->_conn, $sr);
- return ($info['count'] > 0) ? $info[0]['session'][0] : '';
+
+ return ($info['count'] > 0)
+ ? $info[0]['session'][0]
+ : '';
}
/**
*/
protected function _write($id, $session_data)
{
- $update = array('objectClass' => array('phpsession', 'top'),
- 'session' => $session_data);
+ $update = array(
+ 'objectClass' => array('phpsession', 'top'),
+ 'session' => $session_data
+ );
$dn = "cn=$id," . $this->_params['dn'];
@ldap_delete($this->_conn, $dn);
+
return @ldap_add($this->_conn, $dn, $update);
}
public function destroy($id)
{
$dn = "cn=$id," . $this->_params['dn'];
+
return @ldap_delete($this->_conn, $dn);
}
$sr = @ldap_search($this->_conn, $this->_params['dn'],
'(objectClass=phpsession)', array('+', 'cn'));
$info = @ldap_get_entries($this->_conn, $sr);
+
if ($info['count'] > 0) {
- for ($i = 0; $i < $info['count']; $i++) {
+ for ($i = 0; $i < $info['count']; ++$i) {
$id = $info[$i]['cn'][0];
$dn = "cn=$id," . $this->_params['dn'];
$ldapstamp = $info[$i]['modifytimestamp'][0];
return true;
}
+ /**
+ * Get a list of the valid session identifiers.
+ *
+ * @throws Horde_SessionHandler_Exception
+ */
+ public function getSessionIDs()
+ {
+ throw new Horde_SessionHandler_Exception('Driver does not support listing session IDs.');
+ }
+
}
<?php
/**
- * Horde_SessionHandler implementation for memcache.
- *
- * Required parameters:<pre>
- * 'memcache' - (Horde_Memcache) A memcache object.
- * </pre>
- *
- * Optional parameters:<pre>
- * 'persistent_driver' - (string) If set, uses this backend to store session
- * data persistently.
- * 'persistent_params' - (array) If using a persistent backend, the params
- * to use for the persistent backend.
- * 'track' - (boolean) Track active sessions?
- * 'track_lifetime' - (integer) The number of seconds after which tracked
- * sessions will be treated as expired.
- * </pre>
+ * SessionHandler implementation for memcache.
*
* Copyright 2005-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
- * @author Rong-En Fan <rafan@infor.org>
- * @author Michael Slusarz <slusarz@curecanti.org>
- * @package Horde_SessionHandler
+ * @author Rong-En Fan <rafan@infor.org>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package SessionHandler
*/
-class Horde_SessionHandler_Memcache extends Horde_SessionHandler
+class Horde_SessionHandler_Memcache extends Horde_SessionHandler_Driver
{
/**
* Memcache object.
protected $_id;
/**
- * Persistent backend driver.
- *
- * @var Horde_SessionHandler
- */
- protected $_persistent;
-
- /**
* Do read-only get?
*
* @var boolean
/**
* Constructor.
*
- * @param array $params A hash containing connection parameters.
+ * @param array $params Parameters:
+ * <pre>
+ * 'memcache' - (Horde_Memcache) [REQUIRED] A memcache object.
+ * 'track' - (boolean) Track active sessions?
+ * 'track_lifetime' - (integer) The number of seconds after which tracked
+ * sessions will be treated as expired.
+ * </pre>
*
- * @throws Horde_Exception
* @throws InvalidArgumentException
*/
- protected function __construct($params = array())
+ public function __construct(array $params = array())
{
if (empty($params['memcache'])) {
- throw InvalidArgumentException('Missing memcache object.');
+ throw InvalidArgumentException('Missing memcache argument.');
}
$this->_memcache = $params['memcache'];
-
- if (!empty($params['persistent_driver'])) {
- try {
- $this->_persistent = self::singleton($params['persistent_driver'], empty($params['persistent_params']) ? null : $params['persistent_params']);
- } catch (Horde_Exception $e) {
- throw new Horde_Exception('Horde is unable to correctly start the persistent session handler.');
- }
- }
+ unset($params['memcache']);
parent::__construct($params);
- // If using a persistent backend, don't track sessions in memcache
- if (isset($this->_persistent)) {
- $this->_params['track'] = false;
- }
-
- if (empty($this->_params['track_lifetime'])) {
- $this->_params['track_lifetime'] = ini_get('session.gc_maxlifetime');
+ if (empty($this->_params['track_lt'])) {
+ $this->_params['track_lt'] = ini_get('session.gc_maxlifetime');
}
if (!empty($this->_params['track']) && (rand(0, 999) == 0)) {
* @param string $save_path The path to the session object.
* @param string $session_name The name of the session.
*
- * @throws Horde_Exception
+ * @throws Horde_SessionHandler_Exception
*/
protected function _open($save_path = null, $session_name = null)
{
- if (isset($this->_persistent)) {
- if (!$this->_persistent->open($save_path, $session_name)) {
- throw new Horde_Exception('Could not open persistent backend.');
- }
- }
}
/**
* Close the backend.
- *
- * @throws Horde_Exception
*/
protected function _close()
{
if (isset($this->_id)) {
$this->_memcache->unlock($this->_id);
}
- if (isset($this->_persistent)) {
- $this->_persistent->close();
- }
}
/**
$this->_memcache->unlock($id);
}
- if (isset($this->_persistent)) {
- $result = $this->_persistent->read($id);
- }
-
if ($result === false) {
- Horde::logMessage('Error retrieving session data (id = ' . $id . ')', 'DEBUG');
+ if ($this->_logger) {
+ $this->_logger->log('Error retrieving session data (id = ' . $id . ')', 'DEBUG');
+ }
return false;
}
-
- $this->_persistent->write($id, $session_data);
}
if (!$this->_readonly) {
$this->_id = $id;
}
- Horde::logMessage('Read session data (id = ' . $id . ')', 'DEBUG');
+ if ($this->_logger) {
+ $this->_logger->log('Read session data (id = ' . $id . ')', 'DEBUG');
+ }
+
return $result;
}
if (!$res &&
!$this->_memcache->set($id, $session_data)) {
- Horde::logMessage('Error writing session data (id = ' . $id . ')', 'ERR');
+ if ($this->_logger) {
+ $this->_logger->log('Error writing session data (id = ' . $id . ')', 'ERR');
+ }
return false;
}
- if (isset($this->_persistent)) {
- $result = $this->_persistent->write($id, $session_data);
- }
-
if ($track) {
$this->_memcache->lock($this->_trackID);
$ids = $this->_memcache->get($this->_trackID);
$this->_memcache->unlock($this->_trackID);
}
- Horde::logMessage('Wrote session data (id = ' . $id . ')', 'DEBUG');
+ if ($this->_logger) {
+ $this->_logger->log('Wrote session data (id = ' . $id . ')', 'DEBUG');
+ }
+
return true;
}
$this->_memcache->unlock($id);
if ($result === false) {
- Horde::logMessage('Failed to delete session (id = ' . $id . ')', 'DEBUG');
+ if ($this->_logger) {
+ $this->_logger->log('Failed to delete session (id = ' . $id . ')', 'DEBUG');
+ }
return false;
}
- if (isset($this->_persistent)) {
- $result = $this->_persistent->destroy($id);
- }
-
if (!empty($this->_params['track'])) {
$this->_memcache->lock($this->_trackID);
$ids = $this->_memcache->get($this->_trackID);
$this->_memcache->unlock($this->_trackID);
}
- Horde::logMessage('Deleted session data (id = ' . $id . ')', 'DEBUG');
+ if ($this->_logger) {
+ $this->_logger->log('Deleted session data (id = ' . $id . ')', 'DEBUG');
+ }
+
return true;
}
*/
public function gc($maxlifetime = 300)
{
- $result = true;
-
- if (isset($this->_persistent)) {
- $result = $this->_persistent->gc($maxlifetime);
- }
-
// Memcache does its own garbage collection.
- return $result;
+ return true;
}
/**
* Get a list of (possibly) valid session identifiers.
*
* @return array A list of session identifiers.
- * @throws Horde_Exception
+ * @throws Horde_SessionHandler_Exception
*/
public function getSessionIDs()
{
- if (isset($this->_persistent)) {
- return $this->_persistent->getSessionIDs();
- }
-
- try {
- $this->_open();
-
- if (empty($this->_params['track'])) {
- throw new Horde_Exception(_("Memcache session tracking not enabled."));
- }
- } catch (Horde_Exception $e) {
- if (isset($this->_persistent)) {
- return $this->_persistent->getSessionIDs();
- }
- throw $e;
+ if (empty($this->_params['track'])) {
+ throw new Horde_SessionHandler_Exception('Memcache session tracking not enabled.');
}
$this->trackGC();
$ids = $this->_memcache->get($this->_trackID);
- return ($ids === false) ? array() : array_keys($ids);
+
+ return ($ids === false)
+ ? array()
+ : array_keys($ids);
}
/**
$this->_readonly = true;
$result = $this->_memcache->get($id);
$this->_readonly = false;
+
return $result;
}
return;
}
- $tstamp = time() - $this->_params['track_lifetime'];
+ $tstamp = time() - $this->_params['track_lt'];
$alter = false;
foreach ($ids as $key => $val) {
+++ /dev/null
-<?php
-/**
- * Horde_SessionHandler:: implementation for MySQL (native).
- *
- * Required parameters:<pre>
- * 'hostspec' - (string) The hostname of the database server.
- * 'protocol' - (string) The communication protocol ('tcp', 'unix', etc.).
- * 'username' - (string) The username with which to connect to the
- * database.
- * 'password' - (string) The password associated with 'username'.
- * 'database' - (string) The name of the database.
- * 'table' - (string) The name of the sessiondata table in 'database'.
- * 'rowlocking' - (boolean) Whether to use row-level locking and
- * transactions (InnoDB) or table-level locking (MyISAM).
- * </pre>
- *
- * Required for some configurations:<pre>
- * 'port' - (integer) The port on which to connect to the database.
- * </pre>
- *
- * Optional parameters:<pre>
- * 'persistent' - (boolean) Use persistent DB connections?
- * </pre>
- *
- * The table structure can be found in:
- * horde/scripts/sql/horde_sessionhandler.sql.
- *
- * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Mike Cochrame <mike@graftonhall.co.nz>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @author Jan Schneider <jan@horde.org>
- * @package Horde_SessionHandler
- */
-class Horde_SessionHandler_Mysql extends Horde_SessionHandler
-{
- /**
- * Handle for the current database connection.
- *
- * @var resource
- */
- protected $_db;
-
- /**
- * Attempts to open a connection to the SQL server.
- *
- * @param string $save_path The path to the session object.
- * @param string $session_name The name of the session.
- *
- * @throws Horde_Exception
- */
- protected function _open($save_path = null, $session_name = null)
- {
- Horde::assertDriverConfig($this->_params, 'sessionhandler',
- array('hostspec', 'username', 'database'),
- 'session handler MySQL');
-
- if (empty($this->_params['password'])) {
- $this->_params['password'] = '';
- }
-
- if (empty($this->_params['table'])) {
- $this->_params['table'] = 'horde_sessionhandler';
- }
-
- $connect = empty($this->_params['persistent'])
- ? 'mysql_connect'
- : 'mysql_pconnect';
-
- if (!$this->_db = @$connect($this->_params['hostspec'] . (!empty($this->_params['port']) ? ':' . $this->_params['port'] : ''),
- $this->_params['username'],
- $this->_params['password'])) {
- throw new Horde_Exception('Could not connect to database for SQL Horde_SessionHandler.');
- }
-
- if (!@mysql_select_db($this->_params['database'], $this->_db)) {
- throw new Horde_Exception(sprintf('Could not connect to database %s for SQL Horde_SessionHandler.', $this->_params['database']));
- }
- }
-
- /**
- * Close the backend.
- *
- * @throws Horde_Exception
- */
- protected function _close()
- {
- /* Disconnect from database. */
- if (!@mysql_close($this->_db)) {
- throw new Horde_Exception('Could not disconnect from database.');
- }
- }
-
- /**
- * Read the data for a particular session identifier from the backend.
- *
- * @param string $id The session identifier.
- *
- * @return string The session data.
- */
- protected function _read($id)
- {
- /* Select db */
- if (!@mysql_select_db($this->_params['database'], $this->_db)) {
- return '';
- }
-
- $query = sprintf('SELECT session_data FROM %s WHERE session_id = %s',
- $this->_params['table'],
- $this->_quote($id));
-
- if (!empty($this->_params['rowlocking'])) {
- /* Start a transaction. */
- $result = @mysql_query('START TRANSACTION', $this->_db);
- $query .= ' FOR UPDATE';
- } else {
- $result = @mysql_query('LOCK TABLES ' . $this->_params['table'] . ' WRITE', $this->_db);
- }
- if (!$result) {
- return '';
- }
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Mysql::_read(): query = "%s"', $query), 'DEBUG');
-
- $result = @mysql_query($query, $this->_db);
- if (!$result) {
- Horde::logMessage('Error retrieving session data (id = ' . $id . '): ' . mysql_error($this->_db), 'ERR');
- return '';
- }
-
- return @mysql_result($result, 0, 0);
- }
-
- /**
- * Write session data to the backend.
- *
- * @param string $id The session identifier.
- * @param string $session_data The session data.
- *
- * @return boolean True on success, false otherwise.
- */
- protected function _write($id, $session_data)
- {
- /* Select db */
- if (!@mysql_select_db($this->_params['database'], $this->_db)) {
- return '';
- }
-
- /* Build the SQL query. */
- $query = sprintf('REPLACE INTO %s (session_id, session_data, session_lastmodified)' .
- ' VALUES (%s, %s, %s)',
- $this->_params['table'],
- $this->_quote($id),
- $this->_quote($session_data),
- time());
-
- $result = @mysql_query($query, $this->_db);
- if (!$result) {
- $error = mysql_error($this->_db);
- }
- if (empty($this->_params['rowlocking'])) {
- @mysql_query('UNLOCK TABLES ' . $this->_params['table'], $this->_db);
- }
- if (!$result) {
- @mysql_query('ROLLBACK', $this->_db);
- Horde::logMessage('Error writing session data: ' . $error, 'ERR');
- return false;
- }
-
- @mysql_query('COMMIT', $this->_db);
-
- return true;
- }
-
- /**
- * Destroy the data for a particular session identifier in the backend.
- *
- * @param string $id The session identifier.
- *
- * @return boolean True on success, false otherwise.
- */
- public function destroy($id)
- {
- /* Select db */
- if (!@mysql_select_db($this->_params['database'], $this->_db)) {
- return '';
- }
-
- /* Build the SQL query. */
- $query = sprintf('DELETE FROM %s WHERE session_id = %s',
- $this->_params['table'], $this->_quote($id));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Mysql::destroy(): query = "%s"', $query), 'DEBUG');
-
- /* Execute the query. */
- $result = @mysql_query($query, $this->_db);
- if (!$result) {
- $error = mysql_error($this->_db);
- }
- if (empty($this->_params['rowlocking'])) {
- @mysql_query('UNLOCK TABLES ' . $this->_params['table'], $this->_db);
- }
- if (!$result) {
- @mysql_query('ROLLBACK', $this->_db);
- Horde::logMessage('Failed to delete session (id = ' . $id . '): ' . $error, 'ERR');
- return false;
- }
-
- @mysql_query('COMMIT', $this->_db);
-
- return true;
- }
-
- /**
- * Garbage collect stale sessions from the backend.
- *
- * @param integer $maxlifetime The maximum age of a session.
- *
- * @return boolean True on success, false otherwise.
- */
- public function gc($maxlifetime = 300)
- {
- /* Select db */
- if (!@mysql_select_db($this->_params['database'], $this->_db)) {
- return '';
- }
-
- /* Build the SQL query. */
- $query = sprintf('DELETE FROM %s WHERE session_lastmodified < %s',
- $this->_params['table'], (int)(time() - $maxlifetime));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Mysql::gc(): query = "%s"', $query), 'DEBUG');
-
- /* Execute the query. */
- $result = @mysql_query($query, $this->_db);
- if (!$result) {
- Horde::logMessage('Error garbage collecting old sessions: ' . mysql_error($this->_db), 'ERR');
- return false;
- }
-
- return @mysql_affected_rows($this->_db);
- }
-
- /**
- * Get a list of the valid session identifiers.
- *
- * @return array A list of valid session identifiers.
- * @throws Horde_Exception
- */
- public function getSessionIDs()
- {
- /* Make sure we have a valid database connection. */
- $this->open();
-
- $query = sprintf('SELECT session_id FROM %s' .
- ' WHERE session_lastmodified >= %s',
- $this->_params['table'],
- time() - ini_get('session.gc_maxlifetime'));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Mysql::getSessionIDs(): query = "%s"', $query), 'DEBUG');
-
- $result = @mysql_query($query, $this->_db);
- if (!$result) {
- throw new Horde_Exception('Error getting session IDs: ' . mysql_error($this->_db));
- }
-
- $sessions = array();
-
- while ($row = mysql_fetch_row($result)) {
- $sessions[] = $row[0];
- }
-
- return $sessions;
- }
-
- /**
- * Escape a mysql string.
- *
- * @param string $value The string to quote.
- *
- * @return string The quoted string.
- */
- protected function _quote($value)
- {
- switch (strtolower(gettype($value))) {
- case 'null':
- return 'NULL';
-
- case 'integer':
- return $value;
-
- case 'string':
- default:
- return "'" . @mysql_real_escape_string($value, $this->_db) . "'";
- }
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Horde_SessionHandler:: implementation for PHP's built-in session handler.
- *
- * Required parameters:<pre>
- * None.</pre>
- *
- * Optional parameters:<pre>
- * None.</pre>
- *
- * Copyright 2005-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Matt Selsky <selsky@columbia.edu>
- * @package Horde_SessionHandler
- */
-class Horde_SessionHandler_None extends Horde_SessionHandler
-{
- /**
- * Read the data for a particular session identifier from the backend.
- *
- * @param string $id The session identifier.
- *
- * @return string The session data.
- */
- protected function _read($id)
- {
- $file = session_save_path() . DIRECTORY_SEPARATOR . 'sess_' . $id;
- $session_data = @file_get_contents($file);
- if ($session_data === false) {
- Horde::logMessage('Unable to read file: ' . $file, 'ERR');
- $session_data = '';
- }
-
- return $session_data;
- }
-
- /**
- * Get a list of the valid session identifiers.
- *
- * @return array A list of valid session identifiers.
- */
- public function getSessionIDs()
- {
- $sessions = array();
-
- $path = session_save_path();
- $d = @dir(empty($path) ? Horde_Util::getTempDir() : $path);
- if (!$d) {
- return $sessions;
- }
-
- while (($entry = $d->read()) !== false) {
- /* Make sure we're dealing with files that start with
- * sess_. */
- if (is_file($d->path . DIRECTORY_SEPARATOR . $entry) &&
- !strncmp($entry, 'sess_', strlen('sess_'))) {
- $sessions[] = substr($entry, strlen('sess_'));
- }
- }
-
- return $sessions;
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Horde_SessionHandler:: implementation for Oracle 8i (native).
- *
- * Required parameters:<pre>
- * 'hostspec' - (string) The hostname of the database server.
- * 'username' - (string) The username with which to connect to the database.
- * 'password' - (string) The password associated with 'username'.
- * 'database' - (string) The name of the database.
- * 'table' - (string) The name of the sessiondata table in 'database'.
- * </pre>
- *
- * Required for some configurations:<pre>
- * 'port' - (integer) The port on which to connect to the database.
- * </pre>
- *
- * Optional parameters:<pre>
- * 'persistent' - (boolean) Use persistent DB connections?
- * </pre>
-
- * The table structure can be found in:
- * horde/scripts/sql/horde_sessionhandler.oci8.sql.
- *
- * Copyright 2003-2009 Liam Hoekenga <liamr@umich.edu>
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Liam Hoekenga <liamr@umich.edu>
- * @package Horde_SessionHandler
- */
-class Horde_SessionHandler_Oci8 extends Horde_SessionHandler
-{
- /**
- * Handle for the current database connection.
- *
- * @var resource
- */
- protected $_db;
-
- /**
- * Attempts to open a connection to the SQL server.
- *
- * @param string $save_path The path to the session object.
- * @param string $session_name The name of the session.
- *
- * @throws Horde_Exception
- */
- protected function _open($save_path = false, $session_name = false)
- {
- Horde::assertDriverConfig($this->_params, 'sessionhandler',
- array('hostspec', 'username', 'password'),
- 'session handler Oracle');
-
- if (!isset($this->_params['table'])) {
- $this->_params['table'] = 'horde_sessionhandler';
- }
-
- if (function_exists('oci_connect')) {
- $connect = empty($this->_params['persistent'])
- ? 'oci_connect'
- : 'oci_pconnect';
- } else {
- $connect = empty($this->_params['persistent'])
- ? 'OCILogon'
- : 'OCIPLogon';
- }
-
- if (!is_resource($this->_db = @$connect($this->_params['username'],
- $this->_params['password'],
- $this->_params['hostspec']))) {
- throw new Horde_Exception('Could not connect to database for SQL Horde_SessionHandler.');
- }
- }
-
- /**
- * Close the backend.
- *
- * @throws Horde_Exception
- */
- protected function _close()
- {
- if (!OCILogOff($this->_db)) {
- throw new Horde_Exception('Could not disconnect from databse.');
- }
- }
-
- /**
- * Read the data for a particular session identifier from the backend.
- *
- * @param string $id The session identifier.
- *
- * @return string The session data.
- */
- protected function _read($id)
- {
- $select_query = sprintf('SELECT session_data FROM %s WHERE session_id = %s FOR UPDATE',
- $this->_params['table'], $this->_quote($id));
-
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Oci8::_read(): query = "%s"', $select_query), 'DEBUG');
-
- $select_statement = OCIParse($this->_db, $select_query);
- OCIExecute($select_statement, OCI_DEFAULT);
- if (OCIFetchInto($select_statement, $result)) {
- $value = $result[0]->load();
- } else {
- $value = '';
- }
-
- OCIFreeStatement($select_statement);
-
- return $value;
- }
-
- /**
- * Write session data to the backend.
- *
- * @param string $id The session identifier.
- * @param string $session_data The session data.
- *
- * @return boolean True on success, false otherwise.
- */
- protected function _write($id, $session_data)
- {
- $select_query = sprintf('SELECT session_data FROM %s WHERE session_id = %s FOR UPDATE',
- $this->_params['table'], $this->_quote($id));
-
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Oci8::_write(): query = "%s"', $select_query), 'DEBUG');
-
- $select_statement = OCIParse($this->_db, $select_query);
- OCIExecute($select_statement, OCI_DEFAULT);
- if (OCIFetchInto($select_statement, $result)) {
- /* Discard the existing LOB contents. */
- if (!$result[0]->truncate()) {
- OCIRollback($this->_db);
- return false;
- }
-
- /* Save the session data. */
- if ($result[0]->save($session_data)) {
- OCICommit($this->_db);
- OCIFreeStatement($select_statement);
- } else {
- OCIRollback($this->_db);
- return false;
- }
- } else {
- $insert_query = sprintf('INSERT INTO %s (session_id, session_lastmodified, session_data) VALUES (%s, %s, EMPTY_BLOB()) RETURNING session_data INTO :blob',
- $this->_params['table'],
- $this->_quote($id),
- $this->_quote(time()));
-
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Oci8::_read(): query = "%s"', $insert_query), 'DEBUG');
-
- $insert_statement = OCIParse($this->_db, $insert_query);
- $lob = OCINewDescriptor($this->_db);
- OCIBindByName($insert_statement, ':blob', $lob, -1, SQLT_BLOB);
- OCIExecute($insert_statement, OCI_DEFAULT);
- if (!$lob->save($session_data)) {
- OCIRollback($this->_db);
- return false;
- }
- OCICommit($this->_db);
- OCIFreeStatement($insert_statement);
- }
-
- return true;
- }
-
- /**
- * Destroy the data for a particular session identifier in the backend.
- *
- * @param string $id The session identifier.
- *
- * @return boolean True on success, false otherwise.
- */
- public function destroy($id)
- {
- /* Build the SQL query. */
- $query = sprintf('DELETE FROM %s WHERE session_id = %s',
- $this->_params['table'], $this->_quote($id));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Oci8::destroy(): query = "%s"', $query), 'DEBUG');
-
- /* Execute the query. */
- $statement = OCIParse($this->_db, $query);
- $result = OCIExecute($statement);
- if (!$result) {
- OCIFreeStatement($statement);
- Horde::logMessage('Failed to delete session (id = ' . $id . ')', 'ERR');
- return false;
- }
-
- OCIFreeStatement($statement);
-
- return true;
- }
-
- /**
- * Garbage collect stale sessions from the backend.
- *
- * @param integer $maxlifetime The maximum age of a session.
- *
- * @return boolean True on success, false otherwise.
- */
- public function gc($maxlifetime = 1)
- {
- /* Build the SQL query. */
- $query = sprintf('DELETE FROM %s WHERE session_lastmodified < %s',
- $this->_params['table'], $this->_quote(time() - $maxlifetime));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Oci8::gc(): query = "%s"', $query), 'DEBUG');
-
- /* Execute the query. */
- $statement = OCIParse($this->_db, $query);
- $result = OCIExecute($statement);
- if (!$result) {
- OCIFreeStatement($statement);
- Horde::logMessage('Error garbage collecting old sessions', 'ERR');
- return false;
- }
-
- OCIFreeStatement($statement);
-
- return true;
- }
-
- /**
- * Get a list of the valid session identifiers.
- *
- * @return array A list of valid session identifiers.
- * @throws Horde_Exception
- */
- public function getSessionIDs()
- {
- /* Make sure we have a valid database connection. */
- $this->open();
-
- /* Session timeout, don't rely on garbage collection */
- $query = sprintf('SELECT session_id FROM %s ' .
- 'WHERE session_lastmodified >= %s',
- $this->_params['table'],
- time() - ini_get('session.gc_maxlifetime'));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Oci8::getSessionIDs(): query = "%s"', $query), 'DEBUG');
-
- /* Execute query */
- $statement = OCIParse($this->_db, $query);
- OCIExecute($statement);
-
- $sessions = array();
- while (OCIFetchInto($statement, $row)) {
- $sessions[] = $row[0];
- }
-
- OCIFreeStatement($statement);
-
- return $sessions;
- }
-
- /**
- * Escape a string for insertion. Stolen from PEAR::DB.
- *
- * @param string $value The string to quote.
- *
- * @return string The quoted string.
- */
- protected function _quote($value)
- {
- return is_null($value)
- ? 'NULL'
- : "'" . str_replace("'", "''", $value) . "'";
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Horde_SessionHandler implementation for PostgreSQL (native).
- *
- * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * Required parameters:<pre>
- * 'database' - (string) The name of the database.
- * 'password' - (string) The password associated with 'username'.
- * 'protocol' - (string) The communication protocol ('tcp', 'unix').
- * 'username' - (string) The username with which to connect to the database.
- *
- * Required for some configurations (i.e. 'protocol' = 'tcp'):<pre>
- * 'hostspec' - (string) The hostname of the database server.
- * 'port' - (integer) The port on which to connect to the database.
- * </pre>
- *
- * Optional parameters:<pre>
- * 'persistent' - (boolean) Use persistent DB connections?
- * Default: NO
- * 'table' - (string) The name of the sessiondata table in 'database'.
- * Default: 'horde_sessionhandler'</pre>
- * </pre>
-
- * The table structure can be found in:
- * horde/scripts/sql/horde_sessionhandler.pgsql.sql.
- *
- * Contributors:<pre>
- * Jason Carlson Return an empty string on failed reads
- * pat@pcprogrammer.com Perform update in a single transaction
- * Jonathan Crompton Lock row for life of session</pre>
- *
- * @author Jon Parise <jon@csh.rit.edu>
- * @package Horde_SessionHandler
- */
-class Horde_SessionHandler_Pgsql extends Horde_SessionHandler
-{
- /**
- * Handle for the current database connection.
- *
- * @var resource
- */
- protected $_db;
-
- /**
- * Attempts to open a connection to the SQL server.
- *
- * @param string $save_path The path to the session object.
- * @param string $session_name The name of the session.
- *
- * @throws Horde_Exception
- */
- protected function _open($save_path = null, $session_name = null)
- {
- Horde::assertDriverConfig($this->_params, 'sessionhandler',
- array('hostspec', 'username', 'database', 'password'),
- 'session handler pgsql');
-
- if (empty($this->_params['table'])) {
- $this->_params['table'] = 'horde_sessionhandler';
- }
-
- $connect = empty($this->_params['persistent']) ?
- 'pg_connect' :'pg_pconnect';
-
- $paramstr = '';
- if (isset($this->_params['protocol']) &&
- $this->_params['protocol'] == 'tcp') {
- $paramstr .= ' host=' . $this->_params['hostspec'];
- if (isset($this->_params['port'])) {
- $paramstr .= ' port=' . $this->_params['port'];
- }
- }
- $paramstr .= ' dbname=' . $this->_params['database'] .
- ' user=' . $this->_params['username'] .
- ' password=' . $this->_params['password'];
-
- if (!$this->_db = @$connect($paramstr)) {
- throw new Horde_Exception(sprintf('Could not connect to database %s for SQL Horde_SessionHandler.', $this->_params['database']));
- }
- }
-
- /**
- * Close the backend.
- *
- * @throws Horde_Exception
- */
- protected function _close()
- {
- /* Disconnect from database. */
- if (!@pg_close($this->_db)) {
- throw new Horde_Exception('Cound not disconnect from database.');
- }
- }
-
- /**
- * Read the data for a particular session identifier from the backend.
- *
- * @param string $id The session identifier.
- *
- * @return string The session data.
- */
- protected function _read($id)
- {
- @pg_query($this->_db, 'BEGIN;');
-
- $query = sprintf('SELECT session_data FROM %s WHERE session_id = %s ' .
- 'FOR UPDATE;',
- $this->_params['table'],
- $this->_quote($id));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Pgsql::' . '_read(): query = "%s"', $query), 'DEBUG');
-
- $result = @pg_query($this->_db, $query);
- $data = pg_fetch_result($result, 0, 'session_data');
- pg_free_result($result);
-
- return pack('H*', $data);
- }
-
- /**
- * Write session data to the backend.
- *
- * @param string $id The session identifier.
- * @param string $session_data The session data.
- *
- * @return boolean True on success, false otherwise.
- */
- protected function _write($id, $session_data)
- {
- $query = sprintf('SELECT session_data FROM %s WHERE session_id = %s ' .
- 'FOR UPDATE',
- $this->_params['table'],
- $this->_quote($id));
- $result = @pg_query($this->_db, $query);
- $rows = pg_num_rows($result);
- pg_free_result($result);
-
- if ($rows == 0) {
- $query = sprintf('INSERT INTO %s (session_id, ' .
- 'session_lastmodified, session_data) ' .
- 'VALUES (%s, %s, %s);',
- $this->_params['table'],
- $this->_quote($id),
- time(),
- $this->_quote(bin2hex($session_data)));
- } else {
- $query = sprintf('UPDATE %s SET session_lastmodified = %s, ' .
- 'session_data = %s WHERE session_id = %s;',
- $this->_params['table'],
- time(),
- $this->_quote(bin2hex($session_data)),
- $this->_quote($id));
- }
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Pgsql::' . '_write(): query = "%s"', $query), 'DEBUG');
-
- $result = @pg_query($this->_db, $query);
- $rows = pg_affected_rows($result);
- pg_free_result($result);
-
- @pg_query($this->_db, 'COMMIT;');
-
- if ($rows != 1) {
- Horde::logMessage('Error writing session data', 'ERR');
- return false;
- }
-
- return true;
- }
-
- /**
- * Destroy the data for a particular session identifier in the backend.
- *
- * @param string $id The session identifier.
- *
- * @return boolean True on success, false otherwise.
- */
- public function destroy($id)
- {
- /* Build the SQL query. */
- $query = sprintf('DELETE FROM %s WHERE session_id = %s;',
- $this->_params['table'], $this->_quote($id));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Pgsql::' . 'destroy(): query = "%s"', $query), 'DEBUG');
-
- /* Execute the query. */
- $result = @pg_query($this->_db, $query);
-
- @pg_query($this->_db, 'COMMIT;');
-
- if (!$result) {
- pg_free_result($result);
- Horde::logMessage('Failed to delete session (id = ' . $id . ')', 'ERR');
- return false;
- }
-
- pg_free_result($result);
- return true;
- }
-
- /**
- * Garbage collect stale sessions from the backend.
- *
- * @param integer $maxlifetime The maximum age of a session.
- *
- * @return boolean True on success, false otherwise.
- */
- public function gc($maxlifetime = 300)
- {
- /* Build the SQL query. */
- $query = sprintf('DELETE FROM %s WHERE session_lastmodified < %s',
- $this->_params['table'],
- $this->_quote(time() - $maxlifetime));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Pgsql::' . 'gc(): query = "%s"', $query), 'DEBUG');
-
- /* Execute the query. */
- $result = @pg_query($this->_db, $query);
- if (!$result) {
- Horde::logMessage('Error garbage collecting old sessions', 'ERR');
- }
-
- pg_free_result($result);
-
- return $result;
- }
-
- /**
- * Get a list of the valid session identifiers.
- *
- * @return array A list of valid session identifiers.
- * @throws Horde_Exception
- */
- public function getSessionIDs()
- {
- /* Make sure we have a valid database connection. */
- $this->open();
-
- /* Build the SQL query. */
- $query = sprintf('SELECT session_id FROM %s ' .
- 'WHERE session_lastmodified >= %s',
- $this->_params['table'],
- time() - ini_get('session.gc_maxlifetime'));
-
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Pgsql::' . 'getSessionIDs(): query = "%s"', $query), 'DEBUG');
-
- /* Execute the query. */
- $result = @pg_query($this->_db, $query);
- if (!$result) {
- pg_free_result($result);
- throw new Horde_Exception('Error getting session IDs');
- }
-
- $sessions = array();
- while ($row = pg_fetch_row($result)) {
- $sessions[] = $row[0];
- }
-
- pg_free_result($result);
-
- return $sessions;
- }
-
- /**
- * Escape a string for insertion into the database.
- *
- * @param string $value The string to quote.
- *
- * @return string The quoted string.
- */
- protected function _quote($value)
- {
- return "'" . addslashes($value) . "'";
- }
-
-}
<?php
/**
- * Horde_SessionHandler implementation for PHP's PEAR database abstraction
- * layer.
+ * SessionHandler implementation for SQL databases.
*
* The table structure can be found in:
* horde/scripts/sql/horde_sessionhandler.sql.
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
- * @author Mike Cochrane <mike@graftonhall.co.nz>
- * @package Horde_SessionHandler
+ * @author Mike Cochrane <mike@graftonhall.co.nz>
+ * @category Horde
+ * @package SessionHandler
*/
-class Horde_SessionHandler_Sql extends Horde_SessionHandler
+class Horde_SessionHandler_Sql extends Horde_SessionHandler_Driver
{
/**
* Handle for the current database connection.
*
- * @var DB
+ * @var Horde_Db_Adapter_Base
*/
protected $_db;
/**
- * Handle for the current database connection, used for writing. Defaults
- * to the same handle as $_db if a separate write database is not required.
- *
- * @var DB
- */
- protected $_write_db;
-
- /**
* Constructor.
*
* @param array $params Parameters:
* <pre>
- * 'db' - (DB) [REQUIRED] The DB instance.
- * 'persistent' - (boolean) Use persistent DB connections?
- * DEFAULT: false
- * 'table' - (string) The name of the tokens table in 'database'.
- * DEFAULT: 'horde_tokens'
- * 'write_db' - (DB) The write DB instance.
+ * 'db' - (Horde_Db_Adapter_Base) [REQUIRED] The DB instance.
+ * 'table' - (string) The name of the sessions table.
+ * DEFAULT: 'horde_sessionhandler'
* </pre>
*
- * @throws Horde_Exception
+ * @throws InvalidArgumentException
*/
- public function __construct($params = array())
+ public function __construct(array $params = array())
{
if (!isset($params['db'])) {
- throw new Horde_Exception('Missing db parameter.');
+ throw new InvalidArgumentException('Missing db parameter.');
}
$this->_db = $params['db'];
+ unset($params['db']);
- $this->_write_db = isset($params['write_db'])
- ? $params['write_db']
- : $this->_db;
-
- if (isset($params['write_db'])) {
- $this->_write_db = $params['write_db'];
- }
-
- unset($params['db'], $params['write_db']);
-
- $params = array_merge(array(
- 'persistent' => false,
+ parent::__construct(array_merge(array(
'table' => 'horde_sessionhandler'
- ), $params);
-
- parent::__construct($params);
+ ), $params));
}
/**
* Close the backend.
*
- * @throws Horde_Exception
+ * @throws Horde_SessionHandler_Exception
*/
protected function _close()
{
/* Close any open transactions. */
- $this->_db->commit();
- $this->_db->autoCommit(true);
- @$this->_db->disconnect();
-
- if ($this->_db != $this->_write_db) {
- $this->_write_db->commit();
- $this->_write_db->autoCommit(true);
- @$this->_write_db->disconnect();
+ try {
+ $this->_db->commitDbTransaction();
+ } catch (Horde_Db_Exception $e) {
+ throw new Horde_SessionHandler_Exception($e);
}
}
protected function _read($id)
{
/* Begin a transaction. */
- $result = $this->_write_db->autocommit(false);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return '';
- }
+ // TODO: Rowlocking in Mysql
+ $this->_db->beginDbTransaction();
- /* Execute the query. */
- $result = Horde_SQL::readBlob($this->_write_db, $this->_params['table'], 'session_data', array('session_id' => $id));
+ /* Build query. */
+ $query = sprintf('SELECT session_data FROM %s WHERE session_id = ?',
+ $this->_params['table']);
+ $values = array($id);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return '';
+ /* Execute the query. */
+ try {
+ return $this->_db->selectValue($query, $values);
+ } catch (Horde_Db_Exception $e) {
+ return false;
}
-
- return $result;
}
/**
$this->_params['table']);
$values = array($id);
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Sql::write(): query = "%s"', $query), 'DEBUG');
-
/* Execute the query. */
- $result = $this->_write_db->getOne($query, $values);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return false;
- }
-
- if ($result) {
- $result = Horde_SQL::updateBlob($this->_write_db, $this->_params['table'], 'session_data',
- $session_data, array('session_id' => $id),
- array('session_lastmodified' => time()));
- } else {
- $result = Horde_SQL::insertBlob($this->_write_db, $this->_params['table'], 'session_data',
- $session_data, array('session_id' => $id,
- 'session_lastmodified' => time()));
- }
-
- if (is_a($result, 'PEAR_Error')) {
- $this->_write_db->rollback();
- $this->_write_db->autoCommit(true);
- Horde::logMessage($result, 'ERR');
+ try {
+ $result = $this->_db->selectValue($query, $values);
+ } catch (Horde_Db_Exception $e) {
return false;
}
- $result = $this->_write_db->commit();
- if (is_a($result, 'PEAR_Error')) {
- $this->_write_db->autoCommit(true);
- Horde::logMessage($result, 'ERR');
+ /* Build the replace SQL query. */
+ $query = sprintf('REPLACE INTO %s ' .
+ '(session_id, session_data, session_lastmodified) ' .
+ 'VALUES (?, ?, ?)',
+ $this->_params['table']);
+ $values = array(
+ $id,
+ $session_data,
+ time()
+ );
+
+ /* Execute the replace query. */
+ try {
+ $this->_db->update($query, $values);
+ $this->_db->commitDbTransaction();
+ } catch (Horde_Db_Exception $e) {
+ $this->_db->rollbackDbTransaction();
return false;
}
- $this->_write_db->autoCommit(true);
return true;
}
$this->_params['table']);
$values = array($id);
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Sql::destroy(): query = "%s"', $query), 'DEBUG');
-
/* Execute the query. */
- $result = $this->_write_db->query($query, $values);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return false;
- }
-
- $result = $this->_write_db->commit();
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
+ try {
+ $this->_db->delete($query, $values);
+ $this->_db->commitDbTransaction();
+ } catch (Horde_Db_Exception $e) {
return false;
}
$this->_params['table']);
$values = array(time() - $maxlifetime);
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Sql::gc(): query = "%s"', $query), 'DEBUG');
-
/* Execute the query. */
- $result = $this->_write_db->query($query, $values);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
+ try {
+ $this->_db->delete($query, $values);
+ } catch (Horde_Db_Exception $e) {
return false;
}
* Get a list of the valid session identifiers.
*
* @return array A list of valid session identifiers.
- * @throws Horde_Exception
*/
public function getSessionIDs()
{
$this->open();
/* Build the SQL query. */
- $query = 'SELECT session_id FROM ' . $this->_params['table'] .
- ' WHERE session_lastmodified >= ?';
+ $query = sprintf('SELECT session_id FROM %s' .
+ ' WHERE session_lastmodified >= ?',
+ $this->_params['table']);
$values = array(time() - ini_get('session.gc_maxlifetime'));
- /* Log the query at a DEBUG log level. */
- Horde::logMessage(sprintf('SQL Query by Horde_SessionHandler_Sql::getSessionIDs(): query = "%s"', $query), 'DEBUG');
-
/* Execute the query. */
- $result = $this->_db->getCol($query, 0, $values);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return false;
+ try {
+ return $this->_db->selectValues($query, $values);
+ } catch (Horde_Db_Exception $e) {
+ return array();
}
-
- return $result;
}
}
--- /dev/null
+<?php
+/**
+ * Horde_SessionHandler_Stack:: is an implementation that will loop through
+ * a given list of Horde_SessionHandler_Drivers to return the session
+ * information. This driver allows for use of caching backends on top of
+ * persistent backends.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package SessionHandler
+ */
+class Horde_SessionHandler_Stack extends Horde_SessionHandler_Driver
+{
+ /**
+ * Stack of sessionhandlers.
+ *
+ * @var string
+ */
+ protected $_stack = array();
+
+ /**
+ * Constructor.
+ *
+ * @param array $params Parameters:
+ * <pre>
+ * 'stack' - (array) [REQUIRED] A list of sessionhandlers to loop
+ * through, in order of priority. The last entry is considered
+ * the "master" server.
+ * Each value should contain an array with two keys: 'driver', a
+ * string value with the SessionHandler driver to use, and
+ * 'params', containing any parameters needed by this driver.
+ * </pre>
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $params = array())
+ {
+ if (!isset($params['stack'])) {
+ throw new InvalidArgumentException('Missing stack parameter.');
+ }
+
+ foreach ($params['stack'] as $val) {
+ $this->_stack[] = Horde_SessionHandler::factory($val['driver'], $val['params']);
+ }
+
+ unset($params['stack']);
+
+ parent::__construct($params);
+ }
+
+ /**
+ * Open the backend.
+ *
+ * @param string $save_path The path to the session object.
+ * @param string $session_name The name of the session.
+ *
+ * @throws Horde_SessionHandler_Exception
+ */
+ protected function _open($save_path = null, $session_name = null)
+ {
+ foreach ($this->_stack as $val) {
+ $val->open($save_path, $session_name);
+ }
+ }
+
+ /**
+ * Close the backend.
+ *
+ * @throws Horde_SessionHandler_Exception
+ */
+ protected function _close()
+ {
+ foreach ($this->_stack as $val) {
+ $val->close();
+ }
+ }
+
+ /**
+ * Read the data for a particular session identifier from the backend.
+ *
+ * @param string $id The session identifier.
+ *
+ * @return string The session data.
+ */
+ protected function _read($id)
+ {
+ foreach ($this->_stack as $val) {
+ $result = $val->read($id);
+ if ($result === false) {
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Write session data to the backend.
+ *
+ * @param string $id The session identifier.
+ * @param string $session_data The session data.
+ *
+ * @return boolean True on success, false otherwise.
+ */
+ protected function _write($id, $session_data)
+ {
+ /* Do writes in *reverse* order - it is OK if a write to one of the
+ * non-masters backend fails. */
+ $master = true;
+
+ foreach (array_reverse($this->_stack) as $val) {
+ $result = $val->write($id, $session_data);
+ if ($result === false) {
+ if ($master) {
+ return false;
+ }
+ /* Attempt to invalidate cache if write failed. */
+ $val->destroy($id);
+ }
+ $master = false;
+ }
+
+ 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)
+ {
+ foreach ($this->_stack as $val) {
+ $result = $val->destroy($id);
+ if ($result === false) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 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)
+ {
+ /* Only report GC results from master. */
+ foreach ($this->_stack as $val) {
+ $result = $val->gc($maxlifetime);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get a list of the valid session identifiers.
+ *
+ * @return array A list of valid session identifiers.
+ * @throws Horde_SessionHandler_Exception
+ */
+ public function getSessionIDs()
+ {
+ /* Grab session ID list from the master. */
+ $ob = end($this->_stack);
+ return $ob->getSessionIDs();
+ }
+
+}
<api>beta</api>
</stability>
<license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>* Removed Horde-specific session counting script.
+ <notes>* Abstracted memcache persistent-backend code into 'Stack' driver.
+ * Renamed 'none' driver to 'Builtin'.
+ * Now throws Horde_SessionHandler_Exception.
+ * Split driver code into abstract class.
+ * Use horde/Db to access SQL databases.
+ * Do not rely on Horde::logMessage().
+ * Removed Horde-specific session counting script.
* Initial Horde 4 package.
</notes>
<contents>
<dir name="lib">
<dir name="Horde">
<dir name="SessionHandler">
+ <file name="Builtin.php" role="php" />
+ <file name="Driver.php" role="php" />
+ <file name="Exception.php" role="php" />
+ <file name="External.php" role="php" />
<file name="Ldap.php" role="php" />
<file name="Memcache.php" role="php" />
- <file name="Mysql.php" role="php" />
<file name="None.php" role="php" />
- <file name="Oci8.php" role="php" />
- <file name="Pgsql.php" role="php" />
<file name="Sql.php" role="php" />
+ <file name="Stack.php" role="php" />
</dir> <!-- /lib/Horde/SessionHandler -->
<file name="SessionHandler.php" role="php" />
</dir> <!-- /lib/Horde -->
<min>5.2.0</min>
</php>
<pearinstaller>
- <min>1.5.0</min>
+ <min>1.7.0</min>
</pearinstaller>
+ <package>
+ <name>Exception</name>
+ <channel>pear.horde.org</channel>
+ </package>
</required>
<optional>
<package>
- <name>Memcache</name>
+ <name>Auth</name>
<channel>pear.horde.org</channel>
</package>
<package>
- <name>SQL</name>
+ <name>Db</name>
+ <channel>pear.horde.org</channel>
+ </package>
+ <package>
+ <name>Log</name>
+ <channel>pear.horde.org</channel>
+ </package>
+ <package>
+ <name>Memcache</name>
<channel>pear.horde.org</channel>
</package>
</optional>
</dependencies>
<phprelease>
<filelist>
+ <install name="lib/Horde/SessionHandler/Builtin.php" as="Horde/SessionHandler/Builtin.php" />
+ <install name="lib/Horde/SessionHandler/Driver.php" as="Horde/SessionHandler/Driver.php" />
+ <install name="lib/Horde/SessionHandler/Exception.php" as="Horde/SessionHandler/Exception.php" />
+ <install name="lib/Horde/SessionHandler/External.php" as="Horde/SessionHandler/External.php" />
<install name="lib/Horde/SessionHandler/Ldap.php" as="Horde/SessionHandler/Ldap.php" />
<install name="lib/Horde/SessionHandler/Memcache.php" as="Horde/SessionHandler/Memcache.php" />
- <install name="lib/Horde/SessionHandler/Mysql.php" as="Horde/SessionHandler/Mysql.php" />
<install name="lib/Horde/SessionHandler/None.php" as="Horde/SessionHandler/None.php" />
- <install name="lib/Horde/SessionHandler/Oci8.php" as="Horde/SessionHandler/Pgsql.php" />
<install name="lib/Horde/SessionHandler/Sql.php" as="Horde/SessionHandler/Sql.php" />
+ <install name="lib/Horde/SessionHandler/Stack.php" as="Horde/SessionHandler/Stack.php" />
<install name="lib/Horde/SessionHandler.php" as="Horde/SessionHandler.php" />
</filelist>
</phprelease>
echo '<h1 class="header">' . _("Current Sessions");
try {
- if (!isset($registry->sessionHandler)) {
- throw new Horde_Exception(_("Session handler does not support listing active sessions."));
- }
-
$session_info = $registry->sessionHandler->getSessionsInfo();
echo ' (' . count($session_info) . ')</h1>' .
<case name="kolab" desc="Kolab"/>
<case name="ldap" desc="LDAP">
<configsection name="params">
- <configstring name="hostspec" desc="The hostname of the LDAP server">
+ <configstring name="hostspec" desc="the hostname of the ldap server">
localhost</configstring>
- <configstring name="basedn" desc="The base DN for the LDAP server"/>
- <configstring name="binddn" required="false" desc="The DN used to bind
- to the LDAP server"/>
- <configstring name="password" required="false" desc="The password used
- to bind to the LDAP server"/>
- <configenum name="version" desc="LDAP protocol version">3
+ <configstring name="basedn" desc="the base dn for the ldap server"/>
+ <configstring name="binddn" required="false" desc="the dn used to bind
+ to the ldap server"/>
+ <configstring name="password" required="false" desc="the password used
+ to bind to the ldap server"/>
+ <configenum name="version" desc="ldap protocol version">3
<values>
- <value desc="LDAPv2 (deprecated)">2</value>
- <value desc="LDAPv3">3</value>
+ <value desc="ldapv2 (deprecated)">2</value>
+ <value desc="ldapv3">3</value>
</values>
</configenum>
<configboolean name="tls" desc="Enable TLS?">false</configboolean>
<configsection name="sessionhandler">
<configheader>Custom Session Handler Settings</configheader>
<configswitch name="type" desc="What sessionhandler driver should we
- use?">none
- <case name="none" desc="Use the default PHP session handler (file-based by
+ use?">Builtin
+ <case name="Builtin" desc="Use the default PHP session handler (file-based by
default)">
<configdescription>
If you have configured a custom session extension in php.ini, such as
settings settings will be deferred to.
</configdescription>
</case>
- <case name="external" desc="Use your own custom session handler">
+ <case name="External" desc="Use your own custom session handler">
<configsection name="params">
<configstring name="open" desc="Your open() function"/>
<configstring name="close" desc="Your close() function"/>
<configstring name="gc" desc="Your gc() function"/>
</configsection>
</case>
-
- <case name="mysql" desc="MySQL based sessions">
- <configsection name="params">
- <configboolean name="persistent" desc="Request persistent
- connections?">false</configboolean>
- <configboolean name="rowlocking" desc="Should we use row-level locking
- and transactions? This is strongly recommended, but requires a table
- type that is transaction-safe and supports row-level locking, like
- InnoDB. If you don't have such a table type, disable this setting and we
- will use table-level locking and no locking
- instead.">true</configboolean>
- <configswitch name="protocol" desc="What protocol will we use to connect
- to the database?">unix
- <case name="unix" desc="UNIX Sockets">
- <configstring name="socket" required="false" desc="Location of UNIX
- socket"></configstring>
- </case>
- <case name="tcp" desc="TCP/IP">
- <configinteger name="port" required="false" desc="Port the DB is
- running on, if non-standard">3306</configinteger>
- </case>
- </configswitch>
- <configstring name="hostspec" desc="What hostname is the database server
- running on, or what is the name of the system DSN to use?">
- localhost</configstring>
- <configstring name="username" desc="What username do we authenticate to
- the database server as?">horde</configstring>
- <configstring name="password" required="false" desc="What password do we
- authenticate to the database server with?"/>
- <configstring name="database" desc="What database name/tablespace are we
- using?">horde</configstring>
- <configstring name="table" required="false" desc="The name of the
- session table in the database [horde_sessionhandler]"/>
- </configsection>
- </case>
- <case name="oci8" desc="Oracle based sessions">
- <configsection name="params">
- <configboolean name="persistent" desc="Request persistent connections?">
- false</configboolean>
- <configstring name="hostspec" desc="Database name or Easy Connect
- parameter">horde</configstring>
- <configstring name="username" desc="What username do we authenticate to
- the database server as?">horde</configstring>
- <configstring name="password" required="false" desc="What password do we
- authenticate to the database server with?"/>
- <configstring name="table" required="false" desc="The name of the session
- table in the database [horde_sessionhandler]"/>
- </configsection>
- </case>
- <case name="pgsql" desc="PostgreSQL based sessions">
- <configsection name="params">
- <configboolean name="persistent" desc="Request persistent connections?">
- false</configboolean>
- <configswitch name="protocol" desc="What protocol will we use to connect
- to the database?">unix
- <case name="unix" desc="UNIX Sockets">
- <configstring name="socket" required="false" desc="Location of UNIX
- socket"></configstring>
- </case>
- <case name="tcp" desc="TCP/IP">
- <configinteger name="port" required="false" desc="Port the DB is
- running on, if non-standard">5432</configinteger>
- </case>
- </configswitch>
- <configstring name="hostspec" desc="What hostname is the database server
- running on, or what is the name of the system DSN to use?">
- localhost</configstring>
- <configstring name="username" desc="What username do we authenticate to
- the database server as?">horde</configstring>
- <configstring name="password" required="false" desc="What password do we
- authenticate to the database server with?"/>
- <configstring name="database" desc="What database name/tablespace are we
- using?">horde</configstring>
- <configstring name="table" required="false" desc="The name of the
- session table in the database [horde_sessionhandler]"/>
- </configsection>
- </case>
- <case name="sql" desc="Use PEAR's DB abstraction layer">
+ <case name="Ldap" desc="LDAP">
<configsection name="params">
- <configboolean name="persistent" desc="Request persistent
- connections?">false</configboolean>
- <configswitch name="protocol" desc="What protocol will we use to connect
- to the database?">unix
- <case name="unix" desc="UNIX Sockets">
- <configstring name="socket" required="false" desc="Location of UNIX
- socket"></configstring>
- </case>
- <case name="tcp" desc="TCP/IP">
- <configinteger name="port" required="false" desc="Port the DB is
- running on, if non-standard">5432</configinteger>
- </case>
- </configswitch>
- <configstring name="hostspec" desc="What hostname is the database server
- running on, or what is the name of the system DSN to use?">
- localhost</configstring>
- <configstring name="username" desc="What username do we authenticate to
- the database server as?">horde</configstring>
- <configstring name="password" required="false" desc="What password do we
- authenticate to the database server with?"/>
- <configstring name="database" desc="What database name/tablespace are we
- using?">horde</configstring>
- <configstring name="table" required="false" desc="The name of the session
- table in the database [horde_sessionhandler]"/>
+ <configstring name="hostspec" descu"LDAP
+ server/host">localhost</configstring>
+ <configinteger name="port" required="false" desc="Port LDAP is running
+ on, if non-standard">389</configinteger>
+ <configstring name="dn" required="false" desc="The DN used to bind
+ to the LDAP server"/>
+ <configstring name="password" required="false" desc="The password used
+ to bind to the LDAP server"/>
+ <configenum name="version" desc="LDAP Protocol Version">3
+ <values>
+ <value desc="LDAPv2 (Deprecated)">2</value>
+ <value desc="LDAPv3">3</value>
+ </values>
+ </configenum>
</configsection>
</case>
- <case name="memcache" desc="Memcache only">
+ <case name="Memcache" desc="Memcache only">
<configsection name="params">
<configswitch name="track" required="false" desc="Keep track of active
session information? Tracking requires a small amount of extra load.">
</configswitch>
</configsection>
</case>
+ <case name="Sql" desc="SQL Database">
+ <configsection name="params">
+ <configsql switchname="driverconfig">
+ <configstring name="table" required="false" desc="The name of the
+ preference table in the database [horde_sessionhandler]"/>
+ </configsql>
+ </configsection>
+ </case>
</configswitch>
<configboolean name="memcache" desc="Use memcache to cache session
information?">false</configboolean>