1 | <?php |
||
2 | declare(strict_types=1); |
||
3 | |||
4 | namespace Utilities\Router; |
||
5 | |||
6 | use Utilities\Common\Common; |
||
7 | |||
8 | /** |
||
9 | * Session class |
||
10 | * |
||
11 | * @link https://github.com/utilities-php/router |
||
12 | * @author Shahrad Elahi (https://github.com/shahradelahi) |
||
13 | * @license https://github.com/utilities-php/router/blob/master/LICENSE (MIT License) |
||
14 | */ |
||
15 | class Session |
||
16 | { |
||
17 | |||
18 | /** |
||
19 | * @var User |
||
20 | */ |
||
21 | public static User $user; |
||
22 | /** |
||
23 | * @var array |
||
24 | */ |
||
25 | private static array $cookieParams = []; |
||
26 | |||
27 | /** |
||
28 | * Set session value |
||
29 | * |
||
30 | * @param string $key |
||
31 | * @param mixed $value |
||
32 | * @return void |
||
33 | */ |
||
34 | public static function set(string $key, mixed $value): void |
||
35 | { |
||
36 | $_SESSION[$key] = $value; |
||
37 | } |
||
38 | |||
39 | /** |
||
40 | * Get session value |
||
41 | * |
||
42 | * @param string $key |
||
43 | * @return mixed |
||
44 | */ |
||
45 | public static function get(string $key): mixed |
||
46 | { |
||
47 | return $_SESSION[$key] ?? null; |
||
48 | } |
||
49 | |||
50 | /** |
||
51 | * Check if session value exists |
||
52 | * |
||
53 | * @param string $key |
||
54 | * @return bool |
||
55 | */ |
||
56 | public static function has(string $key): bool |
||
57 | { |
||
58 | return isset($_SESSION[$key]); |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * Delete session value |
||
63 | * |
||
64 | * @param string $key |
||
65 | * @return void |
||
66 | */ |
||
67 | public static function delete(string $key): void |
||
68 | { |
||
69 | unset($_SESSION[$key]); |
||
70 | } |
||
71 | |||
72 | /** |
||
73 | * Destroy session |
||
74 | * |
||
75 | * @return void |
||
76 | */ |
||
77 | public static function destroy(): void |
||
78 | { |
||
79 | session_destroy(); |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * Set flash value |
||
84 | * |
||
85 | * @param string $key |
||
86 | * @param mixed $value |
||
87 | * @return void |
||
88 | */ |
||
89 | public static function flash(string $key, mixed $value): void |
||
90 | { |
||
91 | $_SESSION['_flash'][$key] = $value; |
||
92 | } |
||
93 | |||
94 | /** |
||
95 | * Get old value |
||
96 | * |
||
97 | * @param string $key |
||
98 | * @return mixed |
||
99 | */ |
||
100 | public static function old(string $key): mixed |
||
101 | { |
||
102 | return $_SESSION['_old'][$key] ?? null; |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * Check if old value exists |
||
107 | * |
||
108 | * @param string $key |
||
109 | * @return bool |
||
110 | */ |
||
111 | public static function hasOld(string $key): bool |
||
112 | { |
||
113 | return isset($_SESSION['_old'][$key]); |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Delete old value |
||
118 | * |
||
119 | * @param string $key |
||
120 | * @return void |
||
121 | */ |
||
122 | public static function deleteOld(string $key): void |
||
123 | { |
||
124 | unset($_SESSION['_old'][$key]); |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * Destroy old values |
||
129 | * |
||
130 | * @return void |
||
131 | */ |
||
132 | public static function destroyOld(): void |
||
133 | { |
||
134 | $_SESSION['_old'] = []; |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Regenerate session id (keeps session alive) |
||
139 | * |
||
140 | * @return void |
||
141 | */ |
||
142 | public static function regenerateId(): void |
||
143 | { |
||
144 | session_regenerate_id(false); |
||
145 | } |
||
146 | |||
147 | /** |
||
148 | * Regenerate session token |
||
149 | * |
||
150 | * @return void |
||
151 | */ |
||
152 | public static function regenerateToken(): void |
||
153 | { |
||
154 | $_SESSION['_token'] = bin2hex(Common::randomString(32)); |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Refresh session lifetime |
||
159 | * |
||
160 | * @param int|null $lifetime (optional) default: ini_get('session.gc_maxlifetime') |
||
161 | * @return void |
||
162 | */ |
||
163 | public static function refresh(int $lifetime = null): void |
||
164 | { |
||
165 | if ($lifetime === null) { |
||
166 | $lifetime = intval(ini_get('session.gc_maxlifetime')); |
||
167 | } |
||
168 | |||
169 | static::setCookieParams([ |
||
170 | 'lifetime' => $lifetime, |
||
171 | ]); |
||
172 | |||
173 | static::start(); |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * Start session |
||
178 | * |
||
179 | * @param array $params (optional) session cookie params |
||
180 | * @return void |
||
181 | */ |
||
182 | public static function start(array $params = []): void |
||
183 | { |
||
184 | if ($params) { |
||
0 ignored issues
–
show
|
|||
185 | self::setCookieParams($params); |
||
186 | } |
||
187 | |||
188 | if (session_status() === PHP_SESSION_NONE) { |
||
189 | session_set_cookie_params(static::$cookieParams); |
||
0 ignored issues
–
show
|
|||
190 | session_start(); |
||
191 | } |
||
192 | |||
193 | if (empty($_SESSION)) { |
||
194 | $_SESSION = []; |
||
195 | } |
||
196 | |||
197 | $initialKeys = [ |
||
198 | '_flash' => [], |
||
199 | '_old' => [], |
||
200 | '_log' => [], |
||
201 | ]; |
||
202 | |||
203 | foreach ($initialKeys as $key => $value) { |
||
204 | if (empty($_SESSION[$key])) { |
||
205 | $_SESSION[$key] = $value; |
||
206 | } |
||
207 | } |
||
208 | |||
209 | if (empty($_SESSION['_token'])) { |
||
210 | $_SESSION['_token'] = bin2hex(Common::randomString(32)); |
||
211 | } |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * move session to another session_name |
||
216 | * |
||
217 | * @param string $sessionName |
||
218 | * @return void |
||
219 | */ |
||
220 | public static function move(string $sessionName): void |
||
221 | { |
||
222 | self::regenerate(); |
||
223 | session_name($sessionName); |
||
224 | self::start(); |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * Regenerate session (destroy and start) |
||
229 | * |
||
230 | * @return void |
||
231 | */ |
||
232 | public static function regenerate(): void |
||
233 | { |
||
234 | session_regenerate_id(true); |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * set session id |
||
239 | * |
||
240 | * @param string $id |
||
241 | * @return void |
||
242 | */ |
||
243 | public static function setId(string $id): void |
||
244 | { |
||
245 | session_id($id); |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * get session id |
||
250 | * |
||
251 | * @return string |
||
252 | */ |
||
253 | public static function getId(): string |
||
254 | { |
||
255 | return session_id(); |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * get session name |
||
260 | * |
||
261 | * @return string |
||
262 | */ |
||
263 | public static function getName(): string |
||
264 | { |
||
265 | return session_name(); |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * get session status |
||
270 | * |
||
271 | * @return int (0 = disabled, 1 = none, 2 = active) |
||
272 | */ |
||
273 | public static function getStatus(): int |
||
274 | { |
||
275 | return session_status(); |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * get session cookie params |
||
280 | * |
||
281 | * @return array |
||
282 | */ |
||
283 | public static function getCookieParams(): array |
||
284 | { |
||
285 | return static::$cookieParams; |
||
0 ignored issues
–
show
|
|||
286 | } |
||
287 | |||
288 | /** |
||
289 | * Set session cookie params |
||
290 | * |
||
291 | * @param array $params |
||
292 | * @return void |
||
293 | */ |
||
294 | public static function setCookieParams(array $params): void |
||
295 | { |
||
296 | $defaults = [ |
||
297 | 'lifetime' => intval(ini_get('session.gc_maxlifetime')), |
||
298 | 'path' => ini_get('session.save_path'), |
||
299 | 'domain' => ini_get('session.cookie_domain'), |
||
300 | 'secure' => ini_get('session.cookie_secure'), |
||
301 | 'httponly' => ini_get('session.cookie_httponly'), |
||
302 | ]; |
||
303 | |||
304 | foreach ($defaults as $key => $value) { |
||
305 | if (!isset(static::$cookieParams[$key]) && !is_null($value)) { |
||
0 ignored issues
–
show
|
|||
306 | static::$cookieParams[$key] = $value; |
||
307 | } |
||
308 | } |
||
309 | |||
310 | static::$cookieParams = array_merge(static::$cookieParams, $params); |
||
311 | } |
||
312 | |||
313 | /** |
||
314 | * set session save path |
||
315 | * |
||
316 | * @param string $path |
||
317 | * @return void |
||
318 | */ |
||
319 | public static function setSavePath(string $path): void |
||
320 | { |
||
321 | session_save_path($path); |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * get session save path |
||
326 | * |
||
327 | * @return string |
||
328 | */ |
||
329 | public static function getSavePath(): string |
||
330 | { |
||
331 | return session_save_path(); |
||
332 | } |
||
333 | |||
334 | /** |
||
335 | * set session cache limiter |
||
336 | * |
||
337 | * @param string $cache_limiter |
||
338 | * @return void |
||
339 | */ |
||
340 | public static function setCacheLimiter(string $cache_limiter): void |
||
341 | { |
||
342 | session_cache_limiter($cache_limiter); |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * get session cache limiter |
||
347 | * |
||
348 | * @return string |
||
349 | */ |
||
350 | public static function getCacheLimiter(): string |
||
351 | { |
||
352 | return session_cache_limiter(); |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * set session cache expire |
||
357 | * |
||
358 | * @param int $expire |
||
359 | * @return void |
||
360 | */ |
||
361 | public static function setCacheExpire(int $expire): void |
||
362 | { |
||
363 | session_cache_expire($expire); |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * get session cache expire |
||
368 | * |
||
369 | * @return int |
||
370 | */ |
||
371 | public static function getCacheExpire(): int |
||
372 | { |
||
373 | return session_cache_expire(); |
||
374 | } |
||
375 | |||
376 | /** |
||
377 | * log session data |
||
378 | * |
||
379 | * @param string $data |
||
380 | * @return void |
||
381 | */ |
||
382 | public static function log(string $data): void |
||
383 | { |
||
384 | $_SESSION['_log'][] = $data; |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * get session log |
||
389 | * |
||
390 | * @param string|null $key (optional) Key a specific log or all logs |
||
391 | * @return mixed |
||
392 | */ |
||
393 | public static function getLog(string $key = null): mixed |
||
394 | { |
||
395 | if ($key === null) { |
||
396 | return $_SESSION['_log'] ?? []; |
||
397 | } |
||
398 | |||
399 | return $_SESSION['_log'][$key] ?? null; |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * clear session log |
||
404 | * |
||
405 | * @return void |
||
406 | */ |
||
407 | public static function clearLog(): void |
||
408 | { |
||
409 | $_SESSION['_log'] = []; |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * check if there's any session log |
||
414 | * |
||
415 | * @return bool |
||
416 | */ |
||
417 | public static function hasLog(): bool |
||
418 | { |
||
419 | return isset($_SESSION['_log']) && count($_SESSION['_log']) > 0; |
||
420 | } |
||
421 | |||
422 | /** |
||
423 | * delete session log |
||
424 | * |
||
425 | * @param string $key |
||
426 | * @return void |
||
427 | */ |
||
428 | public static function deleteLog(string $key): void |
||
429 | { |
||
430 | unset($_SESSION['_log'][$key]); |
||
431 | } |
||
432 | |||
433 | /** |
||
434 | * destroy session log |
||
435 | * |
||
436 | * @return void |
||
437 | */ |
||
438 | public static function destroyLog(): void |
||
439 | { |
||
440 | unset($_SESSION['_log']); |
||
441 | $_SESSION['_log'] = []; |
||
442 | } |
||
443 | |||
444 | /** |
||
445 | * @param string $name |
||
446 | * @param array $arguments |
||
447 | * @return mixed |
||
448 | */ |
||
449 | public static function __callStatic(string $name, array $arguments): mixed |
||
450 | { |
||
451 | if ($name === 'user') { |
||
452 | return static::getUser(); |
||
453 | } |
||
454 | |||
455 | return call_user_func_array([static::getUser(), $name], $arguments); |
||
456 | } |
||
457 | |||
458 | /** |
||
459 | * get user and initiate it if it doesn't exist |
||
460 | * |
||
461 | * @return User |
||
462 | */ |
||
463 | private static function getUser(): User |
||
464 | { |
||
465 | if (!isset($_SESSION['_user'])) { |
||
466 | $_SESSION['_user'] = new User(); |
||
467 | } |
||
468 | |||
469 | return $_SESSION['_user']; |
||
470 | } |
||
471 | |||
472 | } |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.