Created
November 2, 2010 06:23
-
-
Save brtriver/659318 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* MongoSessionStrage manages session storage via MongoDB | |
* | |
* This class stores the session data in via MongoDB and with an id issued in a | |
* signed cookie. Useful when you don't want to store the session. | |
* | |
* @package PHP | |
* @subpackage session | |
* @author Masao Maeda <[email protected]> | |
*/ | |
class MongoSessionStorage | |
{ | |
static protected | |
$sessionIdRegenerated = false, | |
$sessionStarted = false, | |
$db = null, | |
$col = null, | |
$options = array( | |
'db_name' => 'php_session', | |
'collection_name' => 'session', | |
'db_id_col' => 'sess_id', | |
'db_data_col' => 'sess_data', | |
'db_time_col' => 'sess_time', | |
'host' => 'localhost', | |
'port' => '27017', | |
); | |
/** | |
* Available options: | |
* | |
* * collection_name: The database table in which session data will be stored | |
* * db_name: The sfDatabase object to use | |
* * db_id_col: The database column in which the session id will be stored (sess_id by default) | |
* * db_data_col: The database column in which the session data will be stored (sess_data by default) | |
* * db_time_col: The database column in which the session timestamp will be stored (sess_time by default) | |
* | |
* @param array $options An associative array of options | |
* | |
*/ | |
static public function init($options = array()) | |
{ | |
self::$options = array_merge(self::$options, $options); | |
if (!isset(self::$options['db_name'])) | |
{ | |
throw new Exception('You must provide a "db_name" option to sfMongoSessionStorage.'); | |
} | |
if (!isset(self::$options['collection_name'])) | |
{ | |
throw new Exception('You must provide a "collection_name" option to sfMongoSessionStorage.'); | |
} | |
// use this object as the session handler | |
session_set_save_handler(array(__CLASS__, 'sessionOpen'), | |
array(__CLASS__, 'sessionClose'), | |
array(__CLASS__, 'sessionRead'), | |
array(__CLASS__, 'sessionWrite'), | |
array(__CLASS__, 'sessionDestroy'), | |
array(__CLASS__, 'sessionGC')); | |
// start our session | |
//session_start(); | |
} | |
/** | |
* Closes a session. | |
* | |
* @return boolean true, if the session was closed, otherwise false | |
*/ | |
static public function sessionClose() | |
{ | |
// do nothing | |
return true; | |
} | |
/** | |
* Opens a session. | |
* | |
* @param string $path (ignored) | |
* @param string $name (ignored) | |
* | |
* @return boolean true, if the session was opened, otherwise an exception is thrown | |
* | |
* @throws <b>Exception</b> If a connection with the database does not exist or cannot be created | |
*/ | |
static public function sessionOpen($path = null, $name = null) | |
{ | |
// what host and port are we using? | |
$host = self::$options['host']; | |
$port = self::$options['port']; | |
// what database are we using? | |
$db_name = self::$options['db_name']; | |
if (!class_exists('Mongo')) | |
{ | |
throw new Exception('Mongo class does not exist!'); | |
} | |
$mongo = new Mongo(sprintf("%s:%s", $host, $port)); | |
self::$db = $mongo->selectDB($db_name); | |
self::$col = self::$db->selectCollection(self::$options['collection_name']); | |
if (null === self::$db && null === self::$col) | |
{ | |
throw new Exception('MongoDB connection does not exist. Unable to open session.'); | |
} | |
return true; | |
} | |
/** | |
* Destroys a session. | |
* | |
* @param string $id A session ID | |
* | |
* @return bool true, if the session was destroyed, otherwise an exception is thrown | |
* | |
* @throws <b>Exception</b> If the session cannot be destroyed | |
*/ | |
static public function sessionDestroy($id) { | |
if (self::$col->remove(array(self::$options['db_id_col'] => $id))) | |
{ | |
return true; | |
} | |
$last_error = self::$db->lastError(); | |
throw new Exception(sprintf('%s cannot destroy session id "%s" (%s).', __CLASS__, $id, $last_error['err'])); | |
} | |
/** | |
* Cleans up old sessions. | |
* | |
* @param int $lifetime The lifetime of a session | |
* | |
* @return bool true, if old sessions have been cleaned, otherwise an exception is thrown | |
* | |
* @throws <b>Exception</b> If any old sessions cannot be cleaned | |
*/ | |
static public function sessionGC($lifetime) | |
{ | |
// get column | |
$db_time_col = self::$options['db_time_col']; | |
// delete the record older than the authorised session life time | |
if (self::$col->remove(array('$where' => sprintf('this.%s + %d < %d', $db_time_col, $lifetime, time())))) | |
{ | |
return true; | |
} | |
$last_error = self::$db->lastError(); | |
throw new Exception(sprintf('%s cannot delete old sessions (%s).', __CLASS__, $last_error['err'])); | |
} | |
/** | |
* Reads a session. | |
* | |
* @param string $id A session ID | |
* | |
* @return bool true, if the session was read, otherwise an exception is thrown | |
* | |
* @throws <b>Exception</b> If the session cannot be read | |
*/ | |
static public function sessionRead($id) | |
{ | |
// get column | |
$db_data_col = self::$options['db_data_col']; | |
$db_id_col = self::$options['db_id_col']; | |
$db_time_col = self::$options['db_time_col']; | |
$obj = self::$col->findOne(array(self::$options['db_id_col'] => $id)); | |
if (count($obj)) | |
{ | |
// found the session | |
return $obj[$db_data_col]; | |
} | |
else | |
{ | |
$obj = array( | |
$db_id_col => $id, | |
$db_data_col => '', | |
$db_time_col => time(), | |
); | |
// session does not exist, create it | |
if (self::$col->insert($obj)) | |
{ | |
//self::$col->ensureIndex(array($db_id_col => 1)); | |
return ''; | |
} | |
// can't create record | |
$last_error = self::$db->lastError(); | |
throw new Exception(sprintf('%s cannot create new record for id "%s" (%s).', __CLASS__, $id, $last_error['err'])); | |
} | |
} | |
/** | |
* Writes session data. | |
* | |
* @param string $id A session ID | |
* @param string $data A serialized chunk of session data | |
* | |
* @return bool true, if the session was written, otherwise an exception is thrown | |
* | |
* @throws <b>Exception</b> If the session data cannot be written | |
*/ | |
static public function sessionWrite($id, $data) | |
{ | |
// get column | |
$db_data_col = self::$options['db_data_col']; | |
$db_id_col = self::$options['db_id_col']; | |
$db_time_col = self::$options['db_time_col']; | |
// update the record associated with this id | |
$obj = array( | |
$db_id_col => $id, | |
$db_data_col => $data, | |
$db_time_col => time(), | |
); | |
if (self::$col->update(array($db_id_col => $id), $obj)) | |
{ | |
return true; | |
} | |
// failed to write session data | |
$last_error = self::$db->lastError(); | |
throw new Exception(sprintf('%s cannot write session data for id "%s" (%s).', __CLASS__, $id, $last_error['err'])); | |
} | |
/** | |
* Regenerates id that represents this storage. | |
* | |
* @param boolean $destroy Destroy session when regenerating? | |
* | |
* @return boolean True if session regenerated, false if error | |
* | |
*/ | |
static public function regenerate($destroy = false) | |
{ | |
if (self::$sessionIdRegenerated) | |
{ | |
return; | |
} | |
$currentId = session_id(); | |
// regenerate a new session id once per object | |
session_regenerate_id($destroy); | |
self::$sessionIdRegenerated = true; | |
$newId = session_id(); | |
self::sessionRead($newId); | |
return self::sessionWrite($newId, self::sessionRead($currentId)); | |
} | |
/** | |
* Executes the shutdown procedure. | |
* | |
*/ | |
static public function shutdown() | |
{ | |
session_write_close(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// simple tests | |
error_reporting(E_ALL); | |
ini_set('display_errors', 'On'); | |
echo "<h3>start test</h3>"; | |
try{ | |
// (1) include library | |
require_once dirname(__FILE__) . '/MongoSessionStorage.php'; | |
$options = array( | |
'db_name' => 'php_session', | |
'collection_name' => 'session', | |
'db_id_col' => 'sess_id', | |
'db_data_col' => 'sess_data', | |
'db_time_col' => 'sess_time', | |
'host' => 'localhost', | |
'port' => '27017', | |
); | |
MongoSessionStorage::init($options); | |
// (2) session start | |
if (!session_start()) throw new Exception('cannot start session'); | |
// (3) write to session | |
$hoge = 'red bull!'; | |
$_SESSION['test'] = $hoge; | |
if ($_SESSION['test'] !== $hoge) throw new Exception("cannot write/read session"); | |
// (4) regenerate session id | |
// TODO: If I set the first parameter to 'true', I cannot destory the session data from MongoDB... | |
$id = session_id(); | |
MongoSessionStorage::regenerate(); | |
if ($id === session_id()) throw new Exception("cannot re-generate session id"); | |
// (5) gc, in this teset, MongoDB data are cleaned up. | |
MongoSessionStorage::sessionGC(-10); | |
if (MongoSessionStorage::sessionRead(session_id()) !== "") throw new Exception("cannot run gc"); | |
} catch (Exception $e) { | |
echo "<div style='color:red;'><h4>Failure.</h4>"; | |
echo $e->getMessage(); | |
echo "</div>"; | |
} | |
echo "<h3>done.</h3>"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment