* @author David Costa * @author Michael Metz * @author Stefan Neufeind * @author Torsten Roehr * @copyright 1997-2005 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: DB.php,v 1.7 2007/07/14 12:11:54 troehr Exp $ * @link http://pear.php.net/package/HTTP_Session * @since File available since Release 0.4.0 */ require_once 'HTTP/Session/Container.php'; require_once 'DB.php'; /** * Database container for session data * * Create the following table to store session data * * CREATE TABLE `sessiondata` ( * `id` CHAR(32) NOT NULL, * `expiry` INT UNSIGNED NOT NULL DEFAULT 0, * `data` TEXT NOT NULL, * PRIMARY KEY (`id`) * ); * * * @category HTTP * @package HTTP_Session * @author David Costa * @author Michael Metz * @author Stefan Neufeind * @author Torsten Roehr * @copyright 1997-2005 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/HTTP_Session * @since Class available since Release 0.4.0 */ class HTTP_Session_Container_DB extends HTTP_Session_Container { /** * DB connection object * * @var object DB * @access private */ var $db = null; /** * Session data cache id * * @var mixed * @access private */ var $crc = false; /** * Constrtuctor method * * $options is an array with the options.
* The options are: *
    *
  • 'dsn' - The DSN string
  • *
  • 'table' - Table with session data, default is 'sessiondata'
  • *
  • 'autooptimize' - Boolean, 'true' to optimize * the table on garbage collection, default is 'false'.
  • *
* * @param array $options Options * * @access public * @return object */ function HTTP_Session_Container_DB($options) { $this->_setDefaults(); if (is_array($options)) { $this->_parseOptions($options); } else { $this->options['dsn'] = $options; } } /** * Connect to database by using the given DSN string * * @param string $dsn DSN string * * @access private * @return mixed Object on error, otherwise bool */ function _connect($dsn) { if (is_string($dsn) || is_array($dsn)) { $this->db = DB::connect($dsn); } else if (is_object($dsn) && is_a($dsn, "db_common")) { $this->db = $dsn; } else if (is_object($dsn) && DB::isError($dsn)) { return new DB_Error($dsn->code, PEAR_ERROR_DIE); } else { return new PEAR_Error("The given dsn was not valid in file " . __FILE__ . " at line " . __LINE__, 41, PEAR_ERROR_RETURN, null, null ); } if (DB::isError($this->db)) { return new DB_Error($this->db->code, PEAR_ERROR_DIE); } return true; } /** * Set some default options * * @access private * @return void */ function _setDefaults() { $this->options['dsn'] = null; $this->options['table'] = 'sessiondata'; $this->options['autooptimize'] = false; } /** * Establish connection to a database * * @param string $save_path Save path * @param string $session_name Session name * * @return bool */ function open($save_path, $session_name) { if (DB::isError($this->_connect($this->options['dsn']))) { return false; } else { return true; } } /** * Free resources * * @return void */ function close() { return true; } /** * Read session data * * @param string $id Session id * * @return void */ function read($id) { $query = sprintf("SELECT data FROM %s WHERE id = %s AND expiry >= %d", $this->options['table'], $this->db->quoteSmart(md5($id)), time()); $result = $this->db->getOne($query); if (DB::isError($result)) { new DB_Error($result->code, PEAR_ERROR_DIE); return false; } $this->crc = strlen($result) . crc32($result); return $result; } /** * Write session data * * @param string $id Session id * @param mixed $data Data * * @return bool */ function write($id, $data) { if ((false !== $this->crc) && ($this->crc === strlen($data) . crc32($data))) { // $_SESSION hasn't been touched, no need to update the blob column $query = sprintf("UPDATE %s SET expiry = %d WHERE id = %s", $this->options['table'], time() + ini_get('session.gc_maxlifetime'), $this->db->quoteSmart(md5($id))); } else { // Check if table row already exists $query = sprintf("SELECT COUNT(id) FROM %s WHERE id = %s", $this->options['table'], $this->db->quoteSmart(md5($id))); $result = $this->db->getOne($query); if (DB::isError($result)) { new DB_Error($result->code, PEAR_ERROR_DIE); return false; } if (0 == intval($result)) { // Insert new row into table $query = sprintf("INSERT INTO %s (id, expiry, data) VALUES (%s, %d, %s)", $this->options['table'], $this->db->quoteSmart(md5($id)), time() + ini_get('session.gc_maxlifetime'), $this->db->quoteSmart($data)); } else { // Update existing row $query = sprintf("UPDATE %s SET expiry = %d, data = %s WHERE id = %s", $this->options['table'], time() + ini_get('session.gc_maxlifetime'), $this->db->quoteSmart($data), $this->db->quoteSmart(md5($id))); } } $result = $this->db->query($query); if (DB::isError($result)) { new DB_Error($result->code, PEAR_ERROR_DIE); return false; } return true; } /** * Destroy session data * * @param string $id Session id * * @return void */ function destroy($id) { $query = sprintf("DELETE FROM %s WHERE id = %s", $this->options['table'], $this->db->quoteSmart(md5($id))); $result = $this->db->query($query); if (DB::isError($result)) { new DB_Error($result->code, PEAR_ERROR_DIE); return false; } return true; } /** * Replicate session data to table specified in option 'replicateBeforeDestroy' * * @param string $targetTable Table to replicate to * @param string $id Id of record to replicate * * @access private * @return bool */ function replicate($targetTable, $id = null) { if (is_null($id)) { $id = HTTP_Session::id(); } // Check if table row already exists $query = sprintf("SELECT COUNT(id) FROM %s WHERE id = %s", $targetTable, $this->db->quoteSmart(md5($id))); $result = $this->db->getOne($query); if (DB::isError($result)) { new DB_Error($result->code, PEAR_ERROR_DIE); return false; } // Insert new row into dest table if (0 == intval($result)) { $query = sprintf("INSERT INTO %s SELECT * FROM %s WHERE id = %s", $targetTable, $this->options['table'], $this->db->quoteSmart(md5($id))); } else { // Update existing row $query = sprintf("UPDATE %s dst, %s src SET dst.expiry = src.expiry, dst.data = src.data WHERE dst.id = src.id AND src.id = %s", $targetTable, $this->options['table'], $this->db->quoteSmart(md5($id))); } $result = $this->db->query($query); if (DB::isError($result)) { new DB_Error($result->code, PEAR_ERROR_DIE); return false; } return true; } /** * Garbage collection * * @param int $maxlifetime Maximum lifetime * * @return bool */ function gc($maxlifetime) { $query = sprintf("DELETE FROM %s WHERE expiry < %d", $this->options['table'], time()); $result = $this->db->query($query); if (DB::isError($result)) { new DB_Error($result->code, PEAR_ERROR_DIE); return false; } if ($this->options['autooptimize']) { switch($this->db->phptype) { case 'mysql': $query = sprintf("OPTIMIZE TABLE %s", $this->options['table']); break; case 'pgsql': $query = sprintf("VACUUM %s", $this->options['table']); break; default: $query = null; break; } if (isset($query)) { $result = $this->db->query($query); if (DB::isError($result)) { new DB_Error($result->code, PEAR_ERROR_DIE); return false; } } } return true; } } ?>