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;
}
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.