Reputation: 9082
When storing sessions in a database, I have noticed that updating a session does not necessarily invoke the write function that was set in session_set_save_handler(). This problem seems to be solved when you call session_write_close() at the end of the script.
Am I missing something or is this indeed what needs to be done when storing sessions in a database using session_set_save_handler()?
The code that I am currently using.
// EXECUTE AT START OF SCRIPT
$session = new Session();
session_start();
Session Class
public function __construct() {
$database = Database::instance();
$this->dbh = $database->dbh();
$this->lifetime = get_cfg_var('session.gc_maxlifetime');
session_set_save_handler(
array(&$this, 'open'),
array(&$this, 'close'),
array(&$this, 'read'),
array(&$this, 'write'),
array(&$this, 'destroy'),
array(&$this, 'clean')
);
}
// SESSION HANDLER METHODS
function open($savePath, $sessionName) {
return true;
}
function close() {
return true;
}
function read($sessionUuid) {
logMessage('READ SESSION DATA > ' . $sessionUuid);
$data = array();
$time = time();
$sth = $this->dbh->prepare("SELECT sessionData FROM phpSession WHERE sessionUuid = :sessionUuid AND expires > " . $time);
$sth->setFetchMode(PDO::FETCH_ASSOC);
try {
$sth->execute(array('sessionUuid' => $sessionUuid));
if ($sth->rowCount() == 1) {
$row = $sth->fetch();
$data = $row['sessionData'];
}
} catch (PDOException $exception) {
// HANDLE EXCEPTION
}
return $data;
}
function write($sessionUuid, $sessionData) {
logMessage('WRITE SESSION DATA > ' . $sessionUuid);
$time = time() + $this->lifetime;
$sth1 = $this->dbh->prepare("SELECT sessionUuid FROM phpSession WHERE sessionUuid = :sessionUuid");
try {
$sth1->execute(array('sessionUuid' => $sessionUuid));
$query = '';
$data = array(
'sessionUuid' => $sessionUuid,
'sessionData' => $sessionData,
'expires' => $time
);
if ($sth1->rowCount() == 1) {
// UPDATE
$query = "UPDATE phpSession SET sessionUuid = :sessionUuid, sessionData = :sessionData, expires = :expires";
} else {
// INSERT
$query = "INSERT INTO phpSession (sessionUuid, sessionData, expires) VALUES (:sessionUuid, :sessionData, :expires)";
}
$sth2 = $this->dbh->prepare($query);
try {
$sth2->execute($data);
} catch (PDOException $exception) {
// HANDLE EXCEPTION
}
} catch (PDOException $exception) {
// HANDLE EXCEPTION
}
return true;
}
function destroy($sessionUuid) {
$sth = $this->dbh->prepare("DELETE FROM phpSession WHERE 'sessionUuid' = :sessionUuid");
try {
$sth->execute(array('sessionUuid' => $sessionUuid));
} catch (PDOException $exception) {
// HANDLE EXCEPTION
}
return true;
}
function clean() {
$sth = $this->dbh->prepare("DELETE FROM phpSession WHERE 'expires' < UNIX_TIMESTAMP()");
try {
$sth->execute();
} catch (PDOException $exception) {
// HANDLE EXCEPTION
}
return true;
}
Upvotes: 0
Views: 263
Reputation: 1647
For PHP < 5.4 you need to register session_write_close()
as a shutdown function, so that the database write happens before the script execution cycle ends.
register_shutdown_function('session_write_close');
Upvotes: 2
Reputation: 5174
According to http://php.net/manual/en/function.session-write-close.php
Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time.
Locking is usually the reason for not having your session written. This might happen in framed pages (as the documentation states) or in lengthy ajax requests where more than one request happens simultaneously.
Upvotes: 3