@@ -65,6 +65,8 @@ class PdoSessionHandler extends AbstractSessionHandler
65
65
*/
66
66
const LOCK_TRANSACTIONAL = 2 ;
67
67
68
+ private const MAX_LIFETIME = 315576000 ;
69
+
68
70
/**
69
71
* @var \PDO|null PDO instance or null when not connected yet
70
72
*/
@@ -237,6 +239,7 @@ public function createTable()
237
239
238
240
try {
239
241
$ this ->pdo ->exec ($ sql );
242
+ $ this ->pdo ->exec ("CREATE INDEX EXPIRY ON $ this ->table ( $ this ->lifetimeCol ) " );
240
243
} catch (\PDOException $ e ) {
241
244
$ this ->rollback ();
242
245
@@ -368,14 +371,14 @@ protected function doWrite($sessionId, $data)
368
371
*/
369
372
public function updateTimestamp ($ sessionId , $ data )
370
373
{
371
- $ maxlifetime = (int ) ini_get ('session.gc_maxlifetime ' );
374
+ $ expiry = time () + (int ) ini_get ('session.gc_maxlifetime ' );
372
375
373
376
try {
374
377
$ updateStmt = $ this ->pdo ->prepare (
375
- "UPDATE $ this ->table SET $ this ->lifetimeCol = :lifetime , $ this ->timeCol = :time WHERE $ this ->idCol = :id "
378
+ "UPDATE $ this ->table SET $ this ->lifetimeCol = :expiry , $ this ->timeCol = :time WHERE $ this ->idCol = :id "
376
379
);
377
380
$ updateStmt ->bindParam (':id ' , $ sessionId , \PDO ::PARAM_STR );
378
- $ updateStmt ->bindParam (':lifetime ' , $ maxlifetime , \PDO ::PARAM_INT );
381
+ $ updateStmt ->bindParam (':expiry ' , $ expiry , \PDO ::PARAM_INT );
379
382
$ updateStmt ->bindValue (':time ' , time (), \PDO ::PARAM_INT );
380
383
$ updateStmt ->execute ();
381
384
} catch (\PDOException $ e ) {
@@ -402,14 +405,21 @@ public function close()
402
405
$ this ->gcCalled = false ;
403
406
404
407
// delete the session records that have expired
408
+ $ sql = "DELETE FROM $ this ->table WHERE $ this ->lifetimeCol < :time AND $ this ->lifetimeCol > :min " ;
409
+ $ stmt = $ this ->pdo ->prepare ($ sql );
410
+ $ stmt ->bindValue (':time ' , time (), \PDO ::PARAM_INT );
411
+ $ stmt ->bindValue (':min ' , self ::MAX_LIFETIME , \PDO ::PARAM_INT );
412
+ $ stmt ->execute ();
413
+ // to be removed in 6.0
405
414
if ('mysql ' === $ this ->driver ) {
406
- $ sql = "DELETE FROM $ this ->table WHERE $ this ->lifetimeCol + $ this ->timeCol < :time " ;
415
+ $ legacySql = "DELETE FROM $ this ->table WHERE $ this -> lifetimeCol <= :min AND $ this ->lifetimeCol + $ this ->timeCol < :time " ;
407
416
} else {
408
- $ sql = "DELETE FROM $ this ->table WHERE $ this ->lifetimeCol < :time - $ this ->timeCol " ;
417
+ $ legacySql = "DELETE FROM $ this ->table WHERE $ this -> lifetimeCol <= :min AND $ this ->lifetimeCol < :time - $ this ->timeCol " ;
409
418
}
410
419
411
- $ stmt = $ this ->pdo ->prepare ($ sql );
420
+ $ stmt = $ this ->pdo ->prepare ($ legacySql );
412
421
$ stmt ->bindValue (':time ' , time (), \PDO ::PARAM_INT );
422
+ $ stmt ->bindValue (':min ' , self ::MAX_LIFETIME , \PDO ::PARAM_INT );
413
423
$ stmt ->execute ();
414
424
}
415
425
@@ -616,7 +626,12 @@ protected function doRead($sessionId)
616
626
$ sessionRows = $ selectStmt ->fetchAll (\PDO ::FETCH_NUM );
617
627
618
628
if ($ sessionRows ) {
619
- if ($ sessionRows [0 ][1 ] + $ sessionRows [0 ][2 ] < time ()) {
629
+ $ expiry = (int ) $ sessionRows [0 ][1 ];
630
+ if ($ expiry <= self ::MAX_LIFETIME ) {
631
+ $ expiry += $ sessionRows [0 ][2 ];
632
+ }
633
+
634
+ if ($ expiry < time ()) {
620
635
$ this ->sessionExpired = true ;
621
636
622
637
return '' ;
@@ -747,6 +762,7 @@ private function getSelectSql(): string
747
762
if (self ::LOCK_TRANSACTIONAL === $ this ->lockMode ) {
748
763
$ this ->beginTransaction ();
749
764
765
+ // In the future, we should avoid selecting {$this->>timeCol} column
750
766
switch ($ this ->driver ) {
751
767
case 'mysql ' :
752
768
case 'oci ' :
@@ -775,18 +791,18 @@ private function getInsertStatement(string $sessionId, string $sessionData, int
775
791
$ data = fopen ('php://memory ' , 'r+ ' );
776
792
fwrite ($ data , $ sessionData );
777
793
rewind ($ data );
778
- $ sql = "INSERT INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, EMPTY_BLOB(), :lifetime , :time) RETURNING $ this ->dataCol into :data " ;
794
+ $ sql = "INSERT INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, EMPTY_BLOB(), :expiry , :time) RETURNING $ this ->dataCol into :data " ;
779
795
break ;
780
796
default :
781
797
$ data = $ sessionData ;
782
- $ sql = "INSERT INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, :data, :lifetime , :time) " ;
798
+ $ sql = "INSERT INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, :data, :expiry , :time) " ;
783
799
break ;
784
800
}
785
801
786
802
$ stmt = $ this ->pdo ->prepare ($ sql );
787
803
$ stmt ->bindParam (':id ' , $ sessionId , \PDO ::PARAM_STR );
788
804
$ stmt ->bindParam (':data ' , $ data , \PDO ::PARAM_LOB );
789
- $ stmt ->bindParam (':lifetime ' , $ maxlifetime , \PDO ::PARAM_INT );
805
+ $ stmt ->bindValue (':expiry ' , time () + $ maxlifetime , \PDO ::PARAM_INT );
790
806
$ stmt ->bindValue (':time ' , time (), \PDO ::PARAM_INT );
791
807
792
808
return $ stmt ;
@@ -802,18 +818,18 @@ private function getUpdateStatement(string $sessionId, string $sessionData, int
802
818
$ data = fopen ('php://memory ' , 'r+ ' );
803
819
fwrite ($ data , $ sessionData );
804
820
rewind ($ data );
805
- $ sql = "UPDATE $ this ->table SET $ this ->dataCol = EMPTY_BLOB(), $ this ->lifetimeCol = :lifetime , $ this ->timeCol = :time WHERE $ this ->idCol = :id RETURNING $ this ->dataCol into :data " ;
821
+ $ sql = "UPDATE $ this ->table SET $ this ->dataCol = EMPTY_BLOB(), $ this ->lifetimeCol = :expiry , $ this ->timeCol = :time WHERE $ this ->idCol = :id RETURNING $ this ->dataCol into :data " ;
806
822
break ;
807
823
default :
808
824
$ data = $ sessionData ;
809
- $ sql = "UPDATE $ this ->table SET $ this ->dataCol = :data, $ this ->lifetimeCol = :lifetime , $ this ->timeCol = :time WHERE $ this ->idCol = :id " ;
825
+ $ sql = "UPDATE $ this ->table SET $ this ->dataCol = :data, $ this ->lifetimeCol = :expiry , $ this ->timeCol = :time WHERE $ this ->idCol = :id " ;
810
826
break ;
811
827
}
812
828
813
829
$ stmt = $ this ->pdo ->prepare ($ sql );
814
830
$ stmt ->bindParam (':id ' , $ sessionId , \PDO ::PARAM_STR );
815
831
$ stmt ->bindParam (':data ' , $ data , \PDO ::PARAM_LOB );
816
- $ stmt ->bindParam (':lifetime ' , $ maxlifetime , \PDO ::PARAM_INT );
832
+ $ stmt ->bindValue (':expiry ' , time () + $ maxlifetime , \PDO ::PARAM_INT );
817
833
$ stmt ->bindValue (':time ' , time (), \PDO ::PARAM_INT );
818
834
819
835
return $ stmt ;
@@ -826,7 +842,7 @@ private function getMergeStatement(string $sessionId, string $data, int $maxlife
826
842
{
827
843
switch (true ) {
828
844
case 'mysql ' === $ this ->driver :
829
- $ mergeSql = "INSERT INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, :data, :lifetime , :time) " .
845
+ $ mergeSql = "INSERT INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, :data, :expiry , :time) " .
830
846
"ON DUPLICATE KEY UPDATE $ this ->dataCol = VALUES( $ this ->dataCol ), $ this ->lifetimeCol = VALUES( $ this ->lifetimeCol ), $ this ->timeCol = VALUES( $ this ->timeCol ) " ;
831
847
break ;
832
848
case 'sqlsrv ' === $ this ->driver && version_compare ($ this ->pdo ->getAttribute (\PDO ::ATTR_SERVER_VERSION ), '10 ' , '>= ' ):
@@ -837,10 +853,10 @@ private function getMergeStatement(string $sessionId, string $data, int $maxlife
837
853
"WHEN MATCHED THEN UPDATE SET $ this ->dataCol = ?, $ this ->lifetimeCol = ?, $ this ->timeCol = ?; " ;
838
854
break ;
839
855
case 'sqlite ' === $ this ->driver :
840
- $ mergeSql = "INSERT OR REPLACE INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, :data, :lifetime , :time) " ;
856
+ $ mergeSql = "INSERT OR REPLACE INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, :data, :expiry , :time) " ;
841
857
break ;
842
858
case 'pgsql ' === $ this ->driver && version_compare ($ this ->pdo ->getAttribute (\PDO ::ATTR_SERVER_VERSION ), '9.5 ' , '>= ' ):
843
- $ mergeSql = "INSERT INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, :data, :lifetime , :time) " .
859
+ $ mergeSql = "INSERT INTO $ this ->table ( $ this ->idCol , $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) VALUES (:id, :data, :expiry , :time) " .
844
860
"ON CONFLICT ( $ this ->idCol ) DO UPDATE SET ( $ this ->dataCol , $ this ->lifetimeCol , $ this ->timeCol ) = (EXCLUDED. $ this ->dataCol , EXCLUDED. $ this ->lifetimeCol , EXCLUDED. $ this ->timeCol ) " ;
845
861
break ;
846
862
default :
@@ -854,15 +870,15 @@ private function getMergeStatement(string $sessionId, string $data, int $maxlife
854
870
$ mergeStmt ->bindParam (1 , $ sessionId , \PDO ::PARAM_STR );
855
871
$ mergeStmt ->bindParam (2 , $ sessionId , \PDO ::PARAM_STR );
856
872
$ mergeStmt ->bindParam (3 , $ data , \PDO ::PARAM_LOB );
857
- $ mergeStmt ->bindParam (4 , $ maxlifetime , \PDO ::PARAM_INT );
858
- $ mergeStmt ->bindValue (5 , time (), \PDO ::PARAM_INT );
859
- $ mergeStmt ->bindParam (6 , $ data , \PDO ::PARAM_LOB );
860
- $ mergeStmt ->bindParam ( 7 , $ maxlifetime , \PDO ::PARAM_INT );
861
- $ mergeStmt ->bindValue (8 , time (), \PDO ::PARAM_INT );
873
+ $ mergeStmt ->bindValue (4 , time () + $ maxlifetime , \PDO ::PARAM_INT );
874
+ $ mergeStmt ->bindValue (4 , time (), \PDO ::PARAM_INT );
875
+ $ mergeStmt ->bindParam (5 , $ data , \PDO ::PARAM_LOB );
876
+ $ mergeStmt ->bindValue ( 6 , time () + $ maxlifetime , \PDO ::PARAM_INT );
877
+ $ mergeStmt ->bindValue (6 , time (), \PDO ::PARAM_INT );
862
878
} else {
863
879
$ mergeStmt ->bindParam (':id ' , $ sessionId , \PDO ::PARAM_STR );
864
880
$ mergeStmt ->bindParam (':data ' , $ data , \PDO ::PARAM_LOB );
865
- $ mergeStmt ->bindParam (':lifetime ' , $ maxlifetime , \PDO ::PARAM_INT );
881
+ $ mergeStmt ->bindValue (':expiry ' , time () + $ maxlifetime , \PDO ::PARAM_INT );
866
882
$ mergeStmt ->bindValue (':time ' , time (), \PDO ::PARAM_INT );
867
883
}
868
884
0 commit comments