From 1948e4f501a18c5856cbe45caf09267c0020e036 Mon Sep 17 00:00:00 2001 From: Ben Klang Date: Sun, 3 Oct 2010 14:18:30 -0400 Subject: [PATCH] Rebuild SessionHandler factory --- .../Core/{Binder => Factory}/SessionHandler.php | 30 +- framework/Core/lib/Horde/Registry.php | 3 +- framework/Core/package.xml | 6 +- .../SessionHandler/lib/Horde/SessionHandler.php | 326 ++++++++++++++++++-- .../lib/Horde/SessionHandler/Base.php | 332 --------------------- framework/SessionHandler/package.xml | 30 +- 6 files changed, 349 insertions(+), 378 deletions(-) rename framework/Core/lib/Horde/Core/{Binder => Factory}/SessionHandler.php (77%) delete mode 100644 framework/SessionHandler/lib/Horde/SessionHandler/Base.php diff --git a/framework/Core/lib/Horde/Core/Binder/SessionHandler.php b/framework/Core/lib/Horde/Core/Factory/SessionHandler.php similarity index 77% rename from framework/Core/lib/Horde/Core/Binder/SessionHandler.php rename to framework/Core/lib/Horde/Core/Factory/SessionHandler.php index b4741d42a..79b9b1be7 100644 --- a/framework/Core/lib/Horde/Core/Binder/SessionHandler.php +++ b/framework/Core/lib/Horde/Core/Factory/SessionHandler.php @@ -1,10 +1,26 @@ + * * @category Horde * @package Core */ -class Horde_Core_Binder_SessionHandler implements Horde_Injector_Binder +class Horde_Core_Factory_SessionHandler { + /** + * 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_Driver The newly created concrete + * instance. + * @throws Horde_SessionHandler_Exception + */ public function create(Horde_Injector $injector) { global $conf; @@ -55,12 +71,14 @@ class Horde_Core_Binder_SessionHandler implements Horde_Injector_Binder $params['logger'] = $logger; $params['parse'] = array($this, 'readSessionData'); - return Horde_SessionHandler::factory($driver, $params); - } + $driver = basename(strtolower($driver)); + $class = 'Horde_SessionHandler_' . ucfirst($driver); - public function equals(Horde_Injector_Binder $binder) - { - return false; + if (class_exists($class)) { + return new $class($params); + } + + throw new Horde_SessionHandler_Exception('Driver not found: ' . $driver); } /** diff --git a/framework/Core/lib/Horde/Registry.php b/framework/Core/lib/Horde/Registry.php index a98bd7aac..2a010cff3 100644 --- a/framework/Core/lib/Horde/Registry.php +++ b/framework/Core/lib/Horde/Registry.php @@ -279,7 +279,6 @@ class Horde_Registry 'Horde_Mime_Viewer' => new Horde_Core_Binder_MimeViewer(), 'Horde_Notification' => new Horde_Core_Binder_Notification(), 'Horde_Prefs_Identity' => new Horde_Core_Binder_Identity(), - 'Horde_SessionHandler' => new Horde_Core_Binder_SessionHandler(), 'Horde_Share_Factory' => new Horde_Core_Binder_ShareFactory(), 'Horde_Template' => new Horde_Core_Binder_Template(), 'Horde_Text_Filter' => new Horde_Core_Binder_TextFilter(), @@ -1677,7 +1676,7 @@ class Horde_Registry /* 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'); + $this->sessionHandler = $GLOBALS['injector']->createInstance('Horde_Core_Factory_SessionHandler'); if ($start) { session_start(); diff --git a/framework/Core/package.xml b/framework/Core/package.xml index 0962f58ea..35fd3217b 100644 --- a/framework/Core/package.xml +++ b/framework/Core/package.xml @@ -24,7 +24,7 @@ Application Framework. yes 2010-10-03 - + 0.1.0 0.1.0 @@ -128,7 +128,6 @@ Application Framework. - @@ -169,6 +168,7 @@ Application Framework. + @@ -447,7 +447,6 @@ Application Framework. - @@ -484,6 +483,7 @@ Application Framework. + diff --git a/framework/SessionHandler/lib/Horde/SessionHandler.php b/framework/SessionHandler/lib/Horde/SessionHandler.php index e6e578a41..2a69d8232 100644 --- a/framework/SessionHandler/lib/Horde/SessionHandler.php +++ b/framework/SessionHandler/lib/Horde/SessionHandler.php @@ -1,42 +1,332 @@ * @author Michael Slusarz * @category Horde * @package SessionHandler */ -class Horde_SessionHandler +abstract class Horde_SessionHandler { /** - * Attempts to return a concrete instance based on $driver. + * Hash containing connection parameters. * - * @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. + * @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: + *
+     * 'logger' - (Horde_Log_Logger) A logger instance.
+     *            DEFAULT: No logging
+     * '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
+     * 
+ */ + 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. * - * @return Horde_SessionHandler_Driver The newly created concrete - * instance. * @throws Horde_SessionHandler_Exception */ - static public function factory($driver, array $params = array()) + abstract protected function _open($save_path = null, $session_name = null); + + /** + * Close the backend. + * + * @return boolean True on success, false otherwise. + */ + public function close() { - $driver = basename(strtolower($driver)); - $class = __CLASS__ . '_' . ucfirst($driver); + 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 + * 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; + } + + $sessions = $this->getSessionIDs(); + + foreach ($sessions as $id) { + try { + $data = $this->_readOnly($id); + } catch (Horde_SessionHandler_Exception $e) { + continue; + } - if (class_exists($class)) { - return new $class($params); + $data = call_user_func($this->_params['parse'], $data); + if ($data !== false) { + $info[$id] = $data; + } } - throw new Horde_SessionHandler_Exception('Driver not found: ' . $driver); + return $info; } -} +} \ No newline at end of file diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/Base.php b/framework/SessionHandler/lib/Horde/SessionHandler/Base.php deleted file mode 100644 index 10d65fb4d..000000000 --- a/framework/SessionHandler/lib/Horde/SessionHandler/Base.php +++ /dev/null @@ -1,332 +0,0 @@ - - * @category Horde - * @package SessionHandler - */ -abstract class Horde_SessionHandler_Base -{ - /** - * 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: - *
-     * 'logger' - (Horde_Log_Logger) A logger instance.
-     *            DEFAULT: No logging
-     * '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
-     * 
- */ - 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 - * 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; - } - - $sessions = $this->getSessionIDs(); - - foreach ($sessions as $id) { - try { - $data = $this->_readOnly($id); - } catch (Horde_SessionHandler_Exception $e) { - continue; - } - - $data = call_user_func($this->_params['parse'], $data); - if ($data !== false) { - $info[$id] = $data; - } - } - - return $info; - } - -} diff --git a/framework/SessionHandler/package.xml b/framework/SessionHandler/package.xml index cce1f5ec4..d9a789f7b 100644 --- a/framework/SessionHandler/package.xml +++ b/framework/SessionHandler/package.xml @@ -23,8 +23,8 @@ slusarz@horde.org yes - 2010-05-20 - + 2010-10-03 + 0.1.0 0.1.0 @@ -50,17 +50,15 @@ - - - + - - + + @@ -99,10 +97,8 @@ - - @@ -172,17 +168,17 @@ Initial release as a PEAR package beta beta - 2010-05-20 + 2010-10-03 LGPL * 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. +* 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. -- 2.11.0