From 8a6d5e92d0070ea5584b077fa817ab07b0973d65 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Tue, 9 Jun 2026 22:10:39 +0200 Subject: [PATCH 1/8] fix: use dynamic lockMaxRetries limit in RedisHandler --- system/Session/Handlers/RedisHandler.php | 4 ++-- .../Handlers/Database/RedisHandlerTest.php | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index 4c8f78ba3894..4e9c4b0be037 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -386,10 +386,10 @@ protected function lockSession(string $sessionID): bool break; } while (++$attempt < $this->lockMaxRetries); - if ($attempt === 300) { + if ($attempt === $this->lockMaxRetries) { $this->logger->error( 'Session: Unable to obtain lock for ' . $this->keyPrefix . $sessionID - . ' after 300 attempts, aborting.', + . ' after ' . $this->lockMaxRetries . ' attempts, aborting.', ); return false; diff --git a/tests/system/Session/Handlers/Database/RedisHandlerTest.php b/tests/system/Session/Handlers/Database/RedisHandlerTest.php index 2e7821446fe3..c618f1b99c54 100644 --- a/tests/system/Session/Handlers/Database/RedisHandlerTest.php +++ b/tests/system/Session/Handlers/Database/RedisHandlerTest.php @@ -359,4 +359,26 @@ public function testResetPersistentConnections(): void $handler1->close(); $handler2->close(); } + + public function testLockMaxRetries(): void + { + $options = [ + 'lockWait' => 10_000, // 10ms + 'lockAttempts' => 3, + ]; + + $handler1 = $this->getInstance($options); + $handler1->open($this->sessionSavePath, $this->sessionName); + $handler1->read('lock_test_session'); // Acquires lock + + $handler2 = $this->getInstance($options); + $handler2->open($this->sessionSavePath, $this->sessionName); + + // Before the fix, this would incorrectly return true or empty string (since it falls through). + // With the fix, it should return false after 3 attempts. + $this->assertFalse($handler2->read('lock_test_session')); + + $handler1->close(); + $handler2->close(); + } } From 53540ce24e788dd555f6d97a03e31dc5d904f95f Mon Sep 17 00:00:00 2001 From: Bogdan Date: Tue, 9 Jun 2026 22:35:23 +0200 Subject: [PATCH 2/8] fix: read correct config property names in RedisHandler lockSession --- system/Session/Handlers/RedisHandler.php | 4 ++-- tests/system/Session/Handlers/Database/RedisHandlerTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index 4e9c4b0be037..5c8e098431b5 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -98,8 +98,8 @@ public function __construct(SessionConfig $config, string $ipAddress) $this->keyPrefix .= $this->ipAddress . ':'; } - $this->lockRetryInterval = $config->lockWait ?? $this->lockRetryInterval; - $this->lockMaxRetries = $config->lockAttempts ?? $this->lockMaxRetries; + $this->lockRetryInterval = $config->lockRetryInterval; + $this->lockMaxRetries = $config->lockMaxRetries; } protected function setSavePath(): void diff --git a/tests/system/Session/Handlers/Database/RedisHandlerTest.php b/tests/system/Session/Handlers/Database/RedisHandlerTest.php index c618f1b99c54..375a6c523911 100644 --- a/tests/system/Session/Handlers/Database/RedisHandlerTest.php +++ b/tests/system/Session/Handlers/Database/RedisHandlerTest.php @@ -363,8 +363,8 @@ public function testResetPersistentConnections(): void public function testLockMaxRetries(): void { $options = [ - 'lockWait' => 10_000, // 10ms - 'lockAttempts' => 3, + 'lockRetryInterval' => 10_000, // 10ms + 'lockMaxRetries' => 3, ]; $handler1 = $this->getInstance($options); From 38c787326f3d764cbed28c865c5fa16d792a749c Mon Sep 17 00:00:00 2001 From: Bogdan Date: Tue, 9 Jun 2026 22:44:31 +0200 Subject: [PATCH 3/8] fix: add lockMaxRetries test and remove stale PHPStan baseline entries --- .../Session/Handlers/Database/RedisHandlerTest.php | 2 +- utils/phpstan-baseline/property.notFound.neon | 12 +----------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/system/Session/Handlers/Database/RedisHandlerTest.php b/tests/system/Session/Handlers/Database/RedisHandlerTest.php index 375a6c523911..d50075b37ea3 100644 --- a/tests/system/Session/Handlers/Database/RedisHandlerTest.php +++ b/tests/system/Session/Handlers/Database/RedisHandlerTest.php @@ -374,7 +374,7 @@ public function testLockMaxRetries(): void $handler2 = $this->getInstance($options); $handler2->open($this->sessionSavePath, $this->sessionName); - // Before the fix, this would incorrectly return true or empty string (since it falls through). + // Before the fix, this would incorrectly return true (since $attempt === 3 !== 300). // With the fix, it should return false after 3 attempts. $this->assertFalse($handler2->read('lock_test_session')); diff --git a/utils/phpstan-baseline/property.notFound.neon b/utils/phpstan-baseline/property.notFound.neon index 9e6fc64adb15..b64acebff15b 100644 --- a/utils/phpstan-baseline/property.notFound.neon +++ b/utils/phpstan-baseline/property.notFound.neon @@ -1,4 +1,4 @@ -# total 49 errors +# total 47 errors parameters: ignoreErrors: @@ -17,16 +17,6 @@ parameters: count: 14 path: ../../system/Database/SQLSRV/Forge.php - - - message: '#^Access to an undefined property Config\\Session\:\:\$lockAttempts\.$#' - count: 1 - path: ../../system/Session/Handlers/RedisHandler.php - - - - message: '#^Access to an undefined property Config\\Session\:\:\$lockWait\.$#' - count: 1 - path: ../../system/Session/Handlers/RedisHandler.php - - message: '#^Access to an undefined property CodeIgniter\\Database\\BaseConnection\:\:\$mysqli\.$#' count: 1 From 6743fd0edf7c07b8dc1ea2e06d93499abb39f20b Mon Sep 17 00:00:00 2001 From: Bogdan Date: Tue, 9 Jun 2026 22:57:11 +0200 Subject: [PATCH 4/8] fix: add setLogger to RedisHandlerTest to prevent null logger error --- .../system/Session/Handlers/Database/RedisHandlerTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/system/Session/Handlers/Database/RedisHandlerTest.php b/tests/system/Session/Handlers/Database/RedisHandlerTest.php index d50075b37ea3..637132669aec 100644 --- a/tests/system/Session/Handlers/Database/RedisHandlerTest.php +++ b/tests/system/Session/Handlers/Database/RedisHandlerTest.php @@ -15,6 +15,8 @@ use CodeIgniter\Session\Handlers\RedisHandler; use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\TestLogger; +use Config\Logger as LoggerConfig; use Config\Session as SessionConfig; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; @@ -54,7 +56,10 @@ protected function getInstance($options = []): RedisHandler $sessionConfig->{$key} = $value; } - return new RedisHandler($sessionConfig, $this->userIpAddress); + $handler = new RedisHandler($sessionConfig, $this->userIpAddress); + $handler->setLogger(new TestLogger(new LoggerConfig())); + + return $handler; } protected function tearDown(): void From b3ed68762682042969754d2d9f4cda116e470d83 Mon Sep 17 00:00:00 2001 From: Bogdan Lambarski Date: Wed, 10 Jun 2026 20:04:07 +0200 Subject: [PATCH 5/8] Update system/Session/Handlers/RedisHandler.php Co-authored-by: Michal Sniatala --- system/Session/Handlers/RedisHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index 5c8e098431b5..e108df3ff9d3 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -98,8 +98,8 @@ public function __construct(SessionConfig $config, string $ipAddress) $this->keyPrefix .= $this->ipAddress . ':'; } - $this->lockRetryInterval = $config->lockRetryInterval; - $this->lockMaxRetries = $config->lockMaxRetries; + $this->lockRetryInterval = $config->lockRetryInterval ?? $this->lockRetryInterval; + $this->lockMaxRetries = $config->lockMaxRetries ?? $this->lockMaxRetries; } protected function setSavePath(): void From 2a8f7714cd344e76d2a081666153c7fd40430366 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 10 Jun 2026 20:10:48 +0200 Subject: [PATCH 6/8] Fix PHPStan warnings for RedisHandler and update changelog --- system/Session/Handlers/RedisHandler.php | 4 ++-- user_guide_src/source/changelogs/v4.7.4.rst | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index e108df3ff9d3..54f628c4789b 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -98,8 +98,8 @@ public function __construct(SessionConfig $config, string $ipAddress) $this->keyPrefix .= $this->ipAddress . ':'; } - $this->lockRetryInterval = $config->lockRetryInterval ?? $this->lockRetryInterval; - $this->lockMaxRetries = $config->lockMaxRetries ?? $this->lockMaxRetries; + $this->lockRetryInterval = $config->lockRetryInterval ?? $this->lockRetryInterval; // @phpstan-ignore nullCoalesce.property + $this->lockMaxRetries = $config->lockMaxRetries ?? $this->lockMaxRetries; // @phpstan-ignore nullCoalesce.property } protected function setSavePath(): void diff --git a/user_guide_src/source/changelogs/v4.7.4.rst b/user_guide_src/source/changelogs/v4.7.4.rst index 7a38176717c0..0c7a5e35c9d0 100644 --- a/user_guide_src/source/changelogs/v4.7.4.rst +++ b/user_guide_src/source/changelogs/v4.7.4.rst @@ -33,6 +33,7 @@ Bugs Fixed - **API:** Fixed a bug in Transformers where the root request's ``fields`` and ``include`` query parameters leaked into nested transformers created inside ``include*()`` methods, causing incorrect field filtering, unexpected includes, or infinite recursion. - **Database:** Fixed a bug where ``updateBatch()`` could be called after Query Builder ``where()`` conditions, even though it's not supported. In this situation, now the ``DatabaseException`` is thrown. - **HTTP:** Fixed a bug where the User Agent library reported Safari's WebKit version instead of the browser version from the ``Version`` token. +- **Session:** Fixed a bug in ``RedisHandler`` where missing ``$lockRetryInterval`` and ``$lockMaxRetries`` properties in a custom ``Session`` configuration file could trigger an ``Undefined property`` warning or error. See the repo's `CHANGELOG.md `_ From 7190331d1d6cf8cc29efb75fb1a754854782722c Mon Sep 17 00:00:00 2001 From: Bogdan Lambarski Date: Thu, 11 Jun 2026 20:00:44 +0200 Subject: [PATCH 7/8] Update user_guide_src/source/changelogs/v4.7.4.rst Co-authored-by: Michal Sniatala --- user_guide_src/source/changelogs/v4.7.4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.7.4.rst b/user_guide_src/source/changelogs/v4.7.4.rst index 8847df575cff..700c2c7291e1 100644 --- a/user_guide_src/source/changelogs/v4.7.4.rst +++ b/user_guide_src/source/changelogs/v4.7.4.rst @@ -33,7 +33,7 @@ Bugs Fixed - **API:** Fixed a bug in Transformers where the root request's ``fields`` and ``include`` query parameters leaked into nested transformers created inside ``include*()`` methods, causing incorrect field filtering, unexpected includes, or infinite recursion. - **Database:** Fixed a bug where ``updateBatch()`` could be called after Query Builder ``where()`` conditions, even though it's not supported. In this situation, now the ``DatabaseException`` is thrown. - **HTTP:** Fixed a bug where the User Agent library reported Safari's WebKit version instead of the browser version from the ``Version`` token. -- **Session:** Fixed a bug in ``RedisHandler`` where missing ``$lockRetryInterval`` and ``$lockMaxRetries`` properties in a custom ``Session`` configuration file could trigger an ``Undefined property`` warning or error. +- **Session:** Fixed a bug in ``RedisHandler`` where the configured ``$lockRetryInterval`` and ``$lockMaxRetries`` values were not respected when acquiring session locks. - **Model:** Fixed a bug in ``Model::objectToRawArray()`` where the ``$recursive`` parameter was ignored. See the repo's From 5afa6e68774ce089a926436f8ecc47c20f96ac48 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sat, 13 Jun 2026 20:12:00 +0200 Subject: [PATCH 8/8] docs: alphabetize changelog entries and properties in v4.7.4.rst --- user_guide_src/source/changelogs/v4.7.4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.7.4.rst b/user_guide_src/source/changelogs/v4.7.4.rst index 700c2c7291e1..b5d2343924ac 100644 --- a/user_guide_src/source/changelogs/v4.7.4.rst +++ b/user_guide_src/source/changelogs/v4.7.4.rst @@ -33,8 +33,8 @@ Bugs Fixed - **API:** Fixed a bug in Transformers where the root request's ``fields`` and ``include`` query parameters leaked into nested transformers created inside ``include*()`` methods, causing incorrect field filtering, unexpected includes, or infinite recursion. - **Database:** Fixed a bug where ``updateBatch()`` could be called after Query Builder ``where()`` conditions, even though it's not supported. In this situation, now the ``DatabaseException`` is thrown. - **HTTP:** Fixed a bug where the User Agent library reported Safari's WebKit version instead of the browser version from the ``Version`` token. -- **Session:** Fixed a bug in ``RedisHandler`` where the configured ``$lockRetryInterval`` and ``$lockMaxRetries`` values were not respected when acquiring session locks. - **Model:** Fixed a bug in ``Model::objectToRawArray()`` where the ``$recursive`` parameter was ignored. +- **Session:** Fixed a bug in ``RedisHandler`` where the configured ``$lockMaxRetries`` and ``$lockRetryInterval`` values were not respected when acquiring session locks. See the repo's `CHANGELOG.md `_