Add code needed to manually mark session data as dirty
authorMichael M Slusarz <slusarz@curecanti.org>
Thu, 14 Oct 2010 04:31:06 +0000 (22:31 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Fri, 15 Oct 2010 16:13:55 +0000 (10:13 -0600)
Disable by default in Horde for now (will be enabled when all session
access code has been converted to Horde_Session).

framework/Core/lib/Horde/Core/Factory/SessionHandler.php
framework/Core/lib/Horde/Session.php
framework/SessionHandler/lib/Horde/SessionHandler.php

index b24a4ad..c65d48b 100644 (file)
@@ -69,10 +69,9 @@ class Horde_Core_Factory_SessionHandler
         }
 
         $params['logger'] = $logger;
-        $params['modified'] = array(
-            'get' => array($this, 'getModified'),
-            'set' => array($this, 'setModified')
-        );
+        // TODO: Uncomment once all session data is saved through
+        //  Horde_Session.
+        //$params['no_md5'] = true
         $params['parse'] = array($this, 'readSessionData');
 
         $driver = basename(strtolower($driver));
@@ -125,18 +124,4 @@ class Horde_Core_Factory_SessionHandler
         return false;
     }
 
-    /**
-     */
-    public function getModified()
-    {
-        return $GLOBALS['session']['horde:session_mod'];
-    }
-
-    /**
-     */
-    public function setModified($date)
-    {
-        $GLOBALS['session']['horde:session_mod'] = $date;
-    }
-
 }
index c3e3468..0983bc2 100644 (file)
@@ -105,6 +105,20 @@ class Horde_Session implements ArrayAccess
                 /* Is this key serialized? */
                 $_SESSION[self::SERIALIZED] = array();
             }
+
+            /* Determine if we need to force 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. */
+            $curr_time = time();
+            if ($curr_time >= intval($this['horde:session_mod'])) {
+                $this['horde:session_mod'] = $curr_time + (ini_get('session.gc_maxlifetime') / 2);
+                $this->sessionHandler->changed = true;
+            }
         }
     }
 
@@ -334,6 +348,7 @@ class Horde_Session implements ArrayAccess
         }
 
         $_SESSION[$ob->app][$ob->name] = $value;
+        $this->sessionHandler->changed = true;
     }
 
     /**
index 6df6f58..a943715 100644 (file)
@@ -1,7 +1,6 @@
 <?php
 /**
- * Horde_SessionHandler_Base is the abstract class that all drivers inherit
- * from.
+ * This is the abstract class that all drivers inherit from.
  *
  * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
  *
  *
  * @author   Michael Slusarz <slusarz@horde.org>
  * @category Horde
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
  * @package  SessionHandler
  */
 abstract class Horde_SessionHandler
 {
     /**
-     * Hash containing connection parameters.
+     * If true, indicates the session data has changed.
      *
-     * @var array
+     * @var boolean
      */
-    protected $_params = array();
+    public $changed = false;
 
     /**
-     * Initial session data signature.
+     * Has a connection been made to the backend?
      *
-     * @var string
+     * @var boolean
      */
-    protected $_sig;
+    protected $_connected = false;
 
     /**
-     * Force saving the session data?
+     * A logger instance.
      *
-     * @var boolean
+     * @var Horde_Log_Logger
      */
-    protected $_force = false;
+    protected $_logger;
 
     /**
-     * Has a connection been made to the backend?
+     * Hash containing connection parameters.
      *
-     * @var boolean
+     * @var array
      */
-    protected $_connected = false;
+    protected $_params = array();
 
     /**
-     * A logger instance.
+     * Initial session data signature.
      *
-     * @var Horde_Log_Logger
+     * @var string
      */
-    protected $_logger;
+    protected $_sig;
 
     /**
      * Constructor.
      *
      * @param array $params  Parameters:
      * <pre>
-     * 'logger' - (Horde_Log_Logger) A logger instance.
-     *            DEFAULT: No logging
-     * 'modified' - (array) Callbacks used to store the session last modified
-     *              value.  Needs to define two keys: 'get' and 'set'. 'get'
-     *              returns the last modified value, 'set' receives the last
-     *              modified value as the only parameter.
-     *              DEFAULT: Not saved
-     * '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
+     * logger - (Horde_Log_Logger) A logger instance.
+     *          DEFAULT: No logging
+     * no_md5 - (boolean) If true, does not do MD5 signatures of the session
+     *          to determine if the session has changed. If true, calling code
+     *          is responsible for marking $changed as true when the session
+     *          data has changed.
+     *          DEFAULT: false
+     * noset - (boolean) If true, don't set the save handler.
+     *         DEFAULT: false
+     * parse - (callback) A callback function that parses session
+     *         information into an array. Is passed the raw session data
+     *         as the only argument; expects either false or an array of
+     *         session data as a return.
+     *         DEFAULT: No
      * </pre>
      */
     public function __construct(array $params = array())
@@ -81,10 +81,6 @@ abstract class Horde_SessionHandler
 
         $this->_params = $params;
 
-        if (isset($this->_params['modified'])) {
-            register_shutdown_function(array($this, 'shutdown'));
-        }
-
         if (empty($this->_params['noset'])) {
             ini_set('session.save_handler', 'user');
             session_set_save_handler(
@@ -110,27 +106,6 @@ abstract class Horde_SessionHandler
     }
 
     /**
-     * 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 ($curr_time >= intval(call_user_func($this->_params['modified']['get']))) {
-            call_user_func($this->_params['modified']['set'], $curr_time + (ini_get('session.gc_maxlifetime') / 2));
-            $this->_force = true;
-        }
-    }
-
-    /**
      * Open the backend.
      *
      * @param string $save_path     The path to the session object.
@@ -205,7 +180,9 @@ abstract class Horde_SessionHandler
     public function read($id)
     {
         $result = $this->_read($id);
-        $this->_sig = md5($result);
+        if (empty($this->_params['no_md5'])) {
+            $this->_sig = md5($result);
+        }
         return $result;
     }
 
@@ -230,14 +207,17 @@ abstract class Horde_SessionHandler
      */
     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;
+        if ($this->changed ||
+            (empty($this->_params['no_md5']) &&
+             ($this->_sig != md5($session_data)))) {
+            return $this->_write($id, $session_data);
         }
 
-        return $this->_write($id, $session_data);
+        if ($this->_logger) {
+            $this->_logger->log('Session data unchanged (id = ' . $id . ')', 'DEBUG');
+        }
+
+        return true;
     }
 
     /**