Skip to content

Commit 0f0a6e8

Browse files
committed
PdoSessionHandler: fix advisory lock for pgsql when session.sid_bits_per_character > 4
1 parent e4d9bfd commit 0f0a6e8

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,11 @@ private function doAdvisoryLock($sessionId)
580580
return $releaseStmt;
581581
case 'pgsql':
582582
// Obtaining an exclusive session level advisory lock requires an integer key.
583-
// So we convert the HEX representation of the session id to an integer.
584-
// Since integers are signed, we have to skip one hex char to fit in the range.
585-
if (4 === PHP_INT_SIZE) {
586-
$sessionInt1 = hexdec(substr($sessionId, 0, 7));
587-
$sessionInt2 = hexdec(substr($sessionId, 7, 7));
583+
// When session.sid_bits_per_character > 4, the session id can contain non-hex-characters.
584+
// So we cannot just use hexdec().
585+
if (4 === \PHP_INT_SIZE) {
586+
$sessionInt1 = $this->convertStringToInt($sessionId);
587+
$sessionInt2 = $this->convertStringToInt(substr($sessionId, 4, 4));
588588

589589
$stmt = $this->pdo->prepare('SELECT pg_advisory_lock(:key1, :key2)');
590590
$stmt->bindValue(':key1', $sessionInt1, \PDO::PARAM_INT);
@@ -595,7 +595,7 @@ private function doAdvisoryLock($sessionId)
595595
$releaseStmt->bindValue(':key1', $sessionInt1, \PDO::PARAM_INT);
596596
$releaseStmt->bindValue(':key2', $sessionInt2, \PDO::PARAM_INT);
597597
} else {
598-
$sessionBigInt = hexdec(substr($sessionId, 0, 15));
598+
$sessionBigInt = $this->convertStringToInt($sessionId);
599599

600600
$stmt = $this->pdo->prepare('SELECT pg_advisory_lock(:key)');
601601
$stmt->bindValue(':key', $sessionBigInt, \PDO::PARAM_INT);
@@ -613,6 +613,27 @@ private function doAdvisoryLock($sessionId)
613613
}
614614
}
615615

616+
/**
617+
* Encodes the first 4 (when PHP_INT_SIZE == 4) or 8 characters of the string as an integer.
618+
*
619+
* Keep in mind, PHP integers are signed.
620+
*
621+
* @param string $string
622+
*
623+
* @return int
624+
*/
625+
private function convertStringToInt($string)
626+
{
627+
if (4 === \PHP_INT_SIZE) {
628+
return (ord($string[3]) << 24) + (ord($string[2]) << 16) + (ord($string[1]) << 8) + ord($string[0]);
629+
}
630+
631+
$int1 = (ord($string[7]) << 24) + (ord($string[6]) << 16) + (ord($string[5]) << 8) + ord($string[4]);
632+
$int2 = (ord($string[3]) << 24) + (ord($string[2]) << 16) + (ord($string[1]) << 8) + ord($string[0]);
633+
634+
return $int2 + ($int1 << 32);
635+
}
636+
616637
/**
617638
* Return a locking or nonlocking SQL query to read session information.
618639
*

0 commit comments

Comments
 (0)