Convert drivers to ucfirst names
authorMichael M Slusarz <slusarz@curecanti.org>
Mon, 23 Feb 2009 20:03:51 +0000 (13:03 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Mon, 23 Feb 2009 20:03:51 +0000 (13:03 -0700)
16 files changed:
framework/SessionHandler/lib/Horde/SessionHandler.php
framework/SessionHandler/lib/Horde/SessionHandler/Ldap.php [new file with mode: 0644]
framework/SessionHandler/lib/Horde/SessionHandler/Memcache.php [new file with mode: 0644]
framework/SessionHandler/lib/Horde/SessionHandler/Mysql.php [new file with mode: 0644]
framework/SessionHandler/lib/Horde/SessionHandler/None.php [new file with mode: 0644]
framework/SessionHandler/lib/Horde/SessionHandler/Oci8.php [new file with mode: 0644]
framework/SessionHandler/lib/Horde/SessionHandler/Pgsql.php [new file with mode: 0644]
framework/SessionHandler/lib/Horde/SessionHandler/Sql.php [new file with mode: 0644]
framework/SessionHandler/lib/Horde/SessionHandler/ldap.php [deleted file]
framework/SessionHandler/lib/Horde/SessionHandler/memcache.php [deleted file]
framework/SessionHandler/lib/Horde/SessionHandler/mysql.php [deleted file]
framework/SessionHandler/lib/Horde/SessionHandler/none.php [deleted file]
framework/SessionHandler/lib/Horde/SessionHandler/oci8.php [deleted file]
framework/SessionHandler/lib/Horde/SessionHandler/pgsql.php [deleted file]
framework/SessionHandler/lib/Horde/SessionHandler/sql.php [deleted file]
framework/SessionHandler/package.xml

index 5a20f97..4856748 100644 (file)
@@ -57,7 +57,8 @@ class Horde_SessionHandler
      * Attempts to return a concrete Horde_SessionHandler instance based on
      * $driver.
      *
-     * @param string $driver  The type of concrete subclass to return.
+     * @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.
      *
@@ -66,7 +67,7 @@ class Horde_SessionHandler
      */
     static public function factory($driver, $params = array())
     {
-        $driver = basename($driver);
+        $driver = basename(strtolower($driver));
         $persistent_params = array();
 
         if ($driver == 'memcached') {
@@ -79,7 +80,7 @@ class Horde_SessionHandler
             $params = array();
         }
 
-        $class = 'Horde_SessionHandler_' . $driver;
+        $class = 'Horde_SessionHandler_' . ucfirst($driver);
 
         if (class_exists($class)) {
             if (empty($params)) {
@@ -88,7 +89,7 @@ class Horde_SessionHandler
             return new $class(array_merge($params, $persistent_params));
         }
 
-        throw new Horde_Exception('Class definition of ' . $class . ' not found.');
+        throw new Horde_Exception('Driver "' . $driver . '" not found.');
     }
 
     /**
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/Ldap.php b/framework/SessionHandler/lib/Horde/SessionHandler/Ldap.php
new file mode 100644 (file)
index 0000000..a3e7767
--- /dev/null
@@ -0,0 +1,139 @@
+<?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>
+ *
+ * This code is adapted from the comments at
+ * http://www.php.net/session-set-save-handler.
+ *
+ * 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
+ */
+class Horde_SessionHandler_Ldap extends Horde_SessionHandler
+{
+    /**
+     * Handle for the current database connection.
+     *
+     * @var resource
+     */
+    protected $_conn;
+
+    /**
+     * 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)
+    {
+        $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 (!@ldap_bind($this->_conn, $this->_params['dn'], $this->_params['password'])) {
+            throw new Horde_Exception('Could not bind to LDAP server.');
+        }
+    }
+
+    /**
+     * Close the backend.
+     */
+    protected function _close()
+    {
+        if (!@ldap_close($this->_conn)) {
+            throw new Horde_Exception('Could not unbind from LDAP server.');
+        }
+    }
+
+    /**
+     * 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)
+    {
+        $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] : '';
+    }
+
+    /**
+     * 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)
+    {
+        $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);
+    }
+
+    /**
+     * 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)
+    {
+        $dn = "cn=$id," . $this->_params['dn'];
+        return @ldap_delete($this->_conn, $dn);
+    }
+
+    /**
+     * 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)
+    {
+        $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++) {
+                $id = $info[$i]['cn'][0];
+                $dn = "cn=$id," . $this->_params['dn'];
+                $ldapstamp = $info[$i]['modifytimestamp'][0];
+                $year = substr($ldapstamp, 0, 4);
+                $month = substr($ldapstamp, 4, 2);
+                $day = substr($ldapstamp, 6, 2);
+                $hour = substr($ldapstamp, 8, 2);
+                $minute = substr($ldapstamp, 10, 2);
+                $modified = gmmktime($hour, $minute, 0, $month, $day, $year);
+                if (time() - $modified >= $maxlifetime) {
+                    @ldap_delete($this->_conn, $dn);
+                }
+            }
+        }
+
+        return true;
+    }
+
+}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/Memcache.php b/framework/SessionHandler/lib/Horde/SessionHandler/Memcache.php
new file mode 100644 (file)
index 0000000..59ba2cb
--- /dev/null
@@ -0,0 +1,358 @@
+<?php
+/**
+ * Horde_SessionHandler:: implementation for memcache.
+ *
+ * NOTE FOR WINDOWS USERS w/PHP 4: Due to limitations in PHP 4, you should not
+ * use the memcache driver.  Either upgrade to PHP 5 or use a different
+ * session handler.
+ *
+ * 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>
+ *
+ * Copyright 2005-2009 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
+ */
+class Horde_SessionHandler_Memcache extends Horde_SessionHandler
+{
+    /**
+     * Horde_Memcache object.
+     *
+     * @var Horde_Memcache
+     */
+    protected $_memcache;
+
+    /**
+     * Current session ID.
+     *
+     * @var string
+     */
+    protected $_id;
+
+    /**
+     * Persistent backend driver.
+     *
+     * @var Horde_SessionHandler
+     */
+    protected $_persistent;
+
+    /**
+     * Do read-only get?
+     *
+     * @var boolean
+     */
+    protected $_readonly = false;
+
+    /**
+     * The ID used for session tracking.
+     *
+     * @var string
+     */
+    protected $_trackID = 'horde_memcache_sessions_track';
+
+    /**
+     * Constructor.
+     *
+     * @param array $params  A hash containing connection parameters.
+     *
+     * @throws Horde_Exception
+     */
+    protected function __construct($params = array())
+    {
+        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.');
+            }
+        }
+
+        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');
+        }
+    }
+
+    /**
+     * Destructor.
+     */
+    public function __destruct()
+    {
+        if (!empty($this->_params['track']) && (rand(0, 999) == 0)) {
+            $this->_trackGC();
+        }
+
+        parent::__destruct();
+    }
+
+    /**
+     * 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)
+    {
+        $this->_memcache = &Horde_Memcache::singleton();
+        if (is_a($this->_memcache, 'PEAR_Error')) {
+            throw new Horde_Exception($this->_memcache);
+        }
+
+        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();
+        }
+    }
+
+    /**
+     * Read the data for a particular session identifier.
+     *
+     * @param string $id  The session identifier.
+     *
+     * @return string  The session data.
+     */
+    protected function _read($id)
+    {
+        if (!$this->_readonly) {
+            $this->_memcache->lock($id);
+        }
+        $result = $this->_memcache->get($id);
+
+        if ($result === false) {
+            if (!$this->_readonly) {
+                $this->_memcache->unlock($id);
+            }
+
+            if (isset($this->_persistent)) {
+                $result = $this->_persistent->read($id);
+            }
+
+            if ($result === false) {
+                Horde::logMessage('Error retrieving session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
+                return false;
+            }
+
+            $this->_persistent->write($id, $session_data);
+        }
+
+        if (!$this->_readonly) {
+            $this->_id = $id;
+        }
+
+        Horde::logMessage('Read session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        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)
+    {
+        if (!empty($this->_params['track'])) {
+            // Do a replace - the only time it should fail is if we are
+            // writing a session for the first time.  If that is the case,
+            // update the session tracker.
+            $res = $this->_memcache->replace($id, $session_data);
+            $track = !$res;
+        } else {
+            $res = $track = false;
+        }
+
+        if (!$res &&
+            !$this->_memcache->set($id, $session_data)) {
+            Horde::logMessage('Error writing session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_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);
+            if ($ids === false) {
+                $ids = array();
+            }
+
+            $ids[$id] = time();
+            $this->_memcache->set($this->_trackID, $ids);
+            $this->_memcache->unlock($this->_trackID);
+        }
+
+        Horde::logMessage('Wrote session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return true;
+    }
+
+    /**
+     * Destroy the data for a particular session identifier.
+     *
+     * @param string $id  The session identifier.
+     *
+     * @return boolean  True on success, false otherwise.
+     */
+    public function destroy($id)
+    {
+        $result = $this->_memcache->delete($id);
+        $this->_memcache->unlock($id);
+
+        if ($result !== false &&
+            isset($this->_persistent)) {
+            $result = $this->_persistent->destroy($id);
+        }
+
+        if ($result !== false) {
+            Horde::logMessage('Failed to delete session (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
+            return false;
+        }
+
+        if (!empty($this->_params['track'])) {
+            $this->_memcache->lock($this->_trackID);
+            $ids = $this->_memcache->get($this->_trackID);
+            if ($ids !== false) {
+                unset($ids[$id]);
+                $this->_memcache->set($this->_trackID, $ids);
+            }
+            $this->_memcache->unlock($this->_trackID);
+        }
+
+        Horde::logMessage('Deleted session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        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)
+    {
+        $result = true;
+
+        if (isset($this->_persistent)) {
+            $result = $this->_persistent->gc($maxlifetime);
+        }
+
+        // Memcache does its own garbage collection.
+        return $result;
+    }
+
+    /**
+     * Get a list of (possibly) valid session identifiers.
+     *
+     * @return array  A list of session identifiers.
+     * @throws Horde_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;
+        }
+
+        $this->_trackGC();
+
+        $ids = $this->_memcache->get($this->_trackID);
+        return ($ids === false) ? array() : array_keys($ids);
+    }
+
+    /**
+     * Get session data read-only.
+     *
+     * @param string $id  The session identifier.
+     *
+     * @return string  The session data.
+     */
+    protected function _readOnly($id)
+    {
+        $this->_readonly = true;
+        $result = $this->_memcache->get($id);
+        $this->_readonly = false;
+        return $result;
+    }
+
+    /**
+     * Do garbage collection for session tracking information.
+     */
+    protected function _trackGC()
+    {
+        $this->_memcache->lock($this->_trackID);
+        $ids = $this->_memcache->get($this->_trackID);
+        if (empty($ids)) {
+            $this->_memcache->unlock($this->_trackID);
+            return;
+        }
+
+        $tstamp = time() - $this->_params['track_lifetime'];
+        $alter = false;
+
+        foreach ($ids as $key => $val) {
+            if ($tstamp > $val) {
+                unset($ids[$key]);
+                $alter = true;
+            }
+        }
+
+        if ($alter) {
+            $this->_memcache->set($this->_trackID, $ids);
+        }
+
+        $this->_memcache->unlock($this->_trackID);
+    }
+
+}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/Mysql.php b/framework/SessionHandler/lib/Horde/SessionHandler/Mysql.php
new file mode 100644 (file)
index 0000000..503c789
--- /dev/null
@@ -0,0 +1,305 @@
+<?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-2009 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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        $result = @mysql_query($query, $this->_db);
+        if (!$result) {
+            Horde::logMessage('Error retrieving session data (id = ' . $id . '): ' . mysql_error($this->_db), __FILE__, __LINE__, PEAR_LOG_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, __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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, __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $result = @mysql_query($query, $this->_db);
+        if (!$result) {
+            Horde::logMessage('Error garbage collecting old sessions: ' . mysql_error($this->_db), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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) . "'";
+        }
+    }
+
+}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/None.php b/framework/SessionHandler/lib/Horde/SessionHandler/None.php
new file mode 100644 (file)
index 0000000..e886f75
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Horde_SessionHandler:: implementation for PHP's built-in session handler.
+ *
+ * Required parameters:<pre>
+ *   None.</pre>
+ *
+ * Optional parameters:<pre>
+ *   None.</pre>
+ *
+ * Copyright 2005-2009 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, __FILE__, __LINE__, PEAR_LOG_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) ? 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;
+    }
+
+}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/Oci8.php b/framework/SessionHandler/lib/Horde/SessionHandler/Oci8.php
new file mode 100644 (file)
index 0000000..0dc3ce2
--- /dev/null
@@ -0,0 +1,278 @@
+<?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), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $statement = OCIParse($this->_db, $query);
+        $result = OCIExecute($statement);
+        if (!$result) {
+            OCIFreeStatement($statement);
+            Horde::logMessage('Failed to delete session (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $statement = OCIParse($this->_db, $query);
+        $result = OCIExecute($statement);
+        if (!$result) {
+            OCIFreeStatement($statement);
+            Horde::logMessage('Error garbage collecting old sessions', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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) . "'";
+    }
+
+}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/Pgsql.php b/framework/SessionHandler/lib/Horde/SessionHandler/Pgsql.php
new file mode 100644 (file)
index 0000000..8a9b4e1
--- /dev/null
@@ -0,0 +1,285 @@
+<?php
+/**
+ * Horde_SessionHandler implementation for PostgreSQL (native).
+ *
+ * Copyright 1999-2009 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), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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 . ')', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $result = @pg_query($this->_db, $query);
+        if (!$result) {
+            Horde::logMessage('Error garbage collecting old sessions', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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) . "'";
+    }
+
+}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/Sql.php b/framework/SessionHandler/lib/Horde/SessionHandler/Sql.php
new file mode 100644 (file)
index 0000000..4f7ea5e
--- /dev/null
@@ -0,0 +1,298 @@
+<?php
+/**
+ * Horde_SessionHandler implementation for PHP's PEAR database abstraction
+ * layer.
+ *
+ * Required parameters:<pre>
+ *   'phptype'  - (string) The database type (e.g. 'pgsql', 'mysql', etc.).
+ *   '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.
+ *   'options'  - (array) Additional options to pass to the database.
+ *   'tty'      - (string) The TTY on which to connect to the database.
+ *   'port'     - (integer) The port on which to connect to the database.
+ * </pre>
+ *
+ * Optional parameters:<pre>
+ *   'table'      - (string) The name of the sessiondata table in 'database'.
+ *   'persistent' - (boolean) Use persistent DB connections?
+ * </pre>
+ *
+ * Optional values when using separate reading and writing servers, for example
+ * in replication settings:<pre>
+ *   'splitread' - (boolean) Whether to implement the separation or not.
+ *   'read'      - (array) Array containing the parameters which are
+ *                 different for the writer database connection, currently
+ *                 supports only 'hostspec' and 'port' parameters.
+ * </pre>
+ *
+ * The table structure can be found in:
+ *   horde/scripts/sql/horde_sessionhandler.sql.
+ *
+ * Copyright 2002-2009 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>
+ * @package Horde_SessionHandler
+ */
+class Horde_SessionHandler_Sql extends Horde_SessionHandler
+{
+    /**
+     * Handle for the current database connection.
+     *
+     * @var DB
+     */
+    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;
+
+    /**
+     * 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('phptype'),
+                                  'session handler SQL');
+
+        if (!isset($this->_params['database'])) {
+            $this->_params['database'] = '';
+        }
+        if (!isset($this->_params['username'])) {
+            $this->_params['username'] = '';
+        }
+        if (!isset($this->_params['hostspec'])) {
+            $this->_params['hostspec'] = '';
+        }
+        if (empty($this->_params['table'])) {
+            $this->_params['table'] = 'horde_sessionhandler';
+        }
+
+        /* Connect to the SQL server using the supplied parameters. */
+        $this->_write_db = &DB::connect($this->_params,
+                                        array('persistent' => !empty($this->_params['persistent']),
+                                              'ssl' => !empty($this->_params['ssl'])));
+        if (is_a($this->_write_db, 'PEAR_Error')) {
+            throw new Horde_Exception($this->_write_db);
+        }
+
+        $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+
+        /* Check if we need to set up the read DB connection
+         * seperately. */
+        if (!empty($this->_params['splitread'])) {
+            $params = array_merge($this->_params, $this->_params['read']);
+            $this->_db = &DB::connect($params,
+                                      array('persistent' => !empty($params['persistent']),
+                                            'ssl' => !empty($this->_params['ssl'])));
+            if (is_a($this->_db, 'PEAR_Error')) {
+                throw new Horde_Exception($this->_db);
+            }
+            $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+        } else {
+            /* Default to the same DB handle for reads. */
+            $this->_db =& $this->_write_db;
+        }
+    }
+
+    /**
+     * Close the backend.
+     *
+     * @throws Horde_Exception
+     */
+    protected function _close()
+    {
+        /* Close any open transactions. */
+        $this->_db->commit();
+        $this->_db->autoCommit(true);
+        $this->_write_db->commit();
+        $this->_write_db->autoCommit(true);
+
+        @$this->_write_db->disconnect();
+        @$this->_db->disconnect();
+    }
+
+    /**
+     * 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)
+    {
+        /* Begin a transaction. */
+        $result = $this->_write_db->autocommit(false);
+        if (is_a($result, 'PEAR_Error')) {
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return '';
+        }
+
+        /* Execute the query. */
+        $result = Horde_SQL::readBlob($this->_write_db, $this->_params['table'], 'session_data', array('session_id' => $id));
+
+        if (is_a($result, 'PEAR_Error')) {
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return '';
+        }
+
+        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)
+    {
+        /* Build the SQL query. */
+        $query = sprintf('SELECT session_id FROM %s WHERE session_id = ?',
+                         $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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $result = $this->_write_db->getOne($query, $values);
+        if (is_a($result, 'PEAR_Error')) {
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_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, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return false;
+        }
+
+        $result = $this->_write_db->commit();
+        if (is_a($result, 'PEAR_Error')) {
+            $this->_write_db->autoCommit(true);
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return false;
+        }
+
+        $this->_write_db->autoCommit(true);
+        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 = ?',
+                         $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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $result = $this->_write_db->query($query, $values);
+        if (is_a($result, 'PEAR_Error')) {
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return false;
+        }
+
+        $result = $this->_write_db->commit();
+        if (is_a($result, 'PEAR_Error')) {
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return false;
+        }
+
+        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 < ?',
+                         $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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $result = $this->_write_db->query($query, $values);
+        if (is_a($result, 'PEAR_Error')) {
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * 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 => ?';
+        $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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $result = $this->_db->getCol($query, 0, $values);
+        if (is_a($result, 'PEAR_Error')) {
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return false;
+        }
+
+        return $result;
+    }
+
+}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/ldap.php b/framework/SessionHandler/lib/Horde/SessionHandler/ldap.php
deleted file mode 100644 (file)
index 4aed3b5..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-<?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>
- *
- * This code is adapted from the comments at
- * http://www.php.net/session-set-save-handler.
- *
- * 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
- */
-class Horde_SessionHandler_ldap extends Horde_SessionHandler
-{
-    /**
-     * Handle for the current database connection.
-     *
-     * @var resource
-     */
-    protected $_conn;
-
-    /**
-     * 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)
-    {
-        $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 (!@ldap_bind($this->_conn, $this->_params['dn'], $this->_params['password'])) {
-            throw new Horde_Exception('Could not bind to LDAP server.');
-        }
-    }
-
-    /**
-     * Close the backend.
-     */
-    protected function _close()
-    {
-        if (!@ldap_close($this->_conn)) {
-            throw new Horde_Exception('Could not unbind from LDAP server.');
-        }
-    }
-
-    /**
-     * 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)
-    {
-        $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] : '';
-    }
-
-    /**
-     * 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)
-    {
-        $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);
-    }
-
-    /**
-     * 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)
-    {
-        $dn = "cn=$id," . $this->_params['dn'];
-        return @ldap_delete($this->_conn, $dn);
-    }
-
-    /**
-     * 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)
-    {
-        $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++) {
-                $id = $info[$i]['cn'][0];
-                $dn = "cn=$id," . $this->_params['dn'];
-                $ldapstamp = $info[$i]['modifytimestamp'][0];
-                $year = substr($ldapstamp, 0, 4);
-                $month = substr($ldapstamp, 4, 2);
-                $day = substr($ldapstamp, 6, 2);
-                $hour = substr($ldapstamp, 8, 2);
-                $minute = substr($ldapstamp, 10, 2);
-                $modified = gmmktime($hour, $minute, 0, $month, $day, $year);
-                if (time() - $modified >= $maxlifetime) {
-                    @ldap_delete($this->_conn, $dn);
-                }
-            }
-        }
-
-        return true;
-    }
-
-}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/memcache.php b/framework/SessionHandler/lib/Horde/SessionHandler/memcache.php
deleted file mode 100644 (file)
index 7307516..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-<?php
-/**
- * Horde_SessionHandler:: implementation for memcache.
- *
- * NOTE FOR WINDOWS USERS w/PHP 4: Due to limitations in PHP 4, you should not
- * use the memcache driver.  Either upgrade to PHP 5 or use a different
- * session handler.
- *
- * 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>
- *
- * Copyright 2005-2009 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
- */
-class Horde_SessionHandler_memcache extends Horde_SessionHandler
-{
-    /**
-     * Horde_Memcache object.
-     *
-     * @var Horde_Memcache
-     */
-    protected $_memcache;
-
-    /**
-     * Current session ID.
-     *
-     * @var string
-     */
-    protected $_id;
-
-    /**
-     * Persistent backend driver.
-     *
-     * @var Horde_SessionHandler
-     */
-    protected $_persistent;
-
-    /**
-     * Do read-only get?
-     *
-     * @var boolean
-     */
-    protected $_readonly = false;
-
-    /**
-     * The ID used for session tracking.
-     *
-     * @var string
-     */
-    protected $_trackID = 'horde_memcache_sessions_track';
-
-    /**
-     * Constructor.
-     *
-     * @param array $params  A hash containing connection parameters.
-     *
-     * @throws Horde_Exception
-     */
-    protected function __construct($params = array())
-    {
-        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.');
-            }
-        }
-
-        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');
-        }
-    }
-
-    /**
-     * Destructor.
-     */
-    public function __destruct()
-    {
-        if (!empty($this->_params['track']) && (rand(0, 999) == 0)) {
-            $this->_trackGC();
-        }
-
-        parent::__destruct();
-    }
-
-    /**
-     * 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)
-    {
-        $this->_memcache = &Horde_Memcache::singleton();
-        if (is_a($this->_memcache, 'PEAR_Error')) {
-            throw new Horde_Exception($this->_memcache);
-        }
-
-        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();
-        }
-    }
-
-    /**
-     * Read the data for a particular session identifier.
-     *
-     * @param string $id  The session identifier.
-     *
-     * @return string  The session data.
-     */
-    protected function _read($id)
-    {
-        if (!$this->_readonly) {
-            $this->_memcache->lock($id);
-        }
-        $result = $this->_memcache->get($id);
-
-        if ($result === false) {
-            if (!$this->_readonly) {
-                $this->_memcache->unlock($id);
-            }
-
-            if (isset($this->_persistent)) {
-                $result = $this->_persistent->read($id);
-            }
-
-            if ($result === false) {
-                Horde::logMessage('Error retrieving session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
-                return false;
-            }
-
-            $this->_persistent->write($id, $session_data);
-        }
-
-        if (!$this->_readonly) {
-            $this->_id = $id;
-        }
-
-        Horde::logMessage('Read session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
-        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)
-    {
-        if (!empty($this->_params['track'])) {
-            // Do a replace - the only time it should fail is if we are
-            // writing a session for the first time.  If that is the case,
-            // update the session tracker.
-            $res = $this->_memcache->replace($id, $session_data);
-            $track = !$res;
-        } else {
-            $res = $track = false;
-        }
-
-        if (!$res &&
-            !$this->_memcache->set($id, $session_data)) {
-            Horde::logMessage('Error writing session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_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);
-            if ($ids === false) {
-                $ids = array();
-            }
-
-            $ids[$id] = time();
-            $this->_memcache->set($this->_trackID, $ids);
-            $this->_memcache->unlock($this->_trackID);
-        }
-
-        Horde::logMessage('Wrote session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
-        return true;
-    }
-
-    /**
-     * Destroy the data for a particular session identifier.
-     *
-     * @param string $id  The session identifier.
-     *
-     * @return boolean  True on success, false otherwise.
-     */
-    public function destroy($id)
-    {
-        $result = $this->_memcache->delete($id);
-        $this->_memcache->unlock($id);
-
-        if ($result !== false &&
-            isset($this->_persistent)) {
-            $result = $this->_persistent->destroy($id);
-        }
-
-        if ($result !== false) {
-            Horde::logMessage('Failed to delete session (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
-            return false;
-        }
-
-        if (!empty($this->_params['track'])) {
-            $this->_memcache->lock($this->_trackID);
-            $ids = $this->_memcache->get($this->_trackID);
-            if ($ids !== false) {
-                unset($ids[$id]);
-                $this->_memcache->set($this->_trackID, $ids);
-            }
-            $this->_memcache->unlock($this->_trackID);
-        }
-
-        Horde::logMessage('Deleted session data (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
-        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)
-    {
-        $result = true;
-
-        if (isset($this->_persistent)) {
-            $result = $this->_persistent->gc($maxlifetime);
-        }
-
-        // Memcache does its own garbage collection.
-        return $result;
-    }
-
-    /**
-     * Get a list of (possibly) valid session identifiers.
-     *
-     * @return array  A list of session identifiers.
-     * @throws Horde_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;
-        }
-
-        $this->_trackGC();
-
-        $ids = $this->_memcache->get($this->_trackID);
-        return ($ids === false) ? array() : array_keys($ids);
-    }
-
-    /**
-     * Get session data read-only.
-     *
-     * @param string $id  The session identifier.
-     *
-     * @return string  The session data.
-     */
-    protected function _readOnly($id)
-    {
-        $this->_readonly = true;
-        $result = $this->_memcache->get($id);
-        $this->_readonly = false;
-        return $result;
-    }
-
-    /**
-     * Do garbage collection for session tracking information.
-     */
-    protected function _trackGC()
-    {
-        $this->_memcache->lock($this->_trackID);
-        $ids = $this->_memcache->get($this->_trackID);
-        if (empty($ids)) {
-            $this->_memcache->unlock($this->_trackID);
-            return;
-        }
-
-        $tstamp = time() - $this->_params['track_lifetime'];
-        $alter = false;
-
-        foreach ($ids as $key => $val) {
-            if ($tstamp > $val) {
-                unset($ids[$key]);
-                $alter = true;
-            }
-        }
-
-        if ($alter) {
-            $this->_memcache->set($this->_trackID, $ids);
-        }
-
-        $this->_memcache->unlock($this->_trackID);
-    }
-
-}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/mysql.php b/framework/SessionHandler/lib/Horde/SessionHandler/mysql.php
deleted file mode 100644 (file)
index 9a5aa01..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-<?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-2009 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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        $result = @mysql_query($query, $this->_db);
-        if (!$result) {
-            Horde::logMessage('Error retrieving session data (id = ' . $id . '): ' . mysql_error($this->_db), __FILE__, __LINE__, PEAR_LOG_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, __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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, __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        /* Execute the query. */
-        $result = @mysql_query($query, $this->_db);
-        if (!$result) {
-            Horde::logMessage('Error garbage collecting old sessions: ' . mysql_error($this->_db), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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) . "'";
-        }
-    }
-
-}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/none.php b/framework/SessionHandler/lib/Horde/SessionHandler/none.php
deleted file mode 100644 (file)
index c845cc9..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-/**
- * Horde_SessionHandler implementation for PHP's built-in session handler.
- *
- * Required parameters:<pre>
- *   None.</pre>
- *
- * Optional parameters:<pre>
- *   None.</pre>
- *
- * Copyright 2005-2009 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, __FILE__, __LINE__, PEAR_LOG_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) ? 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;
-    }
-
-}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/oci8.php b/framework/SessionHandler/lib/Horde/SessionHandler/oci8.php
deleted file mode 100644 (file)
index 21c52ff..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-<?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), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        /* Execute the query. */
-        $statement = OCIParse($this->_db, $query);
-        $result = OCIExecute($statement);
-        if (!$result) {
-            OCIFreeStatement($statement);
-            Horde::logMessage('Failed to delete session (id = ' . $id . ')', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        /* Execute the query. */
-        $statement = OCIParse($this->_db, $query);
-        $result = OCIExecute($statement);
-        if (!$result) {
-            OCIFreeStatement($statement);
-            Horde::logMessage('Error garbage collecting old sessions', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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) . "'";
-    }
-
-}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/pgsql.php b/framework/SessionHandler/lib/Horde/SessionHandler/pgsql.php
deleted file mode 100644 (file)
index e9de427..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-<?php
-/**
- * Horde_SessionHandler implementation for PostgreSQL (native).
- *
- * Copyright 1999-2009 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), __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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 . ')', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        /* Execute the query. */
-        $result = @pg_query($this->_db, $query);
-        if (!$result) {
-            Horde::logMessage('Error garbage collecting old sessions', __FILE__, __LINE__, PEAR_LOG_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), __FILE__, __LINE__, PEAR_LOG_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) . "'";
-    }
-
-}
diff --git a/framework/SessionHandler/lib/Horde/SessionHandler/sql.php b/framework/SessionHandler/lib/Horde/SessionHandler/sql.php
deleted file mode 100644 (file)
index d9cd80e..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-<?php
-/**
- * Horde_SessionHandler implementation for PHP's PEAR database abstraction
- * layer.
- *
- * Required parameters:<pre>
- *   'phptype'  - (string) The database type (e.g. 'pgsql', 'mysql', etc.).
- *   '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.
- *   'options'  - (array) Additional options to pass to the database.
- *   'tty'      - (string) The TTY on which to connect to the database.
- *   'port'     - (integer) The port on which to connect to the database.
- * </pre>
- *
- * Optional parameters:<pre>
- *   'table'      - (string) The name of the sessiondata table in 'database'.
- *   'persistent' - (boolean) Use persistent DB connections?
- * </pre>
- *
- * Optional values when using separate reading and writing servers, for example
- * in replication settings:<pre>
- *   'splitread' - (boolean) Whether to implement the separation or not.
- *   'read'      - (array) Array containing the parameters which are
- *                 different for the writer database connection, currently
- *                 supports only 'hostspec' and 'port' parameters.
- * </pre>
- *
- * The table structure can be found in:
- *   horde/scripts/sql/horde_sessionhandler.sql.
- *
- * Copyright 2002-2009 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>
- * @package Horde_SessionHandler
- */
-class Horde_SessionHandler_sql extends Horde_SessionHandler
-{
-    /**
-     * Handle for the current database connection.
-     *
-     * @var DB
-     */
-    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;
-
-    /**
-     * 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('phptype'),
-                                  'session handler SQL');
-
-        if (!isset($this->_params['database'])) {
-            $this->_params['database'] = '';
-        }
-        if (!isset($this->_params['username'])) {
-            $this->_params['username'] = '';
-        }
-        if (!isset($this->_params['hostspec'])) {
-            $this->_params['hostspec'] = '';
-        }
-        if (empty($this->_params['table'])) {
-            $this->_params['table'] = 'horde_sessionhandler';
-        }
-
-        /* Connect to the SQL server using the supplied parameters. */
-        $this->_write_db = &DB::connect($this->_params,
-                                        array('persistent' => !empty($this->_params['persistent']),
-                                              'ssl' => !empty($this->_params['ssl'])));
-        if (is_a($this->_write_db, 'PEAR_Error')) {
-            throw new Horde_Exception($this->_write_db);
-        }
-
-        $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
-
-        /* Check if we need to set up the read DB connection
-         * seperately. */
-        if (!empty($this->_params['splitread'])) {
-            $params = array_merge($this->_params, $this->_params['read']);
-            $this->_db = &DB::connect($params,
-                                      array('persistent' => !empty($params['persistent']),
-                                            'ssl' => !empty($this->_params['ssl'])));
-            if (is_a($this->_db, 'PEAR_Error')) {
-                throw new Horde_Exception($this->_db);
-            }
-            $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
-        } else {
-            /* Default to the same DB handle for reads. */
-            $this->_db =& $this->_write_db;
-        }
-    }
-
-    /**
-     * Close the backend.
-     *
-     * @throws Horde_Exception
-     */
-    protected function _close()
-    {
-        /* Close any open transactions. */
-        $this->_db->commit();
-        $this->_db->autoCommit(true);
-        $this->_write_db->commit();
-        $this->_write_db->autoCommit(true);
-
-        @$this->_write_db->disconnect();
-        @$this->_db->disconnect();
-    }
-
-    /**
-     * 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)
-    {
-        /* Begin a transaction. */
-        $result = $this->_write_db->autocommit(false);
-        if (is_a($result, 'PEAR_Error')) {
-            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return '';
-        }
-
-        /* Execute the query. */
-        $result = Horde_SQL::readBlob($this->_write_db, $this->_params['table'], 'session_data', array('session_id' => $id));
-
-        if (is_a($result, 'PEAR_Error')) {
-            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return '';
-        }
-
-        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)
-    {
-        /* Build the SQL query. */
-        $query = sprintf('SELECT session_id FROM %s WHERE session_id = ?',
-                         $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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        /* Execute the query. */
-        $result = $this->_write_db->getOne($query, $values);
-        if (is_a($result, 'PEAR_Error')) {
-            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_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, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return false;
-        }
-
-        $result = $this->_write_db->commit();
-        if (is_a($result, 'PEAR_Error')) {
-            $this->_write_db->autoCommit(true);
-            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return false;
-        }
-
-        $this->_write_db->autoCommit(true);
-        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 = ?',
-                         $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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        /* Execute the query. */
-        $result = $this->_write_db->query($query, $values);
-        if (is_a($result, 'PEAR_Error')) {
-            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return false;
-        }
-
-        $result = $this->_write_db->commit();
-        if (is_a($result, 'PEAR_Error')) {
-            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return false;
-        }
-
-        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 < ?',
-                         $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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        /* Execute the query. */
-        $result = $this->_write_db->query($query, $values);
-        if (is_a($result, 'PEAR_Error')) {
-            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * 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 => ?';
-        $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), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-        /* Execute the query. */
-        $result = $this->_db->getCol($query, 0, $values);
-        if (is_a($result, 'PEAR_Error')) {
-            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return false;
-        }
-
-        return $result;
-    }
-
-}
index cb58dff..c180a12 100644 (file)
@@ -53,13 +53,13 @@ http://pear.php.net/dtd/package-2.0.xsd">
    <dir name="lib">
     <dir name="Horde">
      <dir name="SessionHandler">
-      <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="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" />
      </dir> <!-- /lib/Horde/SessionHandler -->
      <file name="SessionHandler.php" role="php" />
     </dir> <!-- /lib/Horde -->
@@ -88,12 +88,12 @@ http://pear.php.net/dtd/package-2.0.xsd">
  </dependencies>
  <phprelease>
   <filelist>
-   <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/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.php" as="Horde/SessionHandler.php" />
    <install name="scripts/Horde/SessionHandler/horde-active-sessions.php" as="scripts/horde-active-sessions.php" />
   </filelist>