PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.2.4
Kirki – Freeform Page Builder, Website Builder & Customizer v6.2.4
6.2.5 6.2.4 6.2.3 6.2.2 6.2.1 6.2.0 6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / libraries / framework / Http / Cookie.php
kirki / libraries / framework / Http Last commit date
Client 1 week ago Concerns 1 week ago Cookie.php 1 week ago JsonResponse.php 1 week ago RedirectResponse.php 1 week ago Request.php 1 week ago Response.php 1 week ago
Cookie.php
390 lines
1 <?php
2
3 /**
4 * Immutable value object describing a single HTTP cookie and its attributes.
5 * Normalizes the same-site attribute and validates the name against header injection.
6 * Converts itself into a setcookie() options array or a Set-Cookie header string.
7 *
8 * @package Framework
9 * @subpackage Http
10 * @since 1.0.0
11 */
12 namespace Kirki\Framework\Http;
13
14 \defined('ABSPATH') || exit;
15 use InvalidArgumentException;
16 class Cookie
17 {
18 /**
19 * The same site lax value.
20 *
21 * @var string
22 *
23 * @since 1.0.0
24 */
25 public const SAME_SITE_LAX = 'Lax';
26 /**
27 * The same site strict value.
28 *
29 * @var string
30 *
31 * @since 1.0.0
32 */
33 public const SAME_SITE_STRICT = 'Strict';
34 /**
35 * The same site none value.
36 *
37 * @var string
38 *
39 * @since 1.0.0
40 */
41 public const SAME_SITE_NONE = 'None';
42 /**
43 * The characters that may never appear in a cookie name.
44 *
45 * @var string
46 *
47 * @since 1.0.0
48 */
49 protected const RESERVED_CHARACTERS = "=,; \t\r\n\v\f";
50 /**
51 * The name of the cookie.
52 *
53 * @var string
54 *
55 * @since 1.0.0
56 */
57 protected $name;
58 /**
59 * The value of the cookie.
60 *
61 * @var string
62 *
63 * @since 1.0.0
64 */
65 protected $value;
66 /**
67 * The unix timestamp at which the cookie expires. Zero means a session cookie.
68 *
69 * @var int
70 *
71 * @since 1.0.0
72 */
73 protected $expire;
74 /**
75 * The path the cookie is scoped to.
76 *
77 * @var string
78 *
79 * @since 1.0.0
80 */
81 protected $path;
82 /**
83 * The domain the cookie is scoped to.
84 *
85 * @var string|null
86 *
87 * @since 1.0.0
88 */
89 protected $domain;
90 /**
91 * Whether the cookie is restricted to secure connections.
92 *
93 * @var bool
94 *
95 * @since 1.0.0
96 */
97 protected $secure;
98 /**
99 * Whether the cookie is hidden from client side scripts.
100 *
101 * @var bool
102 *
103 * @since 1.0.0
104 */
105 protected $http_only;
106 /**
107 * Whether the value is sent without URL encoding.
108 *
109 * @var bool
110 *
111 * @since 1.0.0
112 */
113 protected $raw;
114 /**
115 * The same site policy of the cookie.
116 *
117 * @var string|null
118 *
119 * @since 1.0.0
120 */
121 protected $same_site;
122 /**
123 * Create a new cookie instance.
124 *
125 * @param string $name The name of the cookie.
126 * @param string $value The value of the cookie.
127 * @param int $expire The unix timestamp at which the cookie expires, zero for a session cookie.
128 * @param string|null $path The path the cookie is scoped to.
129 * @param string|null $domain The domain the cookie is scoped to.
130 * @param bool|null $secure Whether the cookie is restricted to secure connections.
131 * @param bool $http_only Whether the cookie is hidden from client side scripts.
132 * @param bool $raw Whether the value is sent without URL encoding.
133 * @param string|null $same_site The same site policy of the cookie.
134 *
135 * @return void
136 *
137 * @throws \InvalidArgumentException When the name or the same site policy is invalid.
138 *
139 * @since 1.0.0
140 */
141 public function __construct(string $name, string $value = '', int $expire = 0, ?string $path = '/', ?string $domain = null, ?bool $secure = \false, bool $http_only = \true, bool $raw = \false, ?string $same_site = null)
142 {
143 $this->validate_name($name);
144 $this->name = $name;
145 $this->value = $value;
146 $this->expire = $expire;
147 $this->path = $path === null || $path === '' ? '/' : $path;
148 $this->domain = $domain;
149 $this->secure = (bool) $secure;
150 $this->http_only = $http_only;
151 $this->raw = $raw;
152 $this->same_site = $this->normalize_same_site($same_site);
153 if ($this->same_site === static::SAME_SITE_NONE) {
154 $this->secure = \true;
155 }
156 }
157 /**
158 * Get the name of the cookie.
159 *
160 * @return string
161 *
162 * @since 1.0.0
163 */
164 public function get_name()
165 {
166 return $this->name;
167 }
168 /**
169 * Get the value of the cookie.
170 *
171 * @return string
172 *
173 * @since 1.0.0
174 */
175 public function get_value()
176 {
177 return $this->value;
178 }
179 /**
180 * Get the unix timestamp at which the cookie expires.
181 *
182 * @return int
183 *
184 * @since 1.0.0
185 */
186 public function get_expires_time()
187 {
188 return $this->expire;
189 }
190 /**
191 * Get the number of seconds until the cookie expires.
192 *
193 * @return int
194 *
195 * @since 1.0.0
196 */
197 public function get_max_age()
198 {
199 $age = $this->expire - \time();
200 return \max(0, $age);
201 }
202 /**
203 * Get the path the cookie is scoped to.
204 *
205 * @return string
206 *
207 * @since 1.0.0
208 */
209 public function get_path()
210 {
211 return $this->path;
212 }
213 /**
214 * Get the domain the cookie is scoped to.
215 *
216 * @return string|null
217 *
218 * @since 1.0.0
219 */
220 public function get_domain()
221 {
222 return $this->domain;
223 }
224 /**
225 * Get the same site policy of the cookie.
226 *
227 * @return string|null
228 *
229 * @since 1.0.0
230 */
231 public function get_same_site()
232 {
233 return $this->same_site;
234 }
235 /**
236 * Determine whether the cookie is restricted to secure connections.
237 *
238 * @return bool
239 *
240 * @since 1.0.0
241 */
242 public function is_secure()
243 {
244 return $this->secure;
245 }
246 /**
247 * Determine whether the cookie is hidden from client side scripts.
248 *
249 * @return bool
250 *
251 * @since 1.0.0
252 */
253 public function is_http_only()
254 {
255 return $this->http_only;
256 }
257 /**
258 * Determine whether the value is sent without URL encoding.
259 *
260 * @return bool
261 *
262 * @since 1.0.0
263 */
264 public function is_raw()
265 {
266 return $this->raw;
267 }
268 /**
269 * Determine whether the cookie is a session cookie.
270 *
271 * @return bool
272 *
273 * @since 1.0.0
274 */
275 public function is_session()
276 {
277 return $this->expire === 0;
278 }
279 /**
280 * Determine whether the cookie has already expired.
281 *
282 * @return bool
283 *
284 * @since 1.0.0
285 */
286 public function is_expired()
287 {
288 return !$this->is_session() && $this->expire < \time();
289 }
290 /**
291 * Get the cookie as an options array for the setcookie function.
292 *
293 * @return array
294 *
295 * @since 1.0.0
296 */
297 public function to_options()
298 {
299 $options = ['expires' => $this->expire, 'path' => $this->path, 'domain' => $this->domain ?? '', 'secure' => $this->secure, 'httponly' => $this->http_only];
300 if ($this->same_site !== null) {
301 $options['samesite'] = $this->same_site;
302 }
303 return $options;
304 }
305 /**
306 * Get the cookie as a Set-Cookie header string.
307 *
308 * @return string
309 *
310 * @since 1.0.0
311 */
312 public function to_header_string()
313 {
314 $value = $this->raw ? $this->value : \rawurlencode($this->value);
315 $header = $this->name . '=' . $value;
316 if ($this->expire !== 0) {
317 $header .= '; expires=' . \gmdate('D, d-M-Y H:i:s T', $this->expire);
318 $header .= '; Max-Age=' . $this->get_max_age();
319 }
320 $header .= '; path=' . $this->path;
321 if (!empty($this->domain)) {
322 $header .= '; domain=' . $this->domain;
323 }
324 if ($this->secure) {
325 $header .= '; secure';
326 }
327 if ($this->http_only) {
328 $header .= '; HttpOnly';
329 }
330 if ($this->same_site !== null) {
331 $header .= '; SameSite=' . $this->same_site;
332 }
333 return $header;
334 }
335 /**
336 * Get the string representation of the cookie.
337 *
338 * @return string
339 *
340 * @since 1.0.0
341 */
342 public function __toString()
343 {
344 return $this->to_header_string();
345 }
346 /**
347 * Normalize the same site policy to a supported value.
348 *
349 * @param string|null $same_site The same site policy to normalize.
350 *
351 * @return string|null
352 *
353 * @throws \InvalidArgumentException When the policy is not supported.
354 *
355 * @since 1.0.0
356 */
357 protected function normalize_same_site($same_site)
358 {
359 if ($same_site === null || $same_site === '') {
360 return null;
361 }
362 $supported = ['lax' => static::SAME_SITE_LAX, 'strict' => static::SAME_SITE_STRICT, 'none' => static::SAME_SITE_NONE];
363 $normalized = \strtolower((string) $same_site);
364 if (!isset($supported[$normalized])) {
365 throw new InvalidArgumentException(\sprintf('The same site attribute "%s" is invalid.', $same_site));
366 }
367 return $supported[$normalized];
368 }
369 /**
370 * Validate the cookie name against empty and reserved characters.
371 *
372 * @param string $name The name to validate.
373 *
374 * @return void
375 *
376 * @throws \InvalidArgumentException When the name is empty or contains reserved characters.
377 *
378 * @since 1.0.0
379 */
380 protected function validate_name(string $name)
381 {
382 if ($name === '') {
383 throw new InvalidArgumentException('The cookie name cannot be empty.');
384 }
385 if (\strpbrk($name, static::RESERVED_CHARACTERS) !== \false) {
386 throw new InvalidArgumentException(\sprintf('The cookie name "%s" contains invalid characters.', $name));
387 }
388 }
389 }
390