migration symfony 5 4 (#300)

* symfony 5.4 (diff dev)

* symfony 5.4 (working)

* symfony 5.4 (update autoload)

* symfony 5.4 (remove swiftmailer mailer implementation)

* symfony 5.4 (php doc and split Global accessor class)


### Impacted packages:

composer require php:">=7.2.5 <8.0.0" symfony/console:5.4.* symfony/dotenv:5.4.* symfony/framework-bundle:5.4.* symfony/twig-bundle:5.4.* symfony/yaml:5.4.* --update-with-dependencies

composer require symfony/stopwatch:5.4.* symfony/web-profiler-bundle:5.4.* --dev --update-with-dependencies
This commit is contained in:
bdalsass
2022-06-16 09:13:24 +02:00
committed by GitHub
parent abb13b70b9
commit 79da71ecf8
2178 changed files with 87439 additions and 59451 deletions

View File

@@ -46,7 +46,7 @@ class PdoSessionHandler extends AbstractSessionHandler
* write will win in this case. It might be useful when you implement your own
* logic to deal with this like an optimistic approach.
*/
const LOCK_NONE = 0;
public const LOCK_NONE = 0;
/**
* Creates an application-level lock on a session. The disadvantage is that the
@@ -55,7 +55,7 @@ class PdoSessionHandler extends AbstractSessionHandler
* does not require a transaction.
* This mode is not available for SQLite and not yet implemented for oci and sqlsrv.
*/
const LOCK_ADVISORY = 1;
public const LOCK_ADVISORY = 1;
/**
* Issues a real row lock. Since it uses a transaction between opening and
@@ -63,7 +63,9 @@ class PdoSessionHandler extends AbstractSessionHandler
* that you also use for your application logic. This mode is the default because
* it's the only reliable solution across DBMSs.
*/
const LOCK_TRANSACTIONAL = 2;
public const LOCK_TRANSACTIONAL = 2;
private const MAX_LIFETIME = 315576000;
/**
* @var \PDO|null PDO instance or null when not connected yet
@@ -71,57 +73,67 @@ class PdoSessionHandler extends AbstractSessionHandler
private $pdo;
/**
* @var string|false|null DSN string or null for session.save_path or false when lazy connection disabled
* DSN string or null for session.save_path or false when lazy connection disabled.
*
* @var string|false|null
*/
private $dsn = false;
/**
* @var string Database driver
* @var string|null
*/
private $driver;
/**
* @var string Table name
* @var string
*/
private $table = 'sessions';
/**
* @var string Column for session id
* @var string
*/
private $idCol = 'sess_id';
/**
* @var string Column for session data
* @var string
*/
private $dataCol = 'sess_data';
/**
* @var string Column for lifetime
* @var string
*/
private $lifetimeCol = 'sess_lifetime';
/**
* @var string Column for timestamp
* @var string
*/
private $timeCol = 'sess_time';
/**
* @var string Username when lazy-connect
* Username when lazy-connect.
*
* @var string
*/
private $username = '';
/**
* @var string Password when lazy-connect
* Password when lazy-connect.
*
* @var string
*/
private $password = '';
/**
* @var array Connection options when lazy-connect
* Connection options when lazy-connect.
*
* @var array
*/
private $connectionOptions = [];
/**
* @var int The strategy for locking, see constants
* The strategy for locking, see constants.
*
* @var int
*/
private $lockMode = self::LOCK_TRANSACTIONAL;
@@ -133,17 +145,23 @@ class PdoSessionHandler extends AbstractSessionHandler
private $unlockStatements = [];
/**
* @var bool True when the current session exists but expired according to session.gc_maxlifetime
* True when the current session exists but expired according to session.gc_maxlifetime.
*
* @var bool
*/
private $sessionExpired = false;
/**
* @var bool Whether a transaction is active
* Whether a transaction is active.
*
* @var bool
*/
private $inTransaction = false;
/**
* @var bool Whether gc() has been called
* Whether gc() has been called.
*
* @var bool
*/
private $gcCalled = false;
@@ -165,7 +183,6 @@ class PdoSessionHandler extends AbstractSessionHandler
* * lock_mode: The strategy for locking, see constants [default: LOCK_TRANSACTIONAL]
*
* @param \PDO|string|null $pdoOrDsn A \PDO instance or DSN string or URL string or null
* @param array $options An associative array of options
*
* @throws \InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
*/
@@ -178,21 +195,21 @@ class PdoSessionHandler extends AbstractSessionHandler
$this->pdo = $pdoOrDsn;
$this->driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
} elseif (\is_string($pdoOrDsn) && false !== strpos($pdoOrDsn, '://')) {
} elseif (\is_string($pdoOrDsn) && str_contains($pdoOrDsn, '://')) {
$this->dsn = $this->buildDsnFromUrl($pdoOrDsn);
} else {
$this->dsn = $pdoOrDsn;
}
$this->table = isset($options['db_table']) ? $options['db_table'] : $this->table;
$this->idCol = isset($options['db_id_col']) ? $options['db_id_col'] : $this->idCol;
$this->dataCol = isset($options['db_data_col']) ? $options['db_data_col'] : $this->dataCol;
$this->lifetimeCol = isset($options['db_lifetime_col']) ? $options['db_lifetime_col'] : $this->lifetimeCol;
$this->timeCol = isset($options['db_time_col']) ? $options['db_time_col'] : $this->timeCol;
$this->username = isset($options['db_username']) ? $options['db_username'] : $this->username;
$this->password = isset($options['db_password']) ? $options['db_password'] : $this->password;
$this->connectionOptions = isset($options['db_connection_options']) ? $options['db_connection_options'] : $this->connectionOptions;
$this->lockMode = isset($options['lock_mode']) ? $options['lock_mode'] : $this->lockMode;
$this->table = $options['db_table'] ?? $this->table;
$this->idCol = $options['db_id_col'] ?? $this->idCol;
$this->dataCol = $options['db_data_col'] ?? $this->dataCol;
$this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol;
$this->timeCol = $options['db_time_col'] ?? $this->timeCol;
$this->username = $options['db_username'] ?? $this->username;
$this->password = $options['db_password'] ?? $this->password;
$this->connectionOptions = $options['db_connection_options'] ?? $this->connectionOptions;
$this->lockMode = $options['lock_mode'] ?? $this->lockMode;
}
/**
@@ -238,6 +255,7 @@ class PdoSessionHandler extends AbstractSessionHandler
try {
$this->pdo->exec($sql);
$this->pdo->exec("CREATE INDEX EXPIRY ON $this->table ($this->lifetimeCol)");
} catch (\PDOException $e) {
$this->rollback();
@@ -250,7 +268,7 @@ class PdoSessionHandler extends AbstractSessionHandler
*
* Can be used to distinguish between a new session and one that expired due to inactivity.
*
* @return bool Whether current session expired
* @return bool
*/
public function isSessionExpired()
{
@@ -258,8 +276,9 @@ class PdoSessionHandler extends AbstractSessionHandler
}
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function open($savePath, $sessionName)
{
$this->sessionExpired = false;
@@ -272,8 +291,9 @@ class PdoSessionHandler extends AbstractSessionHandler
}
/**
* {@inheritdoc}
* @return string
*/
#[\ReturnTypeWillChange]
public function read($sessionId)
{
try {
@@ -286,21 +306,22 @@ class PdoSessionHandler extends AbstractSessionHandler
}
/**
* @return bool
* @return int|false
*/
#[\ReturnTypeWillChange]
public function gc($maxlifetime)
{
// We delay gc() to close() so that it is executed outside the transactional and blocking read-write process.
// This way, pruning expired sessions does not block them from being started while the current session is used.
$this->gcCalled = true;
return true;
return 0;
}
/**
* {@inheritdoc}
*/
protected function doDestroy($sessionId)
protected function doDestroy(string $sessionId)
{
// delete the record associated with this id
$sql = "DELETE FROM $this->table WHERE $this->idCol = :id";
@@ -321,7 +342,7 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* {@inheritdoc}
*/
protected function doWrite($sessionId, $data)
protected function doWrite(string $sessionId, string $data)
{
$maxlifetime = (int) ini_get('session.gc_maxlifetime');
@@ -348,7 +369,7 @@ class PdoSessionHandler extends AbstractSessionHandler
$insertStmt->execute();
} catch (\PDOException $e) {
// Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys
if (0 === strpos($e->getCode(), '23')) {
if (str_starts_with($e->getCode(), '23')) {
$updateStmt->execute();
} else {
throw $e;
@@ -365,18 +386,19 @@ class PdoSessionHandler extends AbstractSessionHandler
}
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function updateTimestamp($sessionId, $data)
{
$maxlifetime = (int) ini_get('session.gc_maxlifetime');
$expiry = time() + (int) ini_get('session.gc_maxlifetime');
try {
$updateStmt = $this->pdo->prepare(
"UPDATE $this->table SET $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id"
"UPDATE $this->table SET $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id"
);
$updateStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$updateStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
$updateStmt->bindParam(':expiry', $expiry, \PDO::PARAM_INT);
$updateStmt->bindValue(':time', time(), \PDO::PARAM_INT);
$updateStmt->execute();
} catch (\PDOException $e) {
@@ -389,8 +411,9 @@ class PdoSessionHandler extends AbstractSessionHandler
}
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function close()
{
$this->commit();
@@ -403,19 +426,27 @@ class PdoSessionHandler extends AbstractSessionHandler
$this->gcCalled = false;
// delete the session records that have expired
if ('mysql' === $this->driver) {
$sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol < :time";
} else {
$sql = "DELETE FROM $this->table WHERE $this->lifetimeCol < :time - $this->timeCol";
}
$sql = "DELETE FROM $this->table WHERE $this->lifetimeCol < :time AND $this->lifetimeCol > :min";
$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->bindValue(':min', self::MAX_LIFETIME, \PDO::PARAM_INT);
$stmt->execute();
// to be removed in 6.0
if ('mysql' === $this->driver) {
$legacySql = "DELETE FROM $this->table WHERE $this->lifetimeCol <= :min AND $this->lifetimeCol + $this->timeCol < :time";
} else {
$legacySql = "DELETE FROM $this->table WHERE $this->lifetimeCol <= :min AND $this->lifetimeCol < :time - $this->timeCol";
}
$stmt = $this->pdo->prepare($legacySql);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->bindValue(':min', self::MAX_LIFETIME, \PDO::PARAM_INT);
$stmt->execute();
}
if (false !== $this->dsn) {
$this->pdo = null; // only close lazy-connection
$this->driver = null;
}
return true;
@@ -423,10 +454,8 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Lazy-connects to the database.
*
* @param string $dsn DSN string
*/
private function connect($dsn)
private function connect(string $dsn): void
{
$this->pdo = new \PDO($dsn, $this->username, $this->password, $this->connectionOptions);
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
@@ -436,13 +465,9 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Builds a PDO DSN from a URL-like connection string.
*
* @param string $dsnOrUrl
*
* @return string
*
* @todo implement missing support for oci DSN (which look totally different from other PDO ones)
*/
private function buildDsnFromUrl($dsnOrUrl)
private function buildDsnFromUrl(string $dsnOrUrl): string
{
// (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid
$url = preg_replace('#^((?:pdo_)?sqlite3?):///#', '$1://localhost/', $dsnOrUrl);
@@ -476,17 +501,39 @@ class PdoSessionHandler extends AbstractSessionHandler
'sqlite3' => 'sqlite',
];
$driver = isset($driverAliasMap[$params['scheme']]) ? $driverAliasMap[$params['scheme']] : $params['scheme'];
$driver = $driverAliasMap[$params['scheme']] ?? $params['scheme'];
// Doctrine DBAL supports passing its internal pdo_* driver names directly too (allowing both dashes and underscores). This allows supporting the same here.
if (0 === strpos($driver, 'pdo_') || 0 === strpos($driver, 'pdo-')) {
if (str_starts_with($driver, 'pdo_') || str_starts_with($driver, 'pdo-')) {
$driver = substr($driver, 4);
}
$dsn = null;
switch ($driver) {
case 'mysql':
$dsn = 'mysql:';
if ('' !== ($params['query'] ?? '')) {
$queryParams = [];
parse_str($params['query'], $queryParams);
if ('' !== ($queryParams['charset'] ?? '')) {
$dsn .= 'charset='.$queryParams['charset'].';';
}
if ('' !== ($queryParams['unix_socket'] ?? '')) {
$dsn .= 'unix_socket='.$queryParams['unix_socket'].';';
if (isset($params['path'])) {
$dbName = substr($params['path'], 1); // Remove the leading slash
$dsn .= 'dbname='.$dbName.';';
}
return $dsn;
}
}
// If "unix_socket" is not in the query, we continue with the same process as pgsql
// no break
case 'pgsql':
$dsn = $driver.':';
$dsn ?? $dsn = 'pgsql:';
if (isset($params['host']) && '' !== $params['host']) {
$dsn .= 'host='.$params['host'].';';
@@ -541,7 +588,7 @@ class PdoSessionHandler extends AbstractSessionHandler
* due to https://percona.com/blog/2013/12/12/one-more-innodb-gap-lock-to-avoid/ .
* So we change it to READ COMMITTED.
*/
private function beginTransaction()
private function beginTransaction(): void
{
if (!$this->inTransaction) {
if ('sqlite' === $this->driver) {
@@ -559,7 +606,7 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Helper method to commit a transaction.
*/
private function commit()
private function commit(): void
{
if ($this->inTransaction) {
try {
@@ -581,7 +628,7 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Helper method to rollback a transaction.
*/
private function rollback()
private function rollback(): void
{
// We only need to rollback if we are in a transaction. Otherwise the resulting
// error would hide the real problem why rollback was called. We might not be
@@ -603,11 +650,9 @@ class PdoSessionHandler extends AbstractSessionHandler
* 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.
*
* @param string $sessionId Session ID
*
* @return string The session data
* @return string
*/
protected function doRead($sessionId)
protected function doRead(string $sessionId)
{
if (self::LOCK_ADVISORY === $this->lockMode) {
$this->unlockStatements[] = $this->doAdvisoryLock($sessionId);
@@ -618,12 +663,17 @@ class PdoSessionHandler extends AbstractSessionHandler
$selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$insertStmt = null;
do {
while (true) {
$selectStmt->execute();
$sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM);
if ($sessionRows) {
if ($sessionRows[0][1] + $sessionRows[0][2] < time()) {
$expiry = (int) $sessionRows[0][1];
if ($expiry <= self::MAX_LIFETIME) {
$expiry += $sessionRows[0][2];
}
if ($expiry < time()) {
$this->sessionExpired = true;
return '';
@@ -648,7 +698,7 @@ class PdoSessionHandler extends AbstractSessionHandler
} catch (\PDOException $e) {
// Catch duplicate key error because other connection created the session already.
// It would only not be the case when the other connection destroyed the session.
if (0 === strpos($e->getCode(), '23')) {
if (str_starts_with($e->getCode(), '23')) {
// Retrieve finished session data written by concurrent connection by restarting the loop.
// We have to start a new transaction as a failed query will mark the current transaction as
// aborted in PostgreSQL and disallow further queries within it.
@@ -662,14 +712,12 @@ class PdoSessionHandler extends AbstractSessionHandler
}
return '';
} while (true);
}
}
/**
* Executes an application-level lock on the database.
*
* @param string $sessionId Session ID
*
* @return \PDOStatement The statement that needs to be executed later to release the lock
*
* @throws \DomainException When an unsupported PDO driver is used
@@ -678,7 +726,7 @@ class PdoSessionHandler extends AbstractSessionHandler
* - for oci using DBMS_LOCK.REQUEST
* - for sqlsrv using sp_getapplock with LockOwner = Session
*/
private function doAdvisoryLock($sessionId)
private function doAdvisoryLock(string $sessionId): \PDOStatement
{
switch ($this->driver) {
case 'mysql':
@@ -733,12 +781,8 @@ class PdoSessionHandler extends AbstractSessionHandler
* 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.
*
* @param string $string
*
* @return int
*/
private function convertStringToInt($string)
private function convertStringToInt(string $string): int
{
if (4 === \PHP_INT_SIZE) {
return (\ord($string[3]) << 24) + (\ord($string[2]) << 16) + (\ord($string[1]) << 8) + \ord($string[0]);
@@ -753,15 +797,14 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Return a locking or nonlocking SQL query to read session information.
*
* @return string The SQL string
*
* @throws \DomainException When an unsupported PDO driver is used
*/
private function getSelectSql()
private function getSelectSql(): string
{
if (self::LOCK_TRANSACTIONAL === $this->lockMode) {
$this->beginTransaction();
// selecting the time column should be removed in 6.0
switch ($this->driver) {
case 'mysql':
case 'oci':
@@ -782,32 +825,26 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Returns an insert statement supported by the database for writing session data.
*
* @param string $sessionId Session ID
* @param string $sessionData Encoded session data
* @param int $maxlifetime session.gc_maxlifetime
*
* @return \PDOStatement The insert statement
*/
private function getInsertStatement($sessionId, $sessionData, $maxlifetime)
private function getInsertStatement(string $sessionId, string $sessionData, int $maxlifetime): \PDOStatement
{
switch ($this->driver) {
case 'oci':
$data = fopen('php://memory', 'r+');
fwrite($data, $sessionData);
rewind($data);
$sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :lifetime, :time) RETURNING $this->dataCol into :data";
$sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :expiry, :time) RETURNING $this->dataCol into :data";
break;
default:
$data = $sessionData;
$sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
$sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time)";
break;
}
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$stmt->bindParam(':data', $data, \PDO::PARAM_LOB);
$stmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
$stmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
return $stmt;
@@ -815,32 +852,26 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Returns an update statement supported by the database for writing session data.
*
* @param string $sessionId Session ID
* @param string $sessionData Encoded session data
* @param int $maxlifetime session.gc_maxlifetime
*
* @return \PDOStatement The update statement
*/
private function getUpdateStatement($sessionId, $sessionData, $maxlifetime)
private function getUpdateStatement(string $sessionId, string $sessionData, int $maxlifetime): \PDOStatement
{
switch ($this->driver) {
case 'oci':
$data = fopen('php://memory', 'r+');
fwrite($data, $sessionData);
rewind($data);
$sql = "UPDATE $this->table SET $this->dataCol = EMPTY_BLOB(), $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id RETURNING $this->dataCol into :data";
$sql = "UPDATE $this->table SET $this->dataCol = EMPTY_BLOB(), $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id RETURNING $this->dataCol into :data";
break;
default:
$data = $sessionData;
$sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id";
$sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id";
break;
}
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$stmt->bindParam(':data', $data, \PDO::PARAM_LOB);
$stmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
$stmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
return $stmt;
@@ -848,18 +879,12 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data.
*
* @param string $sessionId Session ID
* @param string $data Encoded session data
* @param int $maxlifetime session.gc_maxlifetime
*
* @return \PDOStatement|null The merge statement or null when not supported
*/
private function getMergeStatement($sessionId, $data, $maxlifetime)
private function getMergeStatement(string $sessionId, string $data, int $maxlifetime): ?\PDOStatement
{
switch (true) {
case 'mysql' === $this->driver:
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time) ".
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)";
break;
case 'sqlsrv' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='):
@@ -870,10 +895,10 @@ class PdoSessionHandler extends AbstractSessionHandler
"WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;";
break;
case 'sqlite' === $this->driver:
$mergeSql = "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
$mergeSql = "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time)";
break;
case 'pgsql' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '9.5', '>='):
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time) ".
"ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)";
break;
default:
@@ -887,15 +912,15 @@ class PdoSessionHandler extends AbstractSessionHandler
$mergeStmt->bindParam(1, $sessionId, \PDO::PARAM_STR);
$mergeStmt->bindParam(2, $sessionId, \PDO::PARAM_STR);
$mergeStmt->bindParam(3, $data, \PDO::PARAM_LOB);
$mergeStmt->bindParam(4, $maxlifetime, \PDO::PARAM_INT);
$mergeStmt->bindValue(4, time() + $maxlifetime, \PDO::PARAM_INT);
$mergeStmt->bindValue(5, time(), \PDO::PARAM_INT);
$mergeStmt->bindParam(6, $data, \PDO::PARAM_LOB);
$mergeStmt->bindParam(7, $maxlifetime, \PDO::PARAM_INT);
$mergeStmt->bindValue(7, time() + $maxlifetime, \PDO::PARAM_INT);
$mergeStmt->bindValue(8, time(), \PDO::PARAM_INT);
} else {
$mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$mergeStmt->bindParam(':data', $data, \PDO::PARAM_LOB);
$mergeStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
$mergeStmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT);
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
}