- No locking means extremely fast and non-blocking requests
- Auto-merge reduces the chance of data corruption and merge conflicts
- Ability to provide custom logic for resolving application-specific merge conflicts
- Supports Memcached and Redis out of the box, but easy to extend to other storage mechanisms
This library comes with session handlers for Memcached and Redis (both the PhpRedis extension and the PRedis library).
Step 1: Get a handler instanace. This part depends on what storage back-end you want to use.
<?php
use EduCom\SessionAutomerge\SessionhandlerMemcached;
use EduCom\SessionAutomerge\SessionhandlerPhpRedis;
use EduCom\SessionAutomerge\SessionhandlerPRedis;
// Memcached
$memcached = new Memcached;
$memcached->addServer('localhost', 11211);
$handler = new SessionhandlerMemcached($memcached);
// PhpRedis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$handler = new SessionhandlerPhpRedis($redis);
// PRedis
$client = new Predis\Client('tcp://10.0.0.1:6379');
$handler = new SessionhandlerPRedis($client);
Step 2: Set options if needed
// All options are public properties and have sensible defaults
// You can override any of them easily if desired.
$handler->ttl = 7200;
Step 3: Set the session handler
// 2nd parameter `true` means the session will auto-close
// at the end of the request if `session_close()` was not explicitly called
session_set_save_handler($handler, true);
ttl
- Number of seconds to keep a session active. Defaults to 3600 (1 hour)prefix
- A prefix to add to all session ids. Defaults tosession_
readonly
- If true, changes to$_SESSION
during the request will be ignored
Use HTTPS site-wide to protect your user's sessions. (check out https://letsencrypt.org/ for free SSL certificates).
Enable the following php.ini
settings for more security:
session.cookie_secure
- protects again session hijacking (Note: requires site-wide HTTPS)session.cookie_httponly
- protects against XSS attacks in some browserssession.use_strict_mode
- protects against session fixation attacks
Do not store objects in the session. Stick to primitive data types. This will reduce chances of future bugs and make your sessions portable
By default, data is run through serialize
before being passed to the storage backend.
If you extend a handler class, it's easy to customize the serialization behavior.
<?php
use EduCom\SessionAutomerge\SessionHandlerMemcached;
class MySessionHandler extends SessionHandlerMemcached {
public function serialize(array $data) {
return json_encode($data);
}
public function unserialize($string) {
return json_decode($string, true);
}
}
By default, if a merge conflict is encountered when saving the session, the latest value always takes precedence.
You can change this behavior and provide custom merge logic by extending a handler class resolveConflict
method. The method takes the following arguments:
$key
is the array key in$_SESSION
that has a conflict$initial
was the intial value of the key at the start of the current request.null
means the key did not exist.$new
is the new value of the key at the end of the current request.null
means the key was deleted.$external
is the latest value of the key from the database (set in a different request).null
means the key was deleted.
<?php
use EduCom\SessionAutomerge\SessionHandlerMemcached;
class MySessionHandler extends SessionHandlerMemcached {
public function resolveConflict($key, $initial, $new, $external) {
// Special handling for a known session key 'items_viewed'
if($key === 'items_viewed') {
// Get the new items added during this request
$items = array_diff($initial, $new);
// Merge these newly added items with the external change
$merged = array_merge($external, $items);
return $merged;
}
// Fall back to default resolution method
return parent::resolveConflict($key,$initial,$new,$external); // TODO: Change the autogenerated stub
}
}
If you want to use something other than Redis or Memcached, it's easy to extend the SessionHandlerBase
class.
At a minimum, you need to define the abstract methods set
, get
, and delete
.
If you need configuration parameters (e.g. database client, file path, etc.) you can create a __construct
method.
Here's a fully working example of storing sessions in the filesystem.
<?php
use EduCom\SessionAutomerge\SessionHandlerBase;
class FileSessionHandler extends SessionHandlerBase {
public $path = '/tmp/';
public function __construct($path='/tmp/') {
$this->path = $path;
}
public function set($key, array $session_data) {
// TODO: support ttl
$ttl = $this->ttl;
$serialized = $this->serialize($session_data);
file_put_contents($this->path.$key, $serialized);
return true;
}
public function get($key) {
$raw = file_get_contents($this->path.$key);
return $this->unserialize($raw);
}
public function delete($key) {
unlink($this->path.$key);
return true;
}
}
Most storage mechanisms won't need this, but you can define a gc
(garbage collection), open
, or close
method as well. These follow the same pattern as SessionHandlerInterface
.
Occasionally errors will happen (e.g. Memcached request fails due to network glitch).
All errors are handled gracefully to avoid data corruption.
In the case of an error, the errorLog
method will be called. By default it will just a trigger_error
call.
You can override the errorLog
method in a child class if needed (e.g. to tie into your application's monolog instance).