Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
25 / 25 |
|
100.00% |
8 / 8 |
CRAP | |
100.00% |
1 / 1 |
CookieJar | |
100.00% |
25 / 25 |
|
100.00% |
8 / 8 |
16 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
lock | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isLocked | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
set | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
get | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
delete | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
4 | |||
remove | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
save | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\DataStorage\Cookie |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\DataStorage\Cookie; |
16 | |
17 | use phpOMS\DataStorage\LockException; |
18 | |
19 | /** |
20 | * CookieJar class |
21 | * |
22 | * @package phpOMS\DataStorage\Cookie |
23 | * @license OMS License 2.0 |
24 | * @link https://jingga.app |
25 | * @since 1.0.0 |
26 | */ |
27 | final class CookieJar |
28 | { |
29 | /** |
30 | * Locked. |
31 | * |
32 | * @var bool |
33 | * @since 1.0.0 |
34 | */ |
35 | private static bool $isLocked = false; |
36 | |
37 | /** |
38 | * Cookie values. |
39 | * |
40 | * @var array |
41 | * @since 1.0.0 |
42 | */ |
43 | private array $cookies = []; |
44 | |
45 | /** |
46 | * Constructor. |
47 | * |
48 | * @since 1.0.0 |
49 | * |
50 | * @SuppressWarnings(PHPMD.Superglobals) |
51 | */ |
52 | public function __construct() |
53 | { |
54 | $this->cookies = $_COOKIE; |
55 | } |
56 | |
57 | /** |
58 | * Lock |
59 | * |
60 | * @return void |
61 | * |
62 | * @since 1.0.0 |
63 | */ |
64 | public static function lock() : void |
65 | { |
66 | self::$isLocked = true; |
67 | } |
68 | |
69 | /** |
70 | * Is locked? |
71 | * |
72 | * @return bool |
73 | * |
74 | * @since 1.0.0 |
75 | */ |
76 | public static function isLocked() : bool |
77 | { |
78 | return self::$isLocked; |
79 | } |
80 | |
81 | /** |
82 | * Set pending cookie |
83 | * |
84 | * @param string $id Cookie id |
85 | * @param mixed $value Cookie value |
86 | * @param int $expire Expire time |
87 | * @param string $path Path |
88 | * @param string $domain Domain |
89 | * @param bool $secure Is secure |
90 | * @param bool $httpOnly Allow only http access |
91 | * @param bool $overwrite Overwrite if already set |
92 | * |
93 | * @return bool |
94 | * |
95 | * @since 1.0.0 |
96 | */ |
97 | public function set( |
98 | string $id, |
99 | mixed $value, |
100 | int $expire = 86400, |
101 | string $path = '/', |
102 | string $domain = null, |
103 | bool $secure = false, |
104 | bool $httpOnly = true, |
105 | bool $overwrite = true |
106 | ) : bool |
107 | { |
108 | if ($overwrite || !isset($this->cookies[$id])) { |
109 | $this->cookies[$id] = [ |
110 | 'value' => $value, |
111 | 'expires' => $expire, |
112 | 'path' => $path, |
113 | 'domain' => $domain, |
114 | 'secure' => $secure, |
115 | 'httponly' => $httpOnly, |
116 | ]; |
117 | |
118 | return true; |
119 | } |
120 | |
121 | return false; |
122 | } |
123 | |
124 | /** |
125 | * Get cookie value |
126 | * |
127 | * @param string $id Cookie id |
128 | * |
129 | * @return mixed |
130 | * |
131 | * @since 1.0.0 |
132 | */ |
133 | public function get(string $id) : mixed |
134 | { |
135 | return $this->cookies[$id] ?? null; |
136 | } |
137 | |
138 | /** |
139 | * Delete already set cookie |
140 | * |
141 | * @param string $id Cookie id to remove |
142 | * |
143 | * @return bool |
144 | * |
145 | * @throws LockException Throws this exception if the cookie is already sent |
146 | * |
147 | * @since 1.0.0 |
148 | */ |
149 | public function delete(string $id) : bool |
150 | { |
151 | if ($this->remove($id)) { |
152 | if (self::$isLocked) { |
153 | throw new LockException('CookieJar'); |
154 | } |
155 | |
156 | // @codeCoverageIgnoreStart |
157 | if (!\headers_sent()) { |
158 | \setcookie($id, '', \time() - 3600); |
159 | |
160 | return true; |
161 | } |
162 | |
163 | return false; |
164 | // @codeCoverageIgnoreEnd |
165 | } |
166 | |
167 | return false; |
168 | } |
169 | |
170 | /** |
171 | * Remove pending cookie |
172 | * |
173 | * @param string $id Cookie id to remove |
174 | * |
175 | * @return bool |
176 | * |
177 | * @since 1.0.0 |
178 | */ |
179 | public function remove(string $id) : bool |
180 | { |
181 | if (isset($this->cookies[$id])) { |
182 | unset($this->cookies[$id]); |
183 | |
184 | return true; |
185 | } |
186 | |
187 | return false; |
188 | } |
189 | |
190 | /** |
191 | * Save cookie |
192 | * |
193 | * @return void |
194 | * |
195 | * @throws LockException Throws this exception if the cookie is already sent |
196 | * |
197 | * @since 1.0.0 |
198 | */ |
199 | public function save() : void |
200 | { |
201 | if (self::$isLocked) { |
202 | throw new LockException('CookieJar'); |
203 | } |
204 | |
205 | // @codeCoverageIgnoreStart |
206 | foreach ($this->cookies as $key => $cookie) { |
207 | \setcookie($key, $cookie['value'], [ |
208 | 'expires' => $cookie['expires'], |
209 | 'path' => $cookie['path'], |
210 | 'domain' => $cookie['domain'], |
211 | 'secure' => $cookie['secure'], |
212 | 'httponly' => $cookie['httponly'], |
213 | 'samesite' => 'Strict', |
214 | ]); |
215 | } |
216 | // @codeCoverageIgnoreEnd |
217 | } |
218 | } |