\Symfony\Component\HttpFoundation\Session\Storage\HandlerPdoSessionHandler

Session handler using a PDO connection to read and write data.

It works with MySQL, PostgreSQL, Oracle, SQL Server and SQLite and implements different locking strategies to handle concurrent access to the same session. Locking is necessary to prevent loss of data due to race conditions and to keep the session data consistent between read() and write(). With locking, requests for the same session will wait until the other one finished writing. For this reason it's best practice to close a session as early as possible to improve concurrency. PHPs internal files session handler also implements locking.

Attention: Since SQLite does not support row level locks but locks the whole database, it means only one session can be accessed at a time. Even different sessions would wait for another to finish. So saving session in SQLite should only be considered for development or prototypes.

Session data is a binary string that can contain non-printable characters like the null byte. For this reason it must be saved in a binary column in the database like BLOB in MySQL. Saving it in a character column could corrupt the data. You can use createTable() to initialize a correctly defined table.

Summary

Methods
Properties
Constants
open()
validateId()
read()
write()
destroy()
__construct()
createTable()
isSessionExpired()
gc()
updateTimestamp()
close()
No public properties found
LOCK_NONE
LOCK_ADVISORY
LOCK_TRANSACTIONAL
MAX_LIFETIME
doRead()
doWrite()
doDestroy()
getConnection()
No protected properties found
N/A
connect()
buildDsnFromUrl()
beginTransaction()
commit()
rollback()
doAdvisoryLock()
convertStringToInt()
getSelectSql()
getInsertStatement()
getUpdateStatement()
getMergeStatement()
$sessionName
$prefetchId
$prefetchData
$newSessionId
$igbinaryEmptyData
$pdo
$dsn
$driver
$table
$idCol
$dataCol
$lifetimeCol
$timeCol
$username
$password
$connectionOptions
$lockMode
$unlockStatements
$sessionExpired
$inTransaction
$gcCalled
N/A

Constants

LOCK_NONE

LOCK_NONE = 0

No locking is done. This means sessions are prone to loss of data due to race conditions of concurrent requests to the same session. The last session write will win in this case. It might be useful when you implement your own logic to deal with this like an optimistic approach.

LOCK_ADVISORY

LOCK_ADVISORY = 1

Creates an application-level lock on a session. The disadvantage is that the lock is not enforced by the database and thus other, unaware parts of the application could still concurrently modify the session. The advantage is it does not require a transaction.

This mode is not available for SQLite and not yet implemented for oci and sqlsrv.

LOCK_TRANSACTIONAL

LOCK_TRANSACTIONAL = 2

Issues a real row lock. Since it uses a transaction between opening and closing a session, you have to be careful when you use same database connection that you also use for your application logic. This mode is the default because it's the only reliable solution across DBMSs.

MAX_LIFETIME

MAX_LIFETIME = 315576000

Properties

$sessionName

$sessionName

$prefetchId

$prefetchId

$prefetchData

$prefetchData

$newSessionId

$newSessionId

$igbinaryEmptyData

$igbinaryEmptyData

$pdo

$pdo : \PDO|null

Type

PDO|null — PDO instance or null when not connected yet

$dsn

$dsn : string|false|null

DSN string or null for session.save_path or false when lazy connection disabled.

Type

string|false|null

$table

$table : string

Type

string

$idCol

$idCol : string

Type

string

$dataCol

$dataCol : string

Type

string

$lifetimeCol

$lifetimeCol : string

Type

string

$timeCol

$timeCol : string

Type

string

$username

$username : string

Username when lazy-connect.

Type

string

$password

$password : string

Password when lazy-connect.

Type

string

$connectionOptions

$connectionOptions : array

Connection options when lazy-connect.

Type

array

$lockMode

$lockMode : int

The strategy for locking, see constants.

Type

int

$unlockStatements

$unlockStatements : \PDOStatement[]

It's an array to support multiple reads before closing which is manual, non-standard usage.

Type

PDOStatement[] — An array of statements to release advisory locks

$sessionExpired

$sessionExpired : bool

True when the current session exists but expired according to session.gc_maxlifetime.

Type

bool

$inTransaction

$inTransaction : bool

Whether a transaction is active.

Type

bool

$gcCalled

$gcCalled : bool

Whether gc() has been called.

Type

bool

Methods

open()

open(mixed  $savePath, mixed  $sessionName) : bool

Parameters

mixed $savePath
mixed $sessionName

Returns

bool —

validateId()

validateId(mixed  $sessionId) : bool

Parameters

mixed $sessionId

Returns

bool —

read()

read(mixed  $sessionId) : string

Parameters

mixed $sessionId

Returns

string —

write()

write(mixed  $sessionId, mixed  $data) : bool

Parameters

mixed $sessionId
mixed $data

Returns

bool —

destroy()

destroy(mixed  $sessionId) : bool

Parameters

mixed $sessionId

Returns

bool —

__construct()

__construct(\PDO|string|null  $pdoOrDsn = null, array  $options = []) : mixed

