Skip to content

Instantly share code, notes, and snippets.

@dimzon
Last active July 30, 2016 08:30
Show Gist options
  • Save dimzon/62eeb9b8561bcb9f0c6d to your computer and use it in GitHub Desktop.
Save dimzon/62eeb9b8561bcb9f0c6d to your computer and use it in GitHub Desktop.
Persisting PHP sessions into mongodb (allows NLB without affinity)
<?php
// all default values
MongoSessionPersistence::create()
->connect()
->register();
// connect to concrete server/db
MongoSessionPersistence::create()
->connect('mongodb://mongo_server:27017', 'databaseName')
->useLifeTime(60*60) // lifetime=1 hour
->register();
// use existing database connection
MongoSessionPersistence::create()
->useCollection($db->phpSessionStoreCollection)
->register();
?>
<?php
class MongoSessionPersistence implements SessionHandlerInterface
{
private $collection=null;
private $lifeTime;
public function register()
{
if(is_null($this->collection))
$this->connect();
$result = session_set_save_handler($this);
return $result;
}
public static function create(){
return new MongoSessionPersistence();
}
public function useLifeTime($lifetime){
$this->lifeTime = $lifetime;
return $this;
}
public function useCollection(MongoCollection $collection){
$this->collection = $collection;
$this->ensureIndex();
return $this;
}
public function connect($server = 'mongodb://localhost:21017',
$database = 'test',
$collection = 'php_session')
{
return $this->useCollection((new MongoClient($server))
->selectDB($database)->selectCollection($collection));
}
function __construct()
{
$this->lifeTime = intVal(get_cfg_var('session.gc_maxlifetime'));
}
/**
* PHP >= 5.4.0<br/>
* Close the session
* @link http://php.net/manual/en/sessionhandlerinterface.close.php
* @return bool <p>
* The return value (usually TRUE on success, FALSE on failure).
* Note this value is returned internally to PHP for processing.
* </p>
*/
public function close()
{
// do nothing
return true;
}
/**
* PHP >= 5.4.0<br/>
* Destroy a session
* @link http://php.net/manual/en/sessionhandlerinterface.destroy.php
* @param int $session_id The session ID being destroyed.
* @return bool <p>
* The return value (usually TRUE on success, FALSE on failure).
* Note this value is returned internally to PHP for processing.
* </p>
*/
public function destroy($session_id)
{
$this->collection->remove(['_id' => $session_id]);
return true;
}
/**
* PHP >= 5.4.0<br/>
* Cleanup old sessions
* @link http://php.net/manual/en/sessionhandlerinterface.gc.php
* @param int $maxlifetime <p>
* Sessions that have not updated for
* the last maxlifetime seconds will be removed.
* </p>
* @return bool <p>
* The return value (usually TRUE on success, FALSE on failure).
* Note this value is returned internally to PHP for processing.
* </p>
*/
public function gc($maxlifetime)
{
// do nothing, actual GC performed by MongoDB ttl index
return true;
}
/**
* PHP >= 5.4.0<br/>
* Initialize session
* @link http://php.net/manual/en/sessionhandlerinterface.open.php
* @param string $save_path The path where to store/retrieve the session.
* @param string $session_id The session id.
* @return bool <p>
* The return value (usually TRUE on success, FALSE on failure).
* Note this value is returned internally to PHP for processing.
* </p>
*/
public function open($save_path, $session_id)
{
// do nothing
return true;
}
/**
* PHP >= 5.4.0<br/>
* Read session data
* @link http://php.net/manual/en/sessionhandlerinterface.read.php
* @param string $session_id The session id to read data for.
* @return string <p>
* Returns an encoded string of the read data.
* If nothing was read, it must return an empty string.
* Note this value is returned internally to PHP for processing.
* </p>
*/
public function read($session_id)
{
$obj = $this->collection->findOne(['_id' => $session_id]);
if ($obj) {
$data = $obj['data'];
return $data->bin;
}
return '';
}
/**
* PHP >= 5.4.0<br/>
* Write session data
* @link http://php.net/manual/en/sessionhandlerinterface.write.php
* @param string $session_id The session id.
* @param string $session_data <p>
* The encoded session data. This data is the
* result of the PHP internally encoding
* the $_SESSION superglobal to a serialized
* string and passing it as this parameter.
* Please note sessions use an alternative serialization method.
* </p>
* @return bool <p>
* The return value (usually TRUE on success, FALSE on failure).
* Note this value is returned internally to PHP for processing.
* </p>
*/
public function write($session_id, $session_data)
{
// obtain proper time from mongodb server
$ts = $this->collection->db->command(['serverStatus' => 1
, 'globalLock' => 0
, 'metrics' => 0
, 'repl' => 0
, 'locks' => 0])['localTime'];
$ttl = new MongoDate($ts->sec + $this->lifeTime, $ts->usec);
$this->collection->save(['_id' => $session_id,
'data' => new MongoBinData($session_data),
'ttl' => $ttl]);
return true;
}
public function create_sid()
{
$id = new MongoId();
return "{$id}";
}
private function ensureIndex()
{
$this->collection->ensureIndex(['ttl' => 1], ['expireAfterSeconds' => 3600]); // +1 hour for sessions
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment