@@ -63,6 +63,16 @@ class RedisHandler extends BaseHandler
63
63
*/
64
64
protected $ sessionExpiration = 7200 ;
65
65
66
+ /**
67
+ * Time (microseconds) to wait if lock cannot be acquired.
68
+ */
69
+ private int $ lockRetryInterval = 100_000 ;
70
+
71
+ /**
72
+ * Maximum number of lock acquisition attempts.
73
+ */
74
+ private int $ lockMaxRetries = 300 ;
75
+
66
76
/**
67
77
* @param string $ipAddress User's IP address
68
78
*
@@ -76,6 +86,7 @@ public function __construct(SessionConfig $config, string $ipAddress)
76
86
$ this ->sessionExpiration = ($ config ->expiration === 0 )
77
87
? (int ) ini_get ('session.gc_maxlifetime ' )
78
88
: $ config ->expiration ;
89
+
79
90
// Add sessionCookieName for multiple session cookies.
80
91
$ this ->keyPrefix .= $ config ->cookieName . ': ' ;
81
92
@@ -84,6 +95,9 @@ public function __construct(SessionConfig $config, string $ipAddress)
84
95
if ($ this ->matchIP === true ) {
85
96
$ this ->keyPrefix .= $ this ->ipAddress . ': ' ;
86
97
}
98
+
99
+ $ this ->lockRetryInterval = $ config ->lockWait ?? $ this ->lockRetryInterval ;
100
+ $ this ->lockMaxRetries = $ config ->lockAttempts ?? $ this ->lockMaxRetries ;
87
101
}
88
102
89
103
protected function setSavePath (): void
@@ -92,23 +106,57 @@ protected function setSavePath(): void
92
106
throw SessionException::forEmptySavepath ();
93
107
}
94
108
95
- if (preg_match ('#(?:(tcp|tls)://)?([^:?]+)(?:\:(\d+))?(\?.+)?# ' , $ this ->savePath , $ matches )) {
96
- if (! isset ($ matches [4 ])) {
97
- $ matches [4 ] = '' ; // Just to avoid undefined index notices below
98
- }
109
+ $ url = parse_url ($ this ->savePath );
110
+ $ query = [];
99
111
100
- $ this ->savePath = [
101
- 'protocol ' => ! empty ($ matches [1 ]) ? $ matches [1 ] : self ::DEFAULT_PROTOCOL ,
102
- 'host ' => $ matches [2 ],
103
- 'port ' => empty ($ matches [3 ]) ? self ::DEFAULT_PORT : $ matches [3 ],
104
- 'password ' => preg_match ('#auth=([^\s&]+)# ' , $ matches [4 ], $ match ) ? $ match [1 ] : null ,
105
- 'database ' => preg_match ('#database=(\d+)# ' , $ matches [4 ], $ match ) ? (int ) $ match [1 ] : 0 ,
106
- 'timeout ' => preg_match ('#timeout=(\d+\.\d+|\d+)# ' , $ matches [4 ], $ match ) ? (float ) $ match [1 ] : 0.0 ,
107
- ];
112
+ if ($ url === false ) {
113
+ // Unix domain socket like `unix:///var/run/redis/redis.sock?persistent=1`.
114
+ if (preg_match ('#unix://(/[^:?]+)(\?.+)?# ' , $ this ->savePath , $ matches )) {
115
+ $ host = $ matches [1 ];
116
+ $ port = 0 ;
108
117
109
- preg_match ('#prefix=([^\s&]+)# ' , $ matches [4 ], $ match ) && $ this ->keyPrefix = $ match [1 ];
118
+ if (isset ($ matches [2 ])) {
119
+ parse_str (ltrim ($ matches [2 ], '? ' ), $ query );
120
+ }
121
+ } else {
122
+ throw SessionException::forInvalidSavePathFormat ($ this ->savePath );
123
+ }
110
124
} else {
111
- throw SessionException::forInvalidSavePathFormat ($ this ->savePath );
125
+ // Also accepts `/var/run/redis.sock` for backward compatibility.
126
+ if (isset ($ url ['path ' ]) && $ url ['path ' ][0 ] === '/ ' ) {
127
+ $ host = $ url ['path ' ];
128
+ $ port = 0 ;
129
+ } else {
130
+ // TCP connection.
131
+ if (! isset ($ url ['host ' ])) {
132
+ throw SessionException::forInvalidSavePathFormat ($ this ->savePath );
133
+ }
134
+
135
+ $ protocol = $ url ['scheme ' ] ?? self ::DEFAULT_PROTOCOL ;
136
+ $ host = $ protocol . ':// ' . $ url ['host ' ];
137
+ $ port = $ url ['port ' ] ?? self ::DEFAULT_PORT ;
138
+ }
139
+
140
+ if (isset ($ url ['query ' ])) {
141
+ parse_str ($ url ['query ' ], $ query );
142
+ }
143
+ }
144
+
145
+ $ password = $ query ['auth ' ] ?? null ;
146
+ $ database = isset ($ query ['database ' ]) ? (int ) $ query ['database ' ] : 0 ;
147
+ $ timeout = isset ($ query ['timeout ' ]) ? (float ) $ query ['timeout ' ] : 0.0 ;
148
+ $ prefix = $ query ['prefix ' ] ?? null ;
149
+
150
+ $ this ->savePath = [
151
+ 'host ' => $ host ,
152
+ 'port ' => $ port ,
153
+ 'password ' => $ password ,
154
+ 'database ' => $ database ,
155
+ 'timeout ' => $ timeout ,
156
+ ];
157
+
158
+ if ($ prefix !== null ) {
159
+ $ this ->keyPrefix = $ prefix ;
112
160
}
113
161
}
114
162
@@ -130,8 +178,8 @@ public function open($path, $name): bool
130
178
131
179
if (
132
180
! $ redis ->connect (
133
- $ this ->savePath ['protocol ' ] . ' :// ' . $ this -> savePath [ ' host ' ],
134
- ( $ this -> savePath [ ' host ' ][ 0 ] === ' / ' ) ? 0 : ( int ) $ this ->savePath ['port ' ],
181
+ $ this ->savePath ['host ' ],
182
+ $ this ->savePath ['port ' ],
135
183
$ this ->savePath ['timeout ' ]
136
184
)
137
185
) {
@@ -325,14 +373,14 @@ protected function lockSession(string $sessionID): bool
325
373
);
326
374
327
375
if (! $ result ) {
328
- usleep (100000 );
376
+ usleep ($ this -> lockRetryInterval );
329
377
330
378
continue ;
331
379
}
332
380
333
381
$ this ->lockKey = $ lockKey ;
334
382
break ;
335
- } while (++$ attempt < 300 );
383
+ } while (++$ attempt < $ this -> lockMaxRetries );
336
384
337
385
if ($ attempt === 300 ) {
338
386
$ this ->logger ->error (
0 commit comments