Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
280 / 280 |
|
100.00% |
14 / 14 |
CRAP | |
100.00% |
1 / 1 |
SessionCollector | |
100.00% |
280 / 280 |
|
100.00% |
14 / 14 |
53 | |
100.00% |
1 / 1 |
setSession | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setOptions | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setSaveHandler | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getContents | |
100.00% |
19 / 19 |
|
100.00% |
1 / 1 |
3 | |||
renderData | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
3 | |||
renderFlash | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
renderFlashOld | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
3 | |||
renderFlashNew | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
3 | |||
renderTemp | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
3 | |||
renderSaveHandler | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
3 | |||
renderSaveHandlerTableRows | |
100.00% |
31 / 31 |
|
100.00% |
1 / 1 |
5 | |||
renderCookieParams | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
3 | |||
renderAutoRegenerateId | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
4 | |||
getSaveHandlerConfigs | |
100.00% |
63 / 63 |
|
100.00% |
1 / 1 |
17 |
1 | <?php declare(strict_types=1); |
2 | /* |
3 | * This file is part of Aplus Framework Session Library. |
4 | * |
5 | * (c) Natan Felles <natanfelles@gmail.com> |
6 | * |
7 | * For the full copyright and license information, please view the LICENSE |
8 | * file that was distributed with this source code. |
9 | */ |
10 | namespace Framework\Session\Debug; |
11 | |
12 | use Framework\Debug\Collector; |
13 | use Framework\Debug\Debugger; |
14 | use Framework\Helpers\ArraySimple; |
15 | use Framework\Session\SaveHandler; |
16 | use Framework\Session\SaveHandlers\DatabaseHandler; |
17 | use Framework\Session\SaveHandlers\FilesHandler; |
18 | use Framework\Session\SaveHandlers\MemcachedHandler; |
19 | use Framework\Session\SaveHandlers\RedisHandler; |
20 | use Framework\Session\Session; |
21 | |
22 | /** |
23 | * Class SessionCollector. |
24 | * |
25 | * @package session |
26 | */ |
27 | class SessionCollector extends Collector |
28 | { |
29 | protected Session $session; |
30 | /** |
31 | * @var array<string> |
32 | */ |
33 | protected array $options = []; |
34 | protected SaveHandler $saveHandler; |
35 | |
36 | public function setSession(Session $session) : static |
37 | { |
38 | $this->session = $session; |
39 | return $this; |
40 | } |
41 | |
42 | /** |
43 | * @param array<string> $options |
44 | * |
45 | * @return static |
46 | */ |
47 | public function setOptions(array $options) : static |
48 | { |
49 | $this->options = $options; |
50 | return $this; |
51 | } |
52 | |
53 | public function setSaveHandler(SaveHandler $handler) : static |
54 | { |
55 | $this->saveHandler = $handler; |
56 | return $this; |
57 | } |
58 | |
59 | public function getContents() : string |
60 | { |
61 | if ( ! isset($this->session)) { |
62 | return '<p>No Session instance has been set on this collector.</p>'; |
63 | } |
64 | if ( ! $this->session->isActive()) { |
65 | return '<p>Session is inactive.</p>'; |
66 | } |
67 | \ob_start(); ?> |
68 | <p><strong>Name:</strong> <?= \ini_get('session.name') ?></p> |
69 | <p><strong>Id:</strong> <?= $this->session->id() ?></p> |
70 | <h1>Data</h1> |
71 | <?= $this->renderData() ?> |
72 | <h1>Flash</h1> |
73 | <?= $this->renderFlash() ?> |
74 | <h1>Temp</h1> |
75 | <?= $this->renderTemp() ?> |
76 | <h1>Save Handler</h1> |
77 | <?= $this->renderSaveHandler() ?> |
78 | <h1>Cookie Params</h1> |
79 | <?= $this->renderCookieParams() ?> |
80 | <h1>Auto Regenerate Id</h1> |
81 | <?php |
82 | echo $this->renderAutoRegenerateId(); |
83 | return \ob_get_clean(); // @phpstan-ignore-line |
84 | } |
85 | |
86 | protected function renderData() : string |
87 | { |
88 | $data = $this->session->getAll(); |
89 | unset($data['$']); |
90 | if (empty($data)) { |
91 | return '<p>No data.</p>'; |
92 | } |
93 | \ksort($data); |
94 | \ob_start(); ?> |
95 | <table> |
96 | <thead> |
97 | <tr> |
98 | <th>Key</th> |
99 | <th>Value</th> |
100 | </tr> |
101 | </thead> |
102 | <tbody> |
103 | <?php foreach ($data as $key => $value): ?> |
104 | <tr> |
105 | <td><?= \htmlentities((string) $key) ?></td> |
106 | <td><pre><code class="language-php"><?= |
107 | \htmlentities(Debugger::makeDebugValue($value)) |
108 | ?></code></pre> |
109 | </td> |
110 | </tr> |
111 | <?php endforeach ?> |
112 | </tbody> |
113 | </table> |
114 | <?php |
115 | return \ob_get_clean(); // @phpstan-ignore-line |
116 | } |
117 | |
118 | protected function renderFlash() : string |
119 | { |
120 | $old = $this->renderFlashOld(); |
121 | $new = $this->renderFlashNew(); |
122 | if ($old === '' && $new === '') { |
123 | return '<p>No flash data.</p>'; |
124 | } |
125 | return $old . $new; |
126 | } |
127 | |
128 | protected function renderFlashOld() : string |
129 | { |
130 | $data = ArraySimple::value('$[flash][old]', $this->session->getAll()); |
131 | if (empty($data)) { |
132 | return ''; |
133 | } |
134 | \ob_start(); ?> |
135 | <h2>Old</h2> |
136 | <p>Flash data available in the current request.</p> |
137 | <table> |
138 | <thead> |
139 | <tr> |
140 | <th>Key</th> |
141 | <th>Value</th> |
142 | </tr> |
143 | </thead> |
144 | <tbody> |
145 | <?php foreach ($data as $key => $value): ?> |
146 | <tr> |
147 | <td><?= \htmlentities($key) ?></td> |
148 | <td><pre><code class="language-php"><?= |
149 | \htmlentities(Debugger::makeDebugValue($value)) |
150 | ?></code></pre> |
151 | </td> |
152 | </tr> |
153 | <?php endforeach ?> |
154 | </tbody> |
155 | </table> |
156 | <?php |
157 | return \ob_get_clean(); // @phpstan-ignore-line |
158 | } |
159 | |
160 | protected function renderFlashNew() : string |
161 | { |
162 | $data = ArraySimple::value('$[flash][new]', $this->session->getAll()); |
163 | if (empty($data)) { |
164 | return ''; |
165 | } |
166 | \ob_start(); ?> |
167 | <h2>New</h2> |
168 | <p>Flash data available in the next request.</p> |
169 | <table> |
170 | <thead> |
171 | <tr> |
172 | <th>Key</th> |
173 | <th>Value</th> |
174 | </tr> |
175 | </thead> |
176 | <tbody> |
177 | <?php foreach ($data as $key => $value): ?> |
178 | <tr> |
179 | <td><?= \htmlentities($key) ?></td> |
180 | <td><pre><code class="language-php"><?= |
181 | \htmlentities(Debugger::makeDebugValue($value)) |
182 | ?></code></pre> |
183 | </td> |
184 | </tr> |
185 | <?php endforeach ?> |
186 | </tbody> |
187 | </table> |
188 | <?php |
189 | return \ob_get_clean(); // @phpstan-ignore-line |
190 | } |
191 | |
192 | protected function renderTemp() : string |
193 | { |
194 | $data = ArraySimple::value('$[temp]', $this->session->getAll()); |
195 | if (empty($data)) { |
196 | return '<p>No temp data.</p>'; |
197 | } |
198 | \ob_start(); ?> |
199 | <table> |
200 | <thead> |
201 | <tr> |
202 | <th>Key</th> |
203 | <th>Value</th> |
204 | <th>TTL</th> |
205 | </tr> |
206 | </thead> |
207 | <tbody> |
208 | <?php foreach ($data as $key => $value): ?> |
209 | <tr> |
210 | <td><?= \htmlentities($key) ?></td> |
211 | <td><pre><code class="language-php"><?= |
212 | \htmlentities(Debugger::makeDebugValue($value)) |
213 | ?></code></pre> |
214 | </td> |
215 | <td><?= \date('Y-m-d H:i:s', $value['ttl']) ?></td> |
216 | </tr> |
217 | <?php endforeach ?> |
218 | </tbody> |
219 | </table> |
220 | <?php |
221 | return \ob_get_clean(); // @phpstan-ignore-line |
222 | } |
223 | |
224 | protected function renderSaveHandler() : string |
225 | { |
226 | \ob_start(); ?> |
227 | <p><strong>Save Handler:</strong> <?= \ini_get('session.save_handler') ?></p> |
228 | <p><strong>Serializer:</strong> <?= \ini_get('session.serialize_handler') ?></p> |
229 | <?php |
230 | if (isset($this->saveHandler)): ?> |
231 | <table> |
232 | <tbody> |
233 | <tr> |
234 | <th>Class</th> |
235 | <td><?= $this->saveHandler::class ?></td> |
236 | </tr> |
237 | <?php foreach ($this->getSaveHandlerConfigs() as $key => $value): ?> |
238 | <?= $this->renderSaveHandlerTableRows($key, $value) ?> |
239 | <?php endforeach ?> |
240 | </tbody> |
241 | </table> |
242 | <?php |
243 | endif; |
244 | return \ob_get_clean(); // @phpstan-ignore-line |
245 | } |
246 | |
247 | protected function renderSaveHandlerTableRows(string $key, mixed $value) : string |
248 | { |
249 | \ob_start(); ?> |
250 | <?php |
251 | if (\is_array($value)): |
252 | $count = \count($value); ?> |
253 | <tr> |
254 | <th rowspan="<?= $count ?>"><?= $key ?></th> |
255 | <td> |
256 | <table> |
257 | <?php foreach ($value[\array_key_first($value)] as $k => $v): ?> |
258 | <tr> |
259 | <th><?= \htmlentities($k) ?></th> |
260 | <td><?= \htmlentities((string) $v) ?></td> |
261 | </tr> |
262 | <?php endforeach ?> |
263 | </table> |
264 | </td> |
265 | </tr> |
266 | <?php |
267 | for ($i = 1; $i < $count; $i++): ?> |
268 | <tr> |
269 | <td> |
270 | <table> |
271 | <?php foreach ($value[$i] as $k => $v): ?> |
272 | <tr> |
273 | <th><?= \htmlentities($k) ?></th> |
274 | <td><?= \htmlentities((string) $v) ?></td> |
275 | </tr> |
276 | <?php endforeach ?> |
277 | </table> |
278 | </td> |
279 | </tr> |
280 | <?php |
281 | endfor; |
282 | return \ob_get_clean(); // @phpstan-ignore-line |
283 | endif; ?> |
284 | <tr> |
285 | <th><?= \htmlentities($key) ?></th> |
286 | <td><?= \htmlentities((string) $value) ?></td> |
287 | </tr> |
288 | <?php |
289 | return \ob_get_clean(); // @phpstan-ignore-line |
290 | } |
291 | |
292 | protected function renderCookieParams() : string |
293 | { |
294 | $params = \session_get_cookie_params(); |
295 | \ob_start(); ?> |
296 | <table> |
297 | <thead> |
298 | <tr> |
299 | <th>Lifetime</th> |
300 | <th>Path</th> |
301 | <th>Domain</th> |
302 | <th>Is Secure</th> |
303 | <th>Is HTTP Only</th> |
304 | <th>SameSite</th> |
305 | </tr> |
306 | </thead> |
307 | <tbody> |
308 | <tr> |
309 | <td><?= $params['lifetime'] ?></td> |
310 | <td><?= $params['path'] ?></td> |
311 | <td><?= $params['domain'] ?></td> |
312 | <td><?= $params['secure'] ? 'Yes' : 'No' ?></td> |
313 | <td><?= $params['httponly'] ? 'Yes' : 'No' ?></td> |
314 | <td><?= $params['samesite'] ?></td> |
315 | </tr> |
316 | </tbody> |
317 | </table> |
318 | <?php |
319 | return \ob_get_clean(); // @phpstan-ignore-line |
320 | } |
321 | |
322 | protected function renderAutoRegenerateId() : string |
323 | { |
324 | if ($this->options['auto_regenerate_maxlifetime'] < 1) { |
325 | return '<p>Auto regenerate id is inactive.</p>'; |
326 | } |
327 | $maxlifetime = (int) $this->options['auto_regenerate_maxlifetime']; |
328 | $regeneratedAt = ArraySimple::value('$[regenerated_at]', $this->session->getAll()); |
329 | $nextRegeneration = $regeneratedAt + $maxlifetime; |
330 | \ob_start(); ?> |
331 | <table> |
332 | <thead> |
333 | <tr> |
334 | <th>Maxlifetime</th> |
335 | <th>Destroy</th> |
336 | <th>Regenerated At</th> |
337 | <th>Next Regeneration</th> |
338 | </tr> |
339 | </thead> |
340 | <tbody> |
341 | <tr> |
342 | <td><?= $maxlifetime ?></td> |
343 | <td><?= $this->options['auto_regenerate_destroy'] ? 'Yes' : 'No' ?></td> |
344 | <td><?= $regeneratedAt ? \date('Y-m-d H:i:s', $regeneratedAt) : '' ?></td> |
345 | <td><?= \date('Y-m-d H:i:s', $nextRegeneration) ?></td> |
346 | </tr> |
347 | </tbody> |
348 | </table> |
349 | <?php |
350 | return \ob_get_clean(); // @phpstan-ignore-line |
351 | } |
352 | |
353 | /** |
354 | * @return array<string,mixed> |
355 | */ |
356 | protected function getSaveHandlerConfigs() : array |
357 | { |
358 | $config = $this->saveHandler->getConfig(); |
359 | if ($this->saveHandler instanceof FilesHandler) { |
360 | return [ |
361 | 'Directory' => $config['directory'], |
362 | 'Prefix' => $config['prefix'], |
363 | 'Match IP' => $config['match_ip'] ? 'Yes' : 'No', |
364 | 'Match User-Agent' => $config['match_ua'] ? 'Yes' : 'No', |
365 | ]; |
366 | } |
367 | if ($this->saveHandler instanceof MemcachedHandler) { |
368 | $servers = []; |
369 | foreach ($config['servers'] as $server) { |
370 | $servers[] = [ |
371 | 'Host' => $server['host'], |
372 | 'Port' => $server['port'] ?? 11211, |
373 | 'Weight' => $server['weight'] ?? 0, |
374 | ]; |
375 | } |
376 | return [ |
377 | 'Servers' => $servers, |
378 | 'Prefix' => $config['prefix'], |
379 | 'Lock Attempts' => $config['lock_attempts'], |
380 | 'Lock Sleep' => $config['lock_sleep'], |
381 | 'Lock TTL' => $config['lock_ttl'], |
382 | 'Maxlifetime' => $config['maxlifetime'] ?? \ini_get('session.gc_maxlifetime'), |
383 | 'Match IP' => $config['match_ip'] ? 'Yes' : 'No', |
384 | 'Match User-Agent' => $config['match_ua'] ? 'Yes' : 'No', |
385 | ]; |
386 | } |
387 | if ($this->saveHandler instanceof RedisHandler) { |
388 | return [ |
389 | 'Host' => $config['host'], |
390 | 'Port' => $config['port'], |
391 | 'Timeout' => $config['timeout'], |
392 | 'Database' => $config['database'], |
393 | 'Prefix' => $config['prefix'], |
394 | 'Lock Attempts' => $config['lock_attempts'], |
395 | 'Lock Sleep' => $config['lock_sleep'], |
396 | 'Lock TTL' => $config['lock_ttl'], |
397 | 'Maxlifetime' => $config['maxlifetime'] ?? \ini_get('session.gc_maxlifetime'), |
398 | 'Match IP' => $config['match_ip'] ? 'Yes' : 'No', |
399 | 'Match User-Agent' => $config['match_ua'] ? 'Yes' : 'No', |
400 | ]; |
401 | } |
402 | if ($this->saveHandler instanceof DatabaseHandler) { |
403 | return [ |
404 | 'Host' => $config['host'], |
405 | 'Schema' => $config['schema'], |
406 | 'Table' => $config['table'], |
407 | 'Columns' => [ |
408 | [ |
409 | 'id' => $config['columns']['id'], |
410 | 'data' => $config['columns']['data'], |
411 | 'timestamp' => $config['columns']['timestamp'], |
412 | 'ip' => $config['columns']['ip'], |
413 | 'ua' => $config['columns']['ua'], |
414 | 'user_id' => $config['columns']['user_id'], |
415 | ], |
416 | ], |
417 | 'Maxlifetime' => $config['maxlifetime'] ?? \ini_get('session.gc_maxlifetime'), |
418 | 'Match IP' => $config['match_ip'] ? 'Yes' : 'No', |
419 | 'Match User-Agent' => $config['match_ua'] ? 'Yes' : 'No', |
420 | 'Save IP' => $config['save_ip'] ? 'Yes' : 'No', |
421 | 'Save User-Agent' => $config['save_ua'] ? 'Yes' : 'No', |
422 | 'Save User Id' => $config['save_user_id'] ? 'Yes' : 'No', |
423 | ]; |
424 | } |
425 | return []; |
426 | } |
427 | } |