SetCookieHeader::has()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 4
rs 10
c 1
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/*
3
 * This file is part of the Borobudur-Http package.
4
 *
5
 * (c) Hexacodelabs <http://hexacodelabs.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
11
namespace Borobudur\Http\Header;
12
13
use Borobudur\Http\Header\Exception\InvalidHeaderValueException;
14
use DateTime;
15
use DateTimeZone;
16
17
/**
18
 * @author      Iqbal Maulana <[email protected]>
19
 * @created     7/28/15
20
 */
21
class SetCookieHeader implements HeaderInterface
22
{
23
    /**
24
     * Expires date format.
25
     */
26
    const DATE_FORMAT = 'D, d M Y H:i:s \G\M\T';
27
28
    /**
29
     * @var array
30
     */
31
    private $parts = array();
32
33
    /**
34
     * @var string
35
     */
36
    private $name;
37
38
    /**
39
     * @var string
40
     */
41
    private $value;
42
43
    /**
44
     * @var bool
45
     */
46
    private $httpOnly = false;
47
48
    /**
49
     * @var bool
50
     */
51
    private $secure = false;
52
53
    /**
54
     * Constructor.
55
     *
56
     * @param string|null   $name
57
     * @param string|null   $value
58
     * @param int|null      $version
59
     * @param int|null      $maxAge
60
     * @param string|null   $domain
61
     * @param string|null   $path
62
     * @param DateTime|null $expires
63
     * @param bool|false    $httpOnly
64
     * @param bool|false    $secure
65
     */
66
    public function __construct(
67
        $name = null,
68
        $value = null,
69
        $version = null,
70
        $maxAge = null,
71
        $domain = null,
72
        $path = null,
73
        DateTime $expires = null,
74
        $httpOnly = false,
75
        $secure = false
76
    ) {
77
        if (null !== $name) {
78
            $this->setName($name);
79
        }
80
81
        if (null !== $value) {
82
            $this->setValue($value);
83
        }
84
85
        if (null !== $version) {
86
            $this->setVersion($version);
87
        }
88
89
        if (null !== $maxAge) {
90
            $this->setMaxAge($maxAge);
91
        }
92
93
        if (null !== $domain) {
94
            $this->setDomain($domain);
95
        }
96
97
        if (null !== $path) {
98
            $this->setPath($path);
99
        }
100
101
        if (null !== $expires) {
102
            $this->setExpires($expires);
103
        }
104
105
        $this->setHttpOnly($httpOnly);
106
        $this->setSecure($secure);
107
    }
108
109
    /**
110
     * Factory create SetCookieHeader from string representation.
111
     *
112
     * @param string $headerLine
113
     *
114
     * @return $this
115
     */
116
    public static function fromString($headerLine)
117
    {
118
        $pos = strpos($headerLine, ':');
119
        $fieldName = trim(substr($headerLine, 0, $pos));
120
        $fieldValue = trim(substr($headerLine, $pos + 1));
121
        GenericHeader::assertHeaderFieldName('Set-Cookie', $fieldName);
122
123
        return self::create($fieldValue);
124
    }
125
126
    /**
127
     * Factory create header.
128
     *
129
     * @param string $fieldValue
130
     *
131
     * @return $this
132
     */
133
    private static function create($fieldValue)
134
    {
135
        $header = new static();
136
        foreach (explode(';', $fieldValue) as $index => $item) {
137
            $parts = explode('=', $item, 2);
138
139
            if (0 === $index) {
140
                $header->setName($parts[0]);
141
                $header->setValue($parts[1]);
142
                continue;
143
            }
144
145
            $header->setDirective($parts[0], isset($parts[1]) ? $parts[1] : null);
146
        }
147
148
        return $header;
149
    }
150
151
    /**
152
     * Get header field name.
153
     *
154
     * @return string
155
     */
156
    public function getFieldName()
157
    {
158
        return 'Set-Cookie';
159
    }
160
161
    /**
162
     * Set name.
163
     *
164
     * @param string $name
165
     *
166
     * @return $this
167
     */
168
    public function setName($name)
169
    {
170
        GenericHeader::assertHeaderValue($name);
171
        $this->name = $name;
172
173
        return $this;
174
    }
175
176
    /**
177
     * Get name.
178
     *
179
     * @return string
180
     */
181
    public function getName()
182
    {
183
        return $this->name;
184
    }
185
186
    /**
187
     * Set value.
188
     *
189
     * @param string $value
190
     *
191
     * @return $this
192
     */
193
    public function setValue($value)
194
    {
195
        GenericHeader::assertHeaderValue($value);
196
        $this->value = $value;
197
198
        return $this;
199
    }
200
201
    /**
202
     * Get value.
203
     *
204
     * @return string
205
     */
206
    public function getValue()
207
    {
208
        return $this->value;
209
    }
210
211
    /**
212
     * Set cookie version.
213
     *
214
     * @param int $version
215
     *
216
     * @return $this
217
     *
218
     * @throws InvalidHeaderValueException
219
     */
220
    public function setVersion($version)
221
    {
222
        if (!is_numeric($version)) {
223
            throw new InvalidHeaderValueException('Invalid Version number specified');
224
        }
225
226
        $this->set('version', (int) $version);
227
228
        return $this;
229
    }
230
231
    /**
232
     * Get cookie version.
233
     *
234
     * @return int|null
235
     */
236
    public function getVersion()
237
    {
238
        return $this->get('version');
239
    }
240
241
    /**
242
     * Set cookie max age.
243
     *
244
     * @param int $deltaSeconds
245
     *
246
     * @return $this
247
     */
248
    public function setMaxAge($deltaSeconds)
249
    {
250
        $this->set('max-age', GenericHeader::computeDeltaSeconds($deltaSeconds));
251
252
        return $this;
253
    }
254
255
    /**
256
     * Get max age.
257
     *
258
     * @return int|null
259
     */
260
    public function getMaxAge()
261
    {
262
        return $this->get('max-age');
263
    }
264
265
    /**
266
     * Set cookie domain.
267
     *
268
     * @param string $domain
269
     *
270
     * @return $this
271
     */
272
    public function setDomain($domain)
273
    {
274
        return $this->set('domain', $domain);
275
    }
276
277
    /**
278
     * Get cookie domain.
279
     *
280
     * @return string|null
281
     */
282
    public function getDomain()
283
    {
284
        return $this->get('domain');
285
    }
286
287
    /**
288
     * Set cookie path.
289
     *
290
     * @param string $path
291
     *
292
     * @return $this
293
     */
294
    public function setPath($path)
295
    {
296
        return $this->set('path', $path);
297
    }
298
299
    /**
300
     * Get cookie path.
301
     *
302
     * @return string|null
303
     */
304
    public function getPath()
305
    {
306
        return $this->get('path');
307
    }
308
309
    /**
310
     * Set cookie as http only.
311
     *
312
     * @param bool $flag
313
     *
314
     * @return $this
315
     */
316
    public function setHttpOnly($flag = true)
317
    {
318
        $this->httpOnly = (bool) $flag;
319
320
        return $this;
321
    }
322
323
    /**
324
     * Check is cookie http only.
325
     *
326
     * @return bool
327
     */
328
    public function isHttpOnly()
329
    {
330
        return $this->httpOnly;
331
    }
332
333
    /**
334
     * Set secure cookie.
335
     *
336
     * @param bool $flag
337
     *
338
     * @return $this
339
     */
340
    public function setSecure($flag = true)
341
    {
342
        $this->secure = (bool) $flag;
343
344
        return $this;
345
    }
346
347
    /**
348
     * Check is cookie secure.
349
     *
350
     * @return bool
351
     */
352
    public function isSecure()
353
    {
354
        return $this->secure;
355
    }
356
357
    /**
358
     * Set cookie expires.
359
     *
360
     * @param DateTime $date
361
     *
362
     * @return $this
363
     */
364
    public function setExpires(DateTime $date)
365
    {
366
        $date->setTimezone(new DateTimeZone('GMT'));
367
        $this->parts['expires'] = $date;
368
369
        return $this;
370
    }
371
372
    /**
373
     * Get expires.
374
     *
375
     * @return DateTime|null
376
     */
377
    public function getExpires()
378
    {
379
        return $this->get('expires');
380
    }
381
382
    /**
383
     * Check that cookie has expires.
384
     *
385
     * @param DateTime|null $now
386
     *
387
     * @return bool
388
     */
389
    public function isExpired(DateTime $now = null)
390
    {
391
        $now = $now ?: new DateTime('now', new DateTimeZone('GMT'));
392
393
        return $this->has('expires') && $this->getExpires() < $now;
394
    }
395
396
    /**
397
     * Get header field value.
398
     *
399
     * @return mixed
400
     */
401
    public function getFieldValue()
402
    {
403
        if (empty($this->name)) {
404
            return '';
405
        }
406
407
        $cookie = sprintf('%s=%s', $this->getName(), $this->getValue());
408
409
        foreach ($this->parts as $key => $value) {
410
            if (null === $value) {
411
                // skip null value (unset)
412
                continue;
413
            }
414
415
            if ($value instanceof DateTime) {
416
                $value = $value->format(self::DATE_FORMAT);
417
            }
418
419
            $cookie .= sprintf(';%s=%s', $key, $value);
420
        }
421
422
        if (true === $this->isHttpOnly()) {
423
            $cookie .= ';HttpOnly';
424
        }
425
426
        if (true === $this->isSecure()) {
427
            $cookie .= ';Secure';
428
        }
429
430
        return $cookie;
431
    }
432
433
    /**
434
     * Set cookie directive.
435
     *
436
     * @param string $key
437
     * @param string $value
438
     *
439
     * @return $this
440
     */
441
    public function setDirective($key, $value)
442
    {
443
        $maps = array(
444
            'httponly' => 'setHttpOnly',
445
            'secure'   => 'setSecure',
446
            'version'  => 'setVersion',
447
            'max-age'  => 'setMaxAge',
448
            'domain'   => 'setDomain',
449
            'path'     => 'setPath',
450
            'expires'  => 'setExpires',
451
        );
452
453
        $key = strtolower($key);
454
455
        if (isset($maps[$key])) {
456
            if (in_array($key, array('httponly', 'secure'))) {
457
                $value = true;
458
            } elseif ('expires' === $key) {
459
                $value = new DateTime($value);
460
            }
461
462
            $this->{$maps[$key]}($value);
463
        } else {
464
            $this->set($key, $value);
465
        }
466
467
        return $this;
468
    }
469
470
    /**
471
     * Cast header to string.
472
     *
473
     * @return string
474
     */
475
    public function __toString()
476
    {
477
        return sprintf('%s: %s', $this->getFieldName(), $this->getFieldValue());
478
    }
479
480
    /**
481
     * Set cookie part.
482
     *
483
     * @param string $key
484
     * @param string $value
485
     *
486
     * @return $this
487
     */
488
    private function set($key, $value)
489
    {
490
        GenericHeader::assertHeaderValue($value);
491
        $this->parts[$key] = $value;
492
493
        return $this;
494
    }
495
496
    /**
497
     * Get cookie part by key.
498
     *
499
     * @param string $key
500
     *
501
     * @return string|int|null
502
     */
503
    private function get($key)
504
    {
505
        return $this->has($key) ? $this->parts[$key] : null;
506
    }
507
508
    /**
509
     * Check is parts has key.
510
     *
511
     * @param string $key
512
     *
513
     * @return bool
514
     */
515
    private function has($key)
516
    {
517
        return array_key_exists($key, $this->parts);
518
    }
519
}
520