You can either pass an existing database connection as PDO instance or pass a DSN string that will be used to lazy-connect to the database when the session is actually used. Furthermore it's possible to pass null which will then use the session.save_path ini setting as PDO DSN parameter.

List of available options:

  • db_table: The name of the table [default: sessions]
  • db_id_col: The column where to store the session id [default: sess_id]
  • db_data_col: The column where to store the session data [default: sess_data]
  • db_lifetime_col: The column where to store the lifetime [default: sess_lifetime]
  • db_time_col: The column where to store the timestamp [default: sess_time]
  • db_username: The username when lazy-connect [default: '']
  • db_password: The password when lazy-connect [default: '']
  • db_connection_options: An array of driver-specific connection options [default: []]
  • lock_mode: The strategy for locking, see constants [default: LOCK_TRANSACTIONAL]

Parameters

\PDO|string|null $pdoOrDsn

A \PDO instance or DSN string or URL string or null

array $options

Throws

\InvalidArgumentException

When PDO error mode is not PDO::ERRMODE_EXCEPTION

Returns

mixed —

createTable()

createTable() : mixed

Creates the table to store sessions which can be called once for setup.

Session ID is saved in a column of maximum length 128 because that is enough even for a 512 bit configured session.hash_function like Whirlpool. Session data is saved in a BLOB. One could also use a shorter inlined varbinary column if one was sure the data fits into it.

Throws

\PDOException

When the table already exists

\DomainException

When an unsupported PDO driver is used

Returns

mixed —

isSessionExpired()

isSessionExpired() : bool

Returns true when the current session exists but expired according to session.gc_maxlifetime.

Can be used to distinguish between a new session and one that expired due to inactivity.

Returns

bool —

gc()

gc(mixed  $maxlifetime) : int|false

Parameters

mixed $maxlifetime

Returns

int|false —

updateTimestamp()

updateTimestamp(mixed  $sessionId, mixed  $data) : bool

Parameters

mixed $sessionId
mixed $data

Returns

bool —

close()

close() : bool

Returns

bool —

doRead()

doRead(string  $sessionId) : string

Reads the session data in respect to the different locking strategies.

We need to make sure we do not return session data that is already considered garbage according to the session.gc_maxlifetime setting because gc() is called after read() and only sometimes.

Parameters

string $sessionId

Returns

string —

doWrite()

doWrite(string  $sessionId, string  $data) : bool

Parameters

string $sessionId
string $data

Returns

bool —

doDestroy()

doDestroy(string  $sessionId) : bool

Parameters

string $sessionId

Returns

bool —

getConnection()

getConnection() : \PDO

Return a PDO instance.

Returns

\PDO —

connect()

connect(string  $dsn) : void

Lazy-connects to the database.

Parameters

string $dsn

buildDsnFromUrl()

buildDsnFromUrl(string  $dsnOrUrl) : string

Builds a PDO DSN from a URL-like connection string.

Parameters

string $dsnOrUrl

Returns

string —

beginTransaction()

beginTransaction() : void

Helper method to begin a transaction.

Since SQLite does not support row level locks, we have to acquire a reserved lock on the database immediately. Because of https://bugs.php.net/42766 we have to create such a transaction manually which also means we cannot use PDO::commit or PDO::rollback or PDO::inTransaction for SQLite.

Also MySQLs default isolation, REPEATABLE READ, causes deadlock for different sessions due to https://percona.com/blog/2013/12/12/one-more-innodb-gap-lock-to-avoid/ . So we change it to READ COMMITTED.

commit()

commit() : void

Helper method to commit a transaction.

rollback()

rollback() : void

Helper method to rollback a transaction.

doAdvisoryLock()

doAdvisoryLock(string  $sessionId) : \PDOStatement

Executes an application-level lock on the database.

Parameters

string $sessionId

Throws

\DomainException

When an unsupported PDO driver is used

Returns

\PDOStatement —

The statement that needs to be executed later to release the lock

convertStringToInt()

convertStringToInt(string  $string) : int

Encodes the first 4 (when PHP_INT_SIZE == 4) or 8 characters of the string as an integer.

Keep in mind, PHP integers are signed.

Parameters

string $string

Returns

int —

getSelectSql()

getSelectSql() : string

Return a locking or nonlocking SQL query to read session information.

Throws

\DomainException

When an unsupported PDO driver is used

Returns

string —

getInsertStatement()

getInsertStatement(string  $sessionId, string  $sessionData, int  $maxlifetime) : \PDOStatement

Returns an insert statement supported by the database for writing session data.

Parameters

string $sessionId
string $sessionData
int $maxlifetime

Returns

\PDOStatement —

getUpdateStatement()

getUpdateStatement(string  $sessionId, string  $sessionData, int  $maxlifetime) : \PDOStatement

Returns an update statement supported by the database for writing session data.

Parameters

string $sessionId
string $sessionData
int $maxlifetime

Returns

\PDOStatement —

getMergeStatement()

getMergeStatement(string  $sessionId, string  $data, int  $maxlifetime) : ?\PDOStatement

Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data.

Parameters

string $sessionId
string $data
int $maxlifetime

Returns

?\PDOStatement —