Configuring Sessions and Save Handlers
Warning: You are browsing the documentation for Symfony 3.x, which is no longer maintained.
Consider upgrading your projects to Symfony 7.1.
This article deals with how to configure session management and fine tune it to your specific needs. This documentation covers save handlers, which store and retrieve session data, and configuring session behavior.
Save Handlers
The PHP session workflow has 6 possible operations that may occur. The normal
session follows open
, read
, write
and close
, with the possibility
of destroy
and gc
(garbage collection which will expire any old sessions:
gc
is called randomly according to PHP's configuration and if called, it is
invoked after the open
operation). You can read more about this at
php.net/session.customhandler
Native PHP Save Handlers
So-called native handlers, are save handlers which are either compiled into PHP or provided by PHP extensions, such as PHP-SQLite, PHP-Memcached and so on.
All native save handlers are internal to PHP and as such, have no public facing API.
They must be configured by php.ini
directives, usually session.save_path
and
potentially other driver specific directives. Specific details can be found in
the docblock of the setOptions()
method of each class. For instance, the one
provided by the Memcached extension can be found on php.net/memcached.setoption
While native save handlers can be activated by directly using
ini_set('session.save_handler', $name);
, Symfony provides a convenient way to
activate these in the same way as it does for custom handlers.
Symfony provides drivers for the following native save handler as an example:
Example usage:
1 2 3 4 5 6
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
$sessionStorage = new NativeSessionStorage([], new NativeFileSessionHandler());
$session = new Session($sessionStorage);
Note
With the exception of the files
handler which is built into PHP and
always available, the availability of the other handlers depends on those
PHP extensions being active at runtime.
Note
Native save handlers provide a quick solution to session storage, however, in complex systems where you need more control, custom save handlers may provide more freedom and flexibility. Symfony provides several implementations which you may further customize as required.
Custom Save Handlers
Custom handlers are those which completely replace PHP's built-in session save handlers by providing six callback functions which PHP calls internally at various points in the session workflow.
The Symfony HttpFoundation component provides some by default and these can serve as examples if you wish to write your own.
- PdoSessionHandler
- MemcacheSessionHandler
- MemcachedSessionHandler
- MongoDbSessionHandler
- NullSessionHandler
Example usage:
1 2 3 4 5 6 7
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
$pdo = new \PDO(...);
$sessionStorage = new NativeSessionStorage([], new PdoSessionHandler($pdo));
$session = new Session($sessionStorage);
Configuring PHP Sessions
The NativeSessionStorage
can configure most of the php.ini
configuration directives which are documented
at php.net/session.configuration.
To configure these settings, pass the keys (omitting the initial session.
part
of the key) as a key-value array to the $options
constructor argument.
Or set them via the
setOptions()
method.
For the sake of clarity, some key options are explained in this documentation.
Session Cookie Lifetime
For security, session tokens are generally recommended to be sent as session cookies.
You can configure the lifetime of session cookies by specifying the lifetime
(in seconds) using the cookie_lifetime
key in the constructor's $options
argument in NativeSessionStorage.
Setting a cookie_lifetime
to 0
will cause the cookie to live only as
long as the browser remains open. Generally, cookie_lifetime
would be set to
a relatively large number of days, weeks or months. It is not uncommon to set
cookies for a year or more depending on the application.
Since session cookies are just a client-side token, they are less important in controlling the fine details of your security settings which ultimately can only be securely controlled from the server side.
Note
The cookie_lifetime
setting is the number of seconds the cookie should live
for, it is not a Unix timestamp. The resulting session cookie will be stamped
with an expiry time of time()
+ cookie_lifetime
where the time is taken
from the server.
Configuring Garbage Collection
When a session opens, PHP will call the gc
handler randomly according to the
probability set by session.gc_probability
/ session.gc_divisor
. For
example if these were set to 5/100
respectively, it would mean a probability
of 5%. Similarly, 3/4
would mean a 3 in 4 chance of being called, i.e. 75%.
If the garbage collection handler is invoked, PHP will pass the value stored in
the php.ini
directive session.gc_maxlifetime
. The meaning in this context is
that any stored session that was saved more than gc_maxlifetime
ago should be
deleted. This allows one to expire records based on idle time.
However, some operating systems (e.g. Debian) do their own session handling and set
the session.gc_probability
variable to 0
to stop PHP doing garbage
collection. That's why Symfony now overwrites this value to 1
.
If you wish to use the original value set in your php.ini
, add the following
configuration:
1 2 3 4
# config.yml
framework:
session:
gc_probability: null
You can configure these settings by passing gc_probability
, gc_divisor
and gc_maxlifetime
in an array to the constructor of
NativeSessionStorage
or to the setOptions()
method.
Session Lifetime
When a new session is created, meaning Symfony issues a new session cookie
to the client, the cookie will be stamped with an expiry time. This is
calculated by adding the PHP runtime configuration value in
session.cookie_lifetime
with the current server time.
Note
PHP will only issue a cookie once. The client is expected to store that cookie
for the entire lifetime. A new cookie will only be issued when the session is
destroyed, the browser cookie is deleted, or the session ID is regenerated
using the migrate()
or invalidate()
methods of the Session
class.
The initial cookie lifetime can be set by configuring NativeSessionStorage
using the setOptions(['cookie_lifetime' => 1234])
method.
Note
A cookie lifetime of 0
means the cookie expires when the browser is closed.
Session Idle Time/Keep Alive
There are often circumstances where you may want to protect, or minimize
unauthorized use of a session when a user steps away from their terminal while
logged in by destroying the session after a certain period of idle time. For
example, it is common for banking applications to log the user out after just
5 to 10 minutes of inactivity. Setting the cookie lifetime here is not
appropriate because that can be manipulated by the client, so we must do the expiry
on the server side. The easiest way is to implement this via garbage collection
which runs reasonably frequently. The cookie_lifetime
would be set to a
relatively high value, and the garbage collection gc_maxlifetime
would be set
to destroy sessions at whatever the desired idle period is.
The other option is specifically check if a session has expired after the session is started. The session can be destroyed as required. This method of processing can allow the expiry of sessions to be integrated into the user experience, for example, by displaying a message.
Symfony records some basic metadata about each session to give you complete freedom in this area.
Session Cache Limiting
To avoid users seeing stale data, it's common for session-enabled resources to be
sent with headers that disable caching. For this purpose PHP Sessions has the
sessions.cache_limiter
option, which determines which headers, if any, will be
sent with the response when the session in started.
Upon construction,
NativeSessionStorage
sets this global option to ""
(send no headers) in case the developer wishes to
use a Response object to manage
response headers.
Caution
If you rely on PHP Sessions to manage HTTP caching, you must manually set the
cache_limiter
option in
NativeSessionStorage
to a non-empty value.
For example, you may set it to PHP's default value during construction:
Example usage:
1 2 3 4
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
$options['cache_limiter'] = session_cache_limiter();
$sessionStorage = new NativeSessionStorage($options);
Session Metadata
Sessions are decorated with some basic metadata to enable fine control over the security settings. The session object has a getter for the metadata, getMetadataBag() which exposes an instance of MetadataBag:
1 2
$session->getMetadataBag()->getCreated();
$session->getMetadataBag()->getLastUsed();
Both methods return a Unix timestamp (relative to the server).
This metadata can be used to explicitly expire a session on access, e.g.:
1 2 3 4 5
$session->start();
if (time() - $session->getMetadataBag()->getLastUsed() > $maxIdleTime) {
$session->invalidate();
throw new SessionExpired(); // redirect to expired session page
}
It is also possible to tell what the cookie_lifetime
was set to for a
particular cookie by reading the getLifetime()
method:
1
$session->getMetadataBag()->getLifetime();
The expiry time of the cookie can be determined by adding the created timestamp and the lifetime.
PHP 5.4 Compatibility
Since PHP 5.4.0, SessionHandler and SessionHandlerInterface are available. Symfony provides forward compatibility for the SessionHandlerInterface so it can be used under PHP 5.3. This greatly improves interoperability with other libraries.
SessionHandler is a special PHP internal class which exposes native save handlers to PHP user-space.
In order to provide a solution for those using PHP 5.4, Symfony has a special
class called NativeSessionHandler
which under PHP 5.4, extends from \SessionHandler
and under PHP 5.3 is just a
empty base class. This provides some interesting opportunities to leverage
PHP 5.4 functionality if it is available.
Save Handler Proxy
A Save Handler Proxy is basically a wrapper around a Save Handler that was introduced to seamlessly support the migration from PHP 5.3 to PHP 5.4+. It further creates an extension point from where custom logic can be added that works independently of which handler is being wrapped inside.
There are two kinds of save handler class proxies which inherit from AbstractProxy: they are NativeProxy and SessionHandlerProxy.
NativeSessionStorage automatically injects storage handlers into a save handler proxy unless already wrapped by one.
NativeProxy
is used automatically under PHP 5.3 when internal PHP save handlers are specified
using the Native*SessionHandler
classes, while
SessionHandlerProxy
will be used to wrap any custom save handlers, that implement SessionHandlerInterface.
From PHP 5.4 and above, all session handlers implement SessionHandlerInterface
including Native*SessionHandler
classes which inherit from SessionHandler.
The proxy mechanism allows you to get more deeply involved in session save handler classes. A proxy for example could be used to encrypt any session transaction without knowledge of the specific save handler.
Note
Before PHP 5.4, you can only proxy user-land save handlers but not native PHP save handlers.