Passed
Push — master ( 974680...fc5316 )
by Kirill
03:59
created

Cookie::isHttpOnly()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Cookies;
13
14
/**
15
 * Represent singular cookie header value with packing abilities.
16
 */
17
final class Cookie
18
{
19
    /**
20
     * The name of the cookie.
21
     *
22
     * @var string
23
     */
24
    private $name;
25
26
    /**
27
     * The value of the cookie. This value is stored on the clients computer; do not store sensitive information.
28
     *
29
     * @var string|null
30
     */
31
    private $value;
32
33
    /**
34
     * Cookie lifetime. This value specified in seconds and declares period of time in which cookie will expire
35
     * relatively to current time() value.
36
     *
37
     * @var int|null
38
     */
39
    private $lifetime;
40
41
    /**
42
     * The path on the server in which the cookie will be available on.
43
     * If set to '/', the cookie will be available within the entire domain. If set to '/foo/', the cookie will only be
44
     * available within the /foo/ directory and all sub-directories such as /foo/bar/ of domain. The default value is
45
     * the current directory that the cookie is being set in.
46
     *
47
     * @var string|null
48
     */
49
    private $path;
50
51
    /**
52
     * The domain that the cookie is available. To make the cookie available on all subdomains ofexample.com then you'd
53
     * set it to '.example.com'. The . is not required but makes itcompatible with more browsers. Setting it to
54
     * www.example.com will make the cookie onlyavailable in the www subdomain. Refer to tail matching in the spec for
55
     * details.
56
     *
57
     * @var string|null
58
     */
59
    private $domain;
60
61
    /**
62
     * Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client. When set to
63
     * true, the cookie will only be set if a secure connection exists. On the server-side, it's on the programmer to
64
     * send this kind of cookie only on secure connection (e.g. with respect to $_SERVER["HTTPS"]).
65
     *
66
     * @var bool
67
     */
68
    private $secure;
69
70
    /**
71
     * When true the cookie will be made accessible only through the HTTP protocol. This means that the cookie won't be
72
     * accessible by scripting languages, such as JavaScript. This setting can effectively help to reduce identity
73
     * theft through XSS attacks (although it is not supported by all browsers).
74
     *
75
     * @var bool
76
     */
77
    private $httpOnly;
78
79
    /**
80
     * The value of the samesite element should be either None, Lax or Strict. If any of the allowed options are not
81
     * given, their default values are the same as the default values of the explicit parameters. If the samesite
82
     * element is omitted, no SameSite cookie attribute is set. When Same-Site attribute is set to "None" it is
83
     * required to have "Secure" attribute enable. Otherwise it will be converted to "Lax".
84
     *
85
     * @var Cookie\SameSite
86
     */
87
    private $sameSite;
88
89
    /**
90
     * New Cookie instance, cookies used to schedule cookie set while dispatching Response.
91
     *
92
     * @link http://php.net/manual/en/function.setcookie.php
93
     *
94
     * @param string      $name     The name of the cookie.
95
     * @param string|null $value    The value of the cookie. This value is stored on the clients computer; do not store
96
     *                              sensitive information.
97
     * @param int|null    $lifetime Cookie lifetime. This value specified in seconds and declares period of time in
98
     *                              which cookie will expire relatively to current time() value.
99
     * @param string|null $path     The path on the server in which the cookie will be available on. If set to '/', the
100
     *                              cookie will be available within the entire domain. If set to '/foo/', the cookie
101
     *                              will only be available within the /foo/ directory and all sub-directories such as
102
     *                              /foo/bar/ of domain. The default value is the current directory that the cookie is
103
     *                              being set in.
104
     * @param string|null $domain   The domain that the cookie is available. To make the cookie available on all
105
     *                              subdomains of example.com then you'd set it to '.example.com'. The . is not
106
     *                              required but makes it compatible with more browsers. Setting it to www.example.com
107
     *                              will make the cookie only available in the www subdomain. Refer to tail matching in
108
     *                              the spec for details.
109
     * @param bool        $secure   Indicates that the cookie should only be transmitted over a secure HTTPS connection
110
     *                              from the client. When set to true, the cookie will only be set if a secure
111
     *                              connection exists. On the server-side, it's on the programmer to send this kind of
112
     *                              cookie only on secure connection (e.g. with respect to $_SERVER["HTTPS"]).
113
     * @param bool        $httpOnly When true the cookie will be made accessible only through the HTTP protocol. This
114
     *                              means that the cookie won't be accessible by scripting languages, such as
115
     *                              JavaScript. This setting can effectively help to reduce identity theft through XSS
116
     *                              attacks (although it is not supported by all browsers).
117
     * @param string|null $sameSite The value of the samesite element should be either None, Lax or Strict. If any of
118
     *                              the allowed options are not given, their default values are the same as the default
119
     *                              values of the explicit parameters. If the samesite element is omitted, no SameSite
120
     *                              cookie attribute is set. When Same-Site attribute is set to "None" it is required
121
     *                              to have "Secure" attribute enable. Otherwise it will be converted to "Lax".
122
     */
123
    public function __construct(
124
        string $name,
125
        ?string $value = null,
126
        ?int $lifetime = null,
127
        ?string $path = null,
128
        ?string $domain = null,
129
        bool $secure = false,
130
        bool $httpOnly = true,
131
        ?string $sameSite = null
132
    ) {
133
        $this->name = $name;
134
        $this->value = $value;
135
        $this->lifetime = $lifetime;
136
        $this->path = $path;
137
        $this->domain = $domain;
138
        $this->secure = $secure;
139
        $this->httpOnly = $httpOnly;
140
        $this->sameSite = new Cookie\SameSite($sameSite, $secure);
141
    }
142
143
    /**
144
     * @return string
145
     */
146
    public function __toString(): string
147
    {
148
        return $this->createHeader();
149
    }
150
151
    /**
152
     * The name of the cookie.
153
     *
154
     * @return string
155
     */
156
    public function getName(): string
157
    {
158
        return $this->name;
159
    }
160
161
    /**
162
     * The value of the cookie. This value is stored on the clients computer; do not store sensitive information.
163
     *
164
     * @return string|null
165
     */
166
    public function getValue(): ?string
167
    {
168
        return $this->value;
169
    }
170
171
    /**
172
     * The path on the server in which the cookie will be available on. If set to '/', the cookie will be available
173
     * within the entire domain. If set to '/foo/', the cookie will only be available within the /foo/ directory and
174
     * all sub-directories such as /foo/bar/ of domain. The default value is the current directory that the cookie is
175
     * being set in.
176
     *
177
     * @return string|null
178
     */
179
    public function getPath(): ?string
180
    {
181
        return $this->path;
182
    }
183
184
    /**
185
     * The domain that the cookie is available. To make the cookie available on all subdomains of example.com then
186
     * you'd set it to '.example.com'. The . is not required but makes it compatible with more browsers. Setting it to
187
     * www.example.com will make the cookie only available in the www subdomain. Refer to tail matching in the spec for
188
     * details.
189
     *
190
     * @return string|null
191
     */
192
    public function getDomain(): ?string
193
    {
194
        return $this->domain;
195
    }
196
197
    /**
198
     * Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client. When set to
199
     * true, the cookie will only be set if a secure connection exists. On the server-side, it's on the programmer to
200
     * send this kind of cookie only on secure connection (e.g. with respect to $_SERVER["HTTPS"]).
201
     *
202
     * @return bool
203
     */
204
    public function isSecure(): bool
205
    {
206
        return $this->secure;
207
    }
208
209
    /**
210
     * When true the cookie will be made accessible only through the HTTP protocol. This means that the cookie won't be
211
     * accessible by scripting languages, such as JavaScript. This setting can effectively help to reduce identity
212
     * theft through XSS attacks (although it is not supported by all browsers).
213
     *
214
     * @return bool
215
     */
216
    public function isHttpOnly(): bool
217
    {
218
        return $this->httpOnly;
219
    }
220
221
    /**
222
     * The value of the samesite element should be either None, Lax or Strict. If any of the allowed options are not
223
     * given, their default values are the same as the default values of the explicit parameters. If the samesite
224
     * element is omitted, no SameSite cookie attribute is set. When Same-Site attribute is set to "None" it is
225
     * required to have "Secure" attribute enable. Otherwise it will be converted to "Lax".
226
     *
227
     * @return string
228
     */
229
    public function getSameSite(): ?string
230
    {
231
        return $this->sameSite->get();
232
    }
233
234
    /**
235
     * Get new cookie with altered value. Original cookie object should not be changed.
236
     *
237
     * @param string $value
238
     * @return Cookie
239
     */
240
    public function withValue(string $value): self
241
    {
242
        $cookie = clone $this;
243
        $cookie->value = $value;
244
245
        return $cookie;
246
    }
247
248
    /**
249
     * Convert cookie instance to string.
250
     *
251
     * @link http://www.w3.org/Protocols/rfc2109/rfc2109
252
     * @return string
253
     */
254
    public function createHeader(): string
255
    {
256
        $header = [rawurlencode($this->name) . '=' . rawurlencode((string)$this->value)];
257
258
        if ($this->lifetime !== null) {
259
            $header[] = 'Expires=' . gmdate(\DateTime::COOKIE, $this->getExpires());
260
            $header[] = "Max-Age={$this->lifetime}";
261
        }
262
263
        if (!empty($this->path)) {
264
            $header[] = "Path={$this->path}";
265
        }
266
267
        if (!empty($this->domain)) {
268
            $header[] = "Domain={$this->domain}";
269
        }
270
271
        if ($this->secure) {
272
            $header[] = 'Secure';
273
        }
274
275
        if ($this->httpOnly) {
276
            $header[] = 'HttpOnly';
277
        }
278
279
        if ($this->sameSite->get() !== null) {
280
            $header[] = "SameSite={$this->sameSite->get()}";
281
        }
282
283
        return implode('; ', $header);
284
    }
285
286
    /**
287
     * The time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch. In other
288
     * words, you'll most likely set this with the time function plus the number of seconds before you want it to
289
     * expire. Or you might use mktime. Will return null if lifetime is not specified.
290
     *
291
     * @return int|null
292
     */
293
    public function getExpires(): ?int
294
    {
295
        if ($this->lifetime === null) {
296
            return null;
297
        }
298
299
        return time() + $this->lifetime;
300
    }
301
302
    /**
303
     * New Cookie instance, cookies used to schedule cookie set while dispatching Response. Static constructor.
304
     *
305
     * @link http://php.net/manual/en/function.setcookie.php
306
     *
307
     * @param string      $name     The name of the cookie.
308
     * @param string|null $value    The value of the cookie. This value is stored on the clients computer; do not store
309
     *                              sensitive information.
310
     * @param int|null    $lifetime Cookie lifetime. This value specified in seconds and declares period of time in
311
     *                              which cookie will expire relatively to current time() value.
312
     * @param string|null $path     The path on the server in which the cookie will be available on. If set to '/', the
313
     *                              cookie will be available within the entire domain. If set to '/foo/', the cookie
314
     *                              will only be available within the /foo/ directory and all sub-directories such as
315
     *                              /foo/bar/ of domain. The default value is the current directory that the cookie is
316
     *                              being set in.
317
     * @param string|null $domain   The domain that the cookie is available. To make the cookie available on all
318
     *                              subdomains of example.com then you'd set it to '.example.com'. The . is not
319
     *                              required but makes it compatible with more browsers. Setting it to www.example.com
320
     *                              will make the cookie only available in the www subdomain. Refer to tail matching in
321
     *                              the spec for details.
322
     * @param bool        $secure   Indicates that the cookie should only be transmitted over a secure HTTPS connection
323
     *                              from the client. When set to true, the cookie will only be set if a secure
324
     *                              connection exists. On the server-side, it's on the programmer to send this kind of
325
     *                              cookie only on secure connection (e.g. with respect to $_SERVER["HTTPS"]).
326
     * @param bool        $httpOnly When true the cookie will be made accessible only through the HTTP protocol. This
327
     *                              means that the cookie won't be accessible by scripting languages, such as
328
     *                              JavaScript. This setting can effectively help to reduce identity theft through XSS
329
     *                              attacks (although it is not supported by all browsers).
330
     * @param string|null $sameSite The value of the samesite element should be either None, Lax or Strict. If any of
331
     *                              the allowed options are not given, their default values are the same as the default
332
     *                              values of the explicit parameters. If the samesite element is omitted, no SameSite
333
     *                              cookie attribute is set. When Same-Site attribute is set to "None" it is required
334
     *                              to have "Secure" attribute enable. Otherwise it will be converted to "Lax".
335
     * @return Cookie
336
     */
337
    public static function create(
338
        string $name,
339
        ?string $value = null,
340
        ?int $lifetime = null,
341
        ?string $path = null,
342
        ?string $domain = null,
343
        bool $secure = false,
344
        bool $httpOnly = true,
345
        ?string $sameSite = null
346
    ): self {
347
        return new self($name, $value, $lifetime, $path, $domain, $secure, $httpOnly, $sameSite);
348
    }
349
}
350