[Session] Fix the PDO handler for mysql concurrent write
This commit is contained in:
parent
e54f4e46c9
commit
b865b096b5
@ -164,27 +164,37 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
$dbIdCol = $this->dbOptions['db_id_col'];
|
$dbIdCol = $this->dbOptions['db_id_col'];
|
||||||
$dbTimeCol = $this->dbOptions['db_time_col'];
|
$dbTimeCol = $this->dbOptions['db_time_col'];
|
||||||
|
|
||||||
$sql = ('mysql' === $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME))
|
//session data can contain non binary safe characters so we need to encode it
|
||||||
? "INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time) "
|
$encoded = base64_encode($data);
|
||||||
."ON DUPLICATE KEY UPDATE $dbDataCol = VALUES($dbDataCol), $dbTimeCol = CASE WHEN $dbTimeCol = :time THEN (VALUES($dbTimeCol) + 1) ELSE VALUES($dbTimeCol) END"
|
|
||||||
: "UPDATE $dbTable SET $dbDataCol = :data, $dbTimeCol = :time WHERE $dbIdCol = :id";
|
|
||||||
|
|
||||||
try {
|
if ('mysql' === $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
|
||||||
//session data can contain non binary safe characters so we need to encode it
|
// MySQL would report $stmt->rowCount() = 0 on UPDATE when the data is left unchanged
|
||||||
$encoded = base64_encode($data);
|
// it could result in calling createNewSession() whereas the session already exists in
|
||||||
$stmt = $this->pdo->prepare($sql);
|
// the DB which would fail as the id is unique
|
||||||
|
$stmt = $this->pdo->prepare(
|
||||||
|
"INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time) " .
|
||||||
|
"ON DUPLICATE KEY UPDATE $dbDataCol = VALUES($dbDataCol), $dbTimeCol = VALUES($dbTimeCol)"
|
||||||
|
);
|
||||||
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
||||||
$stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
$stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
||||||
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$stmt = $this->pdo->prepare("UPDATE $dbTable SET $dbDataCol = :data, $dbTimeCol = :time WHERE $dbIdCol = :id");
|
||||||
|
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
||||||
|
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
if (!$stmt->rowCount()) {
|
if (!$stmt->rowCount()) {
|
||||||
// No session exists in the database to update. This happens when we have called
|
// No session exists in the database to update. This happens when we have called
|
||||||
// session_regenerate_id()
|
// session_regenerate_id()
|
||||||
$this->createNewSession($id, $data);
|
$this->createNewSession($id, $data);
|
||||||
|
}
|
||||||
|
} catch (\PDOException $e) {
|
||||||
|
throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
|
||||||
}
|
}
|
||||||
} catch (\PDOException $e) {
|
|
||||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
Reference in New Issue
Block a user