-
-
Notifications
You must be signed in to change notification settings - Fork 219
/
FileSession.php
104 lines (78 loc) · 2.13 KB
/
FileSession.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<?php
/**
* This file is part of the Tracy (https://tracy.nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Tracy;
class FileSession implements SessionStorage
{
private const FilePrefix = 'tracy-';
private const CookieLifetime = 31_557_600;
public string $cookieName = 'tracy-session';
/** probability that the clean() routine is started */
public float $gcProbability = 0.001;
private string $dir;
/** @var resource */
private $file;
private array $data = [];
public function __construct(string $dir)
{
$this->dir = $dir;
}
public function isAvailable(): bool
{
if (!$this->file) {
$this->open();
}
return true;
}
private function open(): void
{
$id = $_COOKIE[$this->cookieName] ?? null;
if (
!is_string($id)
|| !preg_match('#^\w{10}\z#i', $id)
|| !($file = @fopen($path = $this->dir . '/' . self::FilePrefix . $id, 'r+')) // intentionally @
) {
$id = Helpers::createId();
setcookie($this->cookieName, $id, time() + self::CookieLifetime, '/', '', false, true);
$file = @fopen($path = $this->dir . '/' . self::FilePrefix . $id, 'c+'); // intentionally @
if ($file === false) {
throw new \RuntimeException("Unable to create file '$path'. " . error_get_last()['message']);
}
}
if (!@flock($file, LOCK_EX)) { // intentionally @
throw new \RuntimeException("Unable to acquire exclusive lock on '$path'. ", error_get_last()['message']);
}
$this->file = $file;
$this->data = @unserialize(stream_get_contents($this->file)) ?: []; // @ - file may be empty
if (mt_rand() / mt_getrandmax() < $this->gcProbability) {
$this->clean();
}
}
public function &getData(): array
{
return $this->data;
}
public function clean(): void
{
$old = strtotime('-1 week');
foreach (glob($this->dir . '/' . self::FilePrefix . '*') as $file) {
if (filemtime($file) < $old) {
unlink($file);
}
}
}
public function __destruct()
{
if (!$this->file) {
return;
}
ftruncate($this->file, 0);
fseek($this->file, 0);
fwrite($this->file, serialize($this->data));
fclose($this->file);
$this->file = null;
}
}