@@ -115,6 +115,8 @@ protected function setSavePath(): void
115
115
*
116
116
* @param string $path The path where to store/retrieve the session
117
117
* @param string $name The session name
118
+ *
119
+ * @throws RedisException
118
120
*/
119
121
public function open ($ path , $ name ): bool
120
122
{
@@ -124,12 +126,20 @@ public function open($path, $name): bool
124
126
125
127
$ redis = new Redis ();
126
128
127
- if (! $ redis ->connect ($ this ->savePath ['protocol ' ] . ':// ' . $ this ->savePath ['host ' ], ($ this ->savePath ['host ' ][0 ] === '/ ' ? 0 : $ this ->savePath ['port ' ]), $ this ->savePath ['timeout ' ])) {
129
+ if (
130
+ ! $ redis ->connect (
131
+ $ this ->savePath ['protocol ' ] . ':// ' . $ this ->savePath ['host ' ],
132
+ ($ this ->savePath ['host ' ][0 ] === '/ ' ? 0 : $ this ->savePath ['port ' ]),
133
+ $ this ->savePath ['timeout ' ]
134
+ )
135
+ ) {
128
136
$ this ->logger ->error ('Session: Unable to connect to Redis with the configured settings. ' );
129
137
} elseif (isset ($ this ->savePath ['password ' ]) && ! $ redis ->auth ($ this ->savePath ['password ' ])) {
130
138
$ this ->logger ->error ('Session: Unable to authenticate to Redis instance. ' );
131
139
} elseif (isset ($ this ->savePath ['database ' ]) && ! $ redis ->select ($ this ->savePath ['database ' ])) {
132
- $ this ->logger ->error ('Session: Unable to select Redis database with index ' . $ this ->savePath ['database ' ]);
140
+ $ this ->logger ->error (
141
+ 'Session: Unable to select Redis database with index ' . $ this ->savePath ['database ' ]
142
+ );
133
143
} else {
134
144
$ this ->redis = $ redis ;
135
145
@@ -146,6 +156,8 @@ public function open($path, $name): bool
146
156
*
147
157
* @return false|string Returns an encoded string of the read data.
148
158
* If nothing was read, it must return false.
159
+ *
160
+ * @throws RedisException
149
161
*/
150
162
#[ReturnTypeWillChange]
151
163
public function read ($ id )
@@ -168,14 +180,16 @@ public function read($id)
168
180
return $ data ;
169
181
}
170
182
171
- return '' ;
183
+ return false ;
172
184
}
173
185
174
186
/**
175
187
* Writes the session data to the session storage.
176
188
*
177
189
* @param string $id The session ID
178
190
* @param string $data The encoded session data
191
+ *
192
+ * @throws RedisException
179
193
*/
180
194
public function write ($ id , $ data ): bool
181
195
{
@@ -222,8 +236,8 @@ public function close(): bool
222
236
$ pingReply = $ this ->redis ->ping ();
223
237
224
238
if (($ pingReply === true ) || ($ pingReply === '+PONG ' )) {
225
- if (isset ($ this ->lockKey )) {
226
- $ this -> releaseLock () ;
239
+ if (isset ($ this ->lockKey ) && ! $ this -> releaseLock () ) {
240
+ return false ;
227
241
}
228
242
229
243
if (! $ this ->redis ->close ()) {
@@ -246,12 +260,16 @@ public function close(): bool
246
260
* Destroys a session
247
261
*
248
262
* @param string $id The session ID being destroyed
263
+ *
264
+ * @throws RedisException
249
265
*/
250
266
public function destroy ($ id ): bool
251
267
{
252
268
if (isset ($ this ->redis , $ this ->lockKey )) {
253
269
if (($ result = $ this ->redis ->del ($ this ->keyPrefix . $ id )) !== 1 ) {
254
- $ this ->logger ->debug ('Session: Redis::del() expected to return 1, got ' . var_export ($ result , true ) . ' instead. ' );
270
+ $ this ->logger ->debug (
271
+ 'Session: Redis::del() expected to return 1, got ' . var_export ($ result , true ) . ' instead. '
272
+ );
255
273
}
256
274
257
275
return $ this ->destroyCookie ();
@@ -278,6 +296,8 @@ public function gc($max_lifetime)
278
296
* Acquires an emulated lock.
279
297
*
280
298
* @param string $sessionID Session ID
299
+ *
300
+ * @throws RedisException
281
301
*/
282
302
protected function lockSession (string $ sessionID ): bool
283
303
{
@@ -287,48 +307,49 @@ protected function lockSession(string $sessionID): bool
287
307
// so we need to check here if the lock key is for the
288
308
// correct session ID.
289
309
if ($ this ->lockKey === $ lockKey ) {
310
+ // If there is the lock, make the ttl longer.
290
311
return $ this ->redis ->expire ($ this ->lockKey , 300 );
291
312
}
292
313
293
314
$ attempt = 0 ;
294
315
295
316
do {
296
- $ ttl = $ this ->redis ->ttl ($ lockKey );
297
- assert (is_int ($ ttl ));
317
+ $ result = $ this ->redis ->set (
318
+ $ lockKey ,
319
+ (string ) Time::now ()->getTimestamp (),
320
+ // NX -- Only set the key if it does not already exist.
321
+ // EX seconds -- Set the specified expire time, in seconds.
322
+ ['nx ' , 'ex ' => 300 ]
323
+ );
298
324
299
- if ($ ttl > 0 ) {
300
- sleep ( 1 );
325
+ if (! $ result ) {
326
+ usleep ( 100000 );
301
327
302
328
continue ;
303
329
}
304
330
305
- if (! $ this ->redis ->setex ($ lockKey , 300 , (string ) Time::now ()->getTimestamp ())) {
306
- $ this ->logger ->error ('Session: Error while trying to obtain lock for ' . $ this ->keyPrefix . $ sessionID );
307
-
308
- return false ;
309
- }
310
-
311
331
$ this ->lockKey = $ lockKey ;
312
332
break ;
313
- } while (++$ attempt < 30 );
333
+ } while (++$ attempt < 300 );
314
334
315
- if ($ attempt === 30 ) {
316
- log_message ('error ' , 'Session: Unable to obtain lock for ' . $ this ->keyPrefix . $ sessionID . ' after 30 attempts, aborting. ' );
335
+ if ($ attempt === 300 ) {
336
+ $ this ->logger ->error (
337
+ 'Session: Unable to obtain lock for ' . $ this ->keyPrefix . $ sessionID
338
+ . ' after 300 attempts, aborting. '
339
+ );
317
340
318
341
return false ;
319
342
}
320
343
321
- if ($ ttl === -1 ) {
322
- log_message ('debug ' , 'Session: Lock for ' . $ this ->keyPrefix . $ sessionID . ' had no TTL, overriding. ' );
323
- }
324
-
325
344
$ this ->lock = true ;
326
345
327
346
return true ;
328
347
}
329
348
330
349
/**
331
350
* Releases a previously acquired lock
351
+ *
352
+ * @throws RedisException
332
353
*/
333
354
protected function releaseLock (): bool
334
355
{
0 commit comments