[Solar-svn] Revision 2983

pmjones at solarphp.com pmjones at solarphp.com
Tue Mar 4 21:20:15 CST 2008


Solar_Session: [ADD] Session object now fully supports save-session-handler adapters.  Includes a native adapter and an SQL adapter.  Thanks, Antti Holvikari, for these additions.


Added: trunk/Solar/Session/Handler/Adapter/Native.php
===================================================================
--- trunk/Solar/Session/Handler/Adapter/Native.php	                        (rev 0)
+++ trunk/Solar/Session/Handler/Adapter/Native.php	2008-03-05 03:20:15 UTC (rev 2983)
@@ -0,0 +1,131 @@
+<?php
+/**
+ * 
+ * Session adapter for native PHP sessions
+ * 
+ * This adapter does **not** set any save-handler or ini-settings.
+ * 
+ * @category Solar
+ * 
+ * @package Solar_Session
+ * 
+ * @author Antti Holvikari <anttih at gmail.com>
+ * 
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * 
+ * @version $Id$
+ * 
+ */
+class Solar_Session_Handler_Adapter_Native extends Solar_Session_Handler_Adapter {
+    
+    /**
+     * 
+     * Sets the session save handler.
+     * 
+     * This doesn't actually do anything, because we're using the native PHP
+     * handler, not the methods in this class.
+     * 
+     * @return void
+     * 
+     */
+    protected function _setSaveHandler()
+    {
+        // do nothing
+    }
+    
+    /**
+     * 
+     * Opens the session handler.
+     * 
+     * Provided only to override abstract method, never actually called.
+     * 
+     * @return bool
+     * 
+     */
+    public function open()
+    {
+        return true;
+    }
+    
+    /**
+     * 
+     * Closes session handler.
+     * 
+     * Provided only to override abstract method, never actually called.
+     * 
+     * @return bool
+     * 
+     */
+    public function close()
+    {
+        return true;
+    }
+    
+    /**
+     * 
+     * Reads session data.
+     * 
+     * Provided only to override abstract method, never actually called.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @return string The serialized session data.
+     * 
+     */
+    public function read($id)
+    {
+        return null;
+    }
+    
+    /**
+     * 
+     * Writes session data.
+     * 
+     * Provided only to override abstract method, never actually called.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @param string $data The serialized session data.
+     * 
+     * @return bool
+     * 
+     */
+    public function write($id, $data)
+    {
+        return true;
+    }
+    
+    /**
+     * 
+     * Destroys session data.
+     * 
+     * Provided only to override abstract method, never actually called.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @return bool
+     * 
+     */
+    public function destroy($id)
+    {
+        return true;
+    }
+    
+    /**
+     * 
+     * Removes old session data (garbage collection).
+     * 
+     * Provided only to override abstract method, never actually called.
+     * 
+     * @param int $lifetime Removes session data not updated since this many
+     * seconds ago.  E.g., a lifetime of 86400 removes all session data not
+     * updated in the past 24 hours.
+     * 
+     * @return bool
+     * 
+     */
+    public function gc($lifetime)
+    {
+        return true;
+    }
+}
\ No newline at end of file

