-
Notifications
You must be signed in to change notification settings - Fork 2k
Bug: Redis Session data is lost if lock error happens #8567
Description
CodeIgniter4 Version: develop after 4.4.5
From
- https://forum.codeigniter.com/showthread.php?tid=88643
- https://forum.codeigniter.com/showthread.php?tid=87716
What happened?
If the lockSession() fails when reading the data from Redis, it returns ''.
And it clears the session data, and the data will be saved when closing the session.
CodeIgniter4/system/Session/Handlers/RedisHandler.php
Lines 151 to 172 in cc9ce52
| public function read($id) | |
| { | |
| if (isset($this->redis) && $this->lockSession($id)) { | |
| if (! isset($this->sessionID)) { | |
| $this->sessionID = $id; | |
| } | |
| $data = $this->redis->get($this->keyPrefix . $id); | |
| if (is_string($data)) { | |
| $this->keyExists = true; | |
| } else { | |
| $data = ''; | |
| } | |
| $this->fingerprint = md5($data); | |
| return $data; | |
| } | |
| return ''; | |
| } |
CodeIgniter4/system/Session/Handlers/RedisHandler.php
Lines 315 to 319 in cc9ce52
| if ($attempt === 30) { | |
| log_message('error', 'Session: Unable to obtain lock for ' . $this->keyPrefix . $sessionID . ' after 30 attempts, aborting.'); | |
| return false; | |
| } |
public function index()
{
$session = session();
var_dump($_SESSION);
$count = $session->get('count') ?? 0;
$count++;
$session->set('count', $count);
var_dump($_SESSION);
}Navigate to http://localhost:8080/ and reload many times.
/Users/kenji/work/codeigniter/official/CodeIgniter4/app/Controllers/Home.php:11:
array (size=3)
'__ci_last_regenerate' => int 1708569979
'count' => int 4024
'_ci_previous_url' => string 'http://localhost:8080/index.php/' (length=32)
/Users/kenji/work/codeigniter/official/CodeIgniter4/app/Controllers/Home.php:17:
array (size=3)
'__ci_last_regenerate' => int 1708569979
'count' => int 4025
'_ci_previous_url' => string 'http://localhost:8080/index.php/' (length=32)
Modify the code for testing.
--- a/system/Session/Handlers/RedisHandler.php
+++ b/system/Session/Handlers/RedisHandler.php
@@ -150,6 +150,8 @@ class RedisHandler extends BaseHandler
#[ReturnTypeWillChange]
public function read($id)
{
+ return '';
+
if (isset($this->redis) && $this->lockSession($id)) {
if (! isset($this->sessionID)) {
$this->sessionID = $id;Navigate to http://localhost:8080/ again.
Result:
/Users/kenji/work/codeigniter/official/CodeIgniter4/app/Controllers/Home.php:11:
array (size=1)
'__ci_last_regenerate' => int 1708570128
/Users/kenji/work/codeigniter/official/CodeIgniter4/app/Controllers/Home.php:17:
array (size=2)
'__ci_last_regenerate' => int 1708570128
'count' => int 1
Expected Output
If read() returns false, the following error occurs.
But the session data remains.
ErrorException
session_start(): Failed to read session data: user (path: tcp://localhost:6379) search →