Cookie::matchesPath()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Buzz\Middleware\Cookie;
6
7
use Psr\Http\Message\RequestInterface;
8
9
class Cookie
10
{
11
    const ATTR_DOMAIN = 'domain';
12
13
    const ATTR_PATH = 'path';
14
15
    const ATTR_SECURE = 'secure';
16
17
    const ATTR_MAX_AGE = 'max-age';
18
19
    const ATTR_EXPIRES = 'expires';
20
21
    protected $name;
22
23
    protected $value;
24
25
    protected $attributes = [];
26
27
    protected $createdAt;
28
29
    /**
30
     * Constructor.
31
     */
32 16
    public function __construct()
33
    {
34 16
        $this->createdAt = time();
35 16
    }
36
37
    /**
38
     * Returns true if the current cookie matches the supplied request.
39
     *
40
     * @param RequestInterface $request A request object
41
     */
42 5
    public function matchesRequest(RequestInterface $request): bool
43
    {
44 5
        $uri = $request->getUri();
45
        // domain
46 5
        if (!$this->matchesDomain($uri->getHost())) {
47 1
            return false;
48
        }
49
50
        // path
51 5
        if (!$this->matchesPath($uri->getPath())) {
52 1
            return false;
53
        }
54
55
        // secure
56 5
        if ($this->hasAttribute(static::ATTR_SECURE) && 'https' !== $uri->getScheme()) {
57 1
            return false;
58
        }
59
60 5
        return true;
61
    }
62
63
    /**
64
     * Returns true of the current cookie has expired.
65
     *
66
     * Checks the max-age and expires attributes.
67
     *
68
     * @return bool Whether the current cookie has expired
69
     */
70 3
    public function isExpired(): bool
71
    {
72 3
        $maxAge = $this->getAttribute(static::ATTR_MAX_AGE);
73 3
        if ($maxAge && time() - $this->getCreatedAt() > $maxAge) {
74 2
            return true;
75
        }
76
77 3
        $expires = $this->getAttribute(static::ATTR_EXPIRES);
78 3
        if ($expires && strtotime($expires) < time()) {
79 2
            return true;
80
        }
81
82 2
        return false;
83
    }
84
85
    /**
86
     * Returns true if the current cookie matches the supplied domain.
87
     *
88
     * @param string $domain A domain hostname
89
     */
90 7
    public function matchesDomain(string $domain): bool
91
    {
92 7
        $cookieDomain = $this->getAttribute(static::ATTR_DOMAIN) ?? '';
93
94 7
        if (0 === strpos($cookieDomain, '.')) {
95 3
            $pattern = '/\b'.preg_quote(substr($cookieDomain, 1), '/').'$/i';
96
97 3
            return (bool) preg_match($pattern, $domain);
98
        } else {
99 4
            return 0 == strcasecmp($cookieDomain, $domain);
100
        }
101
    }
102
103
    /**
104
     * Returns true if the current cookie matches the supplied path.
105
     *
106
     * @param string $path A path
107
     */
108 6
    public function matchesPath(string $path): bool
109
    {
110 6
        $needle = $this->getAttribute(static::ATTR_PATH);
111
112 6
        return null === $needle || 0 === strpos($path, $needle);
113
    }
114
115
    /**
116
     * Populates the current cookie with data from the supplied Set-Cookie header.
117
     *
118
     * @param string $header        A Set-Cookie header
119
     * @param string $issuingDomain The domain that issued the header
120
     */
121 3
    public function fromSetCookieHeader(string $header, string $issuingDomain): void
122
    {
123 3
        list($this->name, $header) = explode('=', $header, 2);
124 3
        if (false === strpos($header, ';')) {
125 2
            $this->value = $header;
126 2
            $header = null;
127
        } else {
128 1
            list($this->value, $header) = explode(';', $header, 2);
129
        }
130
131 3
        $this->clearAttributes();
132 3
        if (null !== $header) {
133 1
            foreach (array_map('trim', explode(';', trim($header))) as $pair) {
134 1
                if (false === strpos($pair, '=')) {
135 1
                    $name = $pair;
136 1
                    $value = null;
137
                } else {
138 1
                    list($name, $value) = explode('=', $pair);
139
                }
140
141 1
                $this->setAttribute($name, $value);
142
            }
143
        }
144
145 3
        if (!$this->getAttribute(static::ATTR_DOMAIN)) {
146 2
            $this->setAttribute(static::ATTR_DOMAIN, $issuingDomain);
147
        }
148 3
    }
149
150
    /**
151
     * Formats a Cookie header for the current cookie.
152
     *
153
     * @return string An HTTP request Cookie header
154
     */
155 3
    public function toCookieHeader(): string
156
    {
157 3
        return $this->getName().'='.$this->getValue();
158
    }
159
160 5
    public function setName(string $name): void
161
    {
162 5
        $this->name = $name;
163 5
    }
164
165 7
    public function getName(): string
166
    {
167 7
        return $this->name;
168
    }
169
170 5
    public function setValue(string $value): void
171
    {
172 5
        $this->value = $value;
173 5
    }
174
175 4
    public function getValue(): string
176
    {
177 4
        return $this->value;
178
    }
179
180 3
    public function setAttributes(array $attributes): void
181
    {
182
        // attributes are case insensitive
183 3
        $this->attributes = array_change_key_case($attributes);
184 3
    }
185
186 15
    public function setAttribute(string $name, ?string $value): void
187
    {
188 15
        $this->attributes[strtolower($name)] = $value;
189 15
    }
190
191 1
    public function getAttributes(): array
192
    {
193 1
        return $this->attributes;
194
    }
195
196 15
    public function getAttribute(string $name): ?string
197
    {
198 15
        $name = strtolower($name);
199
200 15
        if (isset($this->attributes[$name])) {
201 14
            return $this->attributes[$name];
202
        }
203
204 11
        return null;
205
    }
206
207 5
    public function hasAttribute(string $name): bool
208
    {
209 5
        return \array_key_exists($name, $this->attributes);
210
    }
211
212 3
    public function clearAttributes(): void
213
    {
214 3
        $this->setAttributes([]);
215 3
    }
216
217 1
    public function setCreatedAt(int $createdAt): void
218
    {
219 1
        $this->createdAt = $createdAt;
220 1
    }
221
222 2
    public function getCreatedAt(): int
223
    {
224 2
        return $this->createdAt;
225
    }
226
}
227