Added: trunk/Solar/Session/Handler/Adapter/Sql.php
===================================================================
--- trunk/Solar/Session/Handler/Adapter/Sql.php	                        (rev 0)
+++ trunk/Solar/Session/Handler/Adapter/Sql.php	2008-03-05 03:20:15 UTC (rev 2983)
@@ -0,0 +1,251 @@
+<?php
+/**
+ * 
+ * Session adapter for SQL based data store.
+ * 
+ * @category Solar
+ * 
+ * @package Solar_Session
+ * 
+ * @author Antti Holvikari <anttih at gmail.com>
+ * 
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * 
+ * @version $Id$
+ * 
+ */
+class Solar_Session_Handler_Adapter_Sql extends Solar_Session_Handler_Adapter {
+    
+    /**
+     * 
+     * Solar_Sql object to connect to the database.
+     * 
+     * @var Solar_Sql_Adapter
+     * 
+     */
+    protected $_sql;
+    
+    /**
+     * 
+     * Default configuration values.
+     * 
+     * Keys are ...
+     * 
+     * `sql`
+     * : (dependency) A Solar_Sql dependency injection.
+     * 
+     * `table`
+     * : (string) Table where the session data will be stored, default
+     * 'sessions'.
+     * 
+     * `created_col`
+     * : (string) Column name where time of creation is to be stored, default
+     *   'created'.
+     * 
+     * `id_col`
+     * : (string) Column name of the session id, default 'id'.
+     * 
+     * `data_col`
+     * : (string) Column name where the actual session data will be stored,
+     *   default 'data'.
+     * 
+     * @var array
+     * 
+     */
+    protected $_Solar_Session_Handler_Adapter_Sql = array(
+        'sql'         => 'sql',
+        'table'       => 'sessions',
+        'id_col'      => 'id',
+        'created_col' => 'created',
+        'updated_col' => 'updated',
+        'data_col'    => 'data',
+    );
+    
+    /**
+     * 
+     * Open session handler
+     * 
+     * @return bool
+     * 
+     */
+    public function open()
+    {
+        if (! $this->_sql) {
+            $this->_sql = Solar::dependency(
+                'Solar_Sql',
+                $this->_config['sql']
+            );
+        }
+        
+        return true;
+    }
+    
+    /**
+     * 
+     * Reads session data.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @return string The serialized session data.
+     * 
+     */
+    public function read($id)
+    {
+        $sel = Solar::factory(
+            'Solar_Sql_Select',
+            array('sql' => $this->_sql)
+        );
+        
+        $sel->from($this->_config['table'])
+            ->cols($this->_config['data_col'])
+            ->where("{$this->_config['id_col']} = ?", $id);
+        
+        return $sel->fetchValue();
+    }
+    
+    /**
+     * 
+     * Writes session data.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @param string $data The serialized session data.
+     * 
+     * @return bool
+     * 
+     */
+    public function write($id, $data)
+    {
+        $sel = Solar::factory(
+            'Solar_Sql_Select',
+            array('sql' => $this->_sql)
+        );
+        
+        // select up to 2 records from the database
+        $sel->from($this->_config['table'])
+            ->cols($this->_config['id_col'])
+            ->where("{$this->_config['id_col']} = ?", $id)
+            ->limit(2);
+            
+        // use fetchCol() instead of countPages() for speed reasons.
+        // count on some DBs is pretty slow, so this will fetch only
+        // the rows we need.
+        $rows  = $sel->fetchCol();
+        $count = count((array) $rows);
+        
+        // insert or update?
+        if ($count == 0) {
+            // no data yet, insert
+            return $this->_insert($data);
+        } elseif ($count == 1) {
+            // existing data, update
+            return $this->_update($data);
+        } else {
+            // more than one row means an ID collision
+            // @todo log this somehow?
+            return false;
+        }
+    }
+    
+    /**
+     * 
+     * Destroys session data.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @return bool
+     * 
+     */
+    public function destroy($id)
+    {
+        $this->_sql->delete(
+            $this->_config['table'],
+            array("{$this->_config['id_col']} = ?" => $id)
+        );
+        
+        return true;
+    }
+    
+    /**
+     * 
+     * Removes old session data (garbage collection).
+     * 
+     * @param int $lifetime Removes session data not updated since this many
+     * seconds ago.  E.g., a lifetime of 86400 removes all session data not
+     * updated in the past 24 hours.
+     * 
+     * @return bool
+     * 
+     */
+    public function gc($lifetime)
+    {
+        // timestamp is current time minus session.gc_maxlifetime
+        $timestamp = date(
+            'Y-m-d H:i:s',
+            mktime(date('H'), date('i'), date('s') - $lifetime)
+        );
+        
+        // delete all sessions last updated before the timestamp
+        $this->_sql->delete($this->_config['table'], array(
+            "{$this->_config['updated_col']} < ?" => $timestamp,
+        ));
+        
+        return true;
+    }
+    
+    /**
+     * 
+     * Inserts a new session-data row in the database.
+     * 
+     * @param string $data The serialized session data.
+     * 
+     * @return bool
+     * 
+     */
+    protected function _insert($data)
+    {
+        $now = date('Y-m-d H:i:s');
+        
+        $cols = array(
+            $this->_config['created_col'] => $now,
+            $this->_config['updated_col'] => $now,
+            $this->_config['id_col']      => $id,
+            $this->_config['data_col']    => $data,
+        );
+        
+        try {
+            $this->_sql->insert($this->_config['table'], $values);
+        } catch (Solar_Sql_Exception $e) {
+            // @todo log this somehow?
+            return false;
+        }
+    }
+    
+    /**
+     * 
+     * Updates an existing session-data row in the database.
+     * 
+     * @param string $data The serialized session data.
+     * 
+     * @return bool
+     * 
+     * @todo Should we log caught exceptions?
+     *
+     */
+    protected function _update($data)
+    {
+        $cols = array(
+            $this->_config['updated_col'] => date('Y-m-d H:i:s'),
+            $this->_config['data_col']    => $data,
+        );
+        
+        $where = array("{$this->_config['id_col']} = ?" => $id);
+        
+        try {
+            $this->_sql->update($this->_config['table'], $cols, $where);
+        } catch (Solar_Sql_Exception $e) {
+            // @todo log this somehow?
+            return false;
+        }
+    }
+}
\ No newline at end of file

Added: trunk/Solar/Session/Handler/Adapter.php
===================================================================
--- trunk/Solar/Session/Handler/Adapter.php	                        (rev 0)
+++ trunk/Solar/Session/Handler/Adapter.php	2008-03-05 03:20:15 UTC (rev 2983)
@@ -0,0 +1,129 @@
+<?php
+/**
+ * 
+ * Abstract class for session adapters.
+ * 
+ * @category Solar
+ * 
+ * @package Solar_Session
+ * 
+ * @author Antti Holvikari <anttih at gmail.com>
+ * 
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * 
+ * @version $Id$
+ * 
+ */
+abstract class Solar_Session_Handler_Adapter extends Solar_Base {
+    
+    /**
+     * 
+     * Constructor.
+     * 
+     * @param array $config User-defined configuration values.
+     * 
+     */
+    public function __construct($config = null)
+    {
+        parent::__construct($config);
+        $this->_setSaveHandler();
+    }
+    
+    /**
+     * 
+     * Destructor; calls session_write_close() so that the session gets
+     * written before the object is destroyed.
+     * 
+     * @return void
+     * 
+     */
+    public function __destruct()
+    {
+        session_write_close();
+    }
+    
+    /**
+     * 
+     * Sets session save handler to use the methods in this class.
+     * 
+     * @return void
+     * 
+     */
+    protected function _setSaveHandler()
+    {
+        session_set_save_handler(
+            array($this, 'open'),
+            array($this, 'close'),
+            array($this, 'read'),
+            array($this, 'write'),
+            array($this, 'destroy'),
+            array($this, 'gc')
+        );
+    }
+    
+    /**
+     * 
+     * Opens the session handler.
+     * 
+     * @return bool
+     * 
+     */
+    abstract public function open();
+    
+    /**
+     * 
+     * Closes the session handler.
+     * 
+     * @return bool
+     * 
+     */
+    abstract public function close();
+    
+    /**
+     * 
+     * Reads session data.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @return string The serialized session data.
+     * 
+     */
+    abstract public function read($id);
+    
+    /**
+     * 
+     * Writes session data.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @param string $data The serialized session data.
+     * 
+     * @return bool
+     * 
+     */
+    abstract public function write($id, $data);
+    
+    /**
+     * 
+     * Destroys session data.
+     * 
+     * @param string $id The session ID.
+     * 
+     * @return bool
+     * 
+     */
+    abstract public function destroy($id);
+    
+    /**
+     * 
+     * Removes old session data (garbage collection).
+     * 
+     * @param int $lifetime Removes session data not updated since this many
+     * seconds ago.  E.g., a lifetime of 86400 removes all session data not
+     * updated in the past 24 hours.
+     * 
+     * @return bool
+     * 
+     */
+    abstract public function gc($lifetime);
+}

Added: trunk/Solar/Session/Handler.php
===================================================================
--- trunk/Solar/Session/Handler.php	                        (rev 0)
+++ trunk/Solar/Session/Handler.php	2008-03-05 03:20:15 UTC (rev 2983)
@@ -0,0 +1,53 @@
+<?php
+/**
+ * 
+ * Factory class for session save-handlers.
+ * 
+ * @category Solar
+ * 
+ * @package Solar_Session
+ * 
+ * @author Antti Holvikari <anttih at gmail.com>
+ * 
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * 
+ * @version $Id$
+ * 
+ */
+class Solar_Session_Handler extends Solar_Base {
+    
+    /**
+     * 
+     * User-provided configuration.
+     * 
+     * Keys are ...
+     * 
+     * `adapter`
+     * : (string) The class to factory, for example
+     *   'Solar_Session_Handler_Adapter_Native'.
+     * 
+     * @var array
+     * 
+     */
+    protected $_Solar_Session_Handler = array(
+        'adapter' => 'Solar_Session_Handler_Adapter_Native',
+    );
+    
+    /**
+     * 
+     * Factory method to create session adapter objects.
+     * 
+     * @return Solar_Session_Handler_Adapter
+     * 
+     */
+    public function solarFactory()
+    {
+        // bring in the config and get the adapter class.
+        $config = $this->_config;
+        $class = $config['adapter'];
+        unset($config['adapter']);
+        
+        // return the factoried adapter object
+        return Solar::factory($class, $config);
+    }
+}

Modified: trunk/Solar/Session.php
===================================================================
--- trunk/Solar/Session.php	2008-03-04 13:54:02 UTC (rev 2982)
+++ trunk/Solar/Session.php	2008-03-05 03:20:15 UTC (rev 2983)
@@ -19,10 +19,12 @@
  * 
  * @category Solar
  * 
- * @package Solar
+ * @package Solar_Session
  * 
  * @author Paul M. Jones <pmjones at solarphp.com>
  * 
+ * @author Antti Holvikari <anttih at gmail.com>
+ * 
  * @license http://opensource.org/licenses/bsd-license.php BSD
  * 
  * @version $Id$
@@ -163,19 +165,18 @@
      */
     protected $_Solar_Session = array(
         'class'   => 'Solar',
-        'handler' => 'php',
+        'handler' => null,
         'P3P'     => 'CP="CAO COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT STA"',
     );
     
     /**
      * 
-     * The session save handler object, or a string 'php' to use the native
-     * PHP session handler instead.
+     * The session save handler object.
      * 
-     * @param Solar_Session_Handler|string
+     * @param Solar_Session_Handler_Adapter
      * 
      */
-    static public $handler = 'php';
+    static public $handler;
     
     /**
      * 
@@ -227,11 +228,11 @@
         
         // only set up the handler if it doesn't exist yet.
         if (! self::$handler) {
-            self::setHandler($this->_config['handler']);
+            $this->_setHandler($this->_config['handler']);
         }
         
         // start a session if one does not exist, but not if we're at
-        // the command line.
+        // the command line. at the command line, you need to start it yourself.
         if (session_id() === '' && PHP_SAPI != 'cli') {
             if ($this->_config['P3P']) {
                 header('P3P: ' . $this->_config['P3P']);
@@ -250,16 +251,16 @@
     
     /**
      * 
-     * Sets the save-handler for **all** session objecs.
+     * Sets the save-handler for **all** session objects.
      * 
      * Once a session is started, the handler cannot be changed.
      * 
-     * @param dependency $hander A Solar_Sesssion_Handler dependency injection..
+     * @param dependency $handler A Solar_Sesssion_Handler dependency injection..
      * 
      * @return void
      * 
      */
-    static public function setHandler($handler)
+    protected function _setHandler($handler)
     {
         if (session_id() === '' && self::$handler) {
             // if the handler is set and the session is already running,
@@ -272,15 +273,7 @@
             );
         }
         
-        // use native php sessions?
-        if (is_string($handler) && strtolower($handler) == 'php') {
-            // set the handler to a non-object, so that we know we're
-            // asking for the native php session handler.
-            $handler = 'php';
-            return;
-        }
-        
-        // build the handler up from a dependency otherwise
+        // session handler dependency
         self::$handler = Solar::dependency(
             'Solar_Session_Handler',
             $handler
@@ -506,4 +499,4 @@
             session_regenerate_id(true);
         }
     }
-}
+}
\ No newline at end of file




More information about the Solar-svn mailing list