Passed
Push — master ( dde655...76187f )
by Enjoys
01:26
created

Cookie::has()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 1
c 1
b 0
f 1
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Enjoys\Cookie;
6
7
use Enjoys\Http\ServerRequest;
8
use Enjoys\Http\ServerRequestInterface;
9
10
class Cookie
11
{
12
13
    /**
14
     * @var array<mixed>
15
     */
16
    private array $options = [
17
        'expires' => 0,
18
        'path' => '',
19
        'domain' => false,
20
        'secure' => false,
21
        'httponly' => false,
22
        'samesite' => 'Lax',
23
24
    ];
25
26
    /**
27
     * @var ServerRequestInterface
28
     */
29
    private ServerRequestInterface $serverRequest;
30
31
    public function __construct(ServerRequestInterface $serverRequest = null)
32
    {
33
        $this->serverRequest = $serverRequest ?? new ServerRequest();
34
        $this->setDomain();
35
    }
36
37
    public static function get(string $key): ?string
38
    {
39
        return (self::has($key)) ? $_COOKIE[$key] : null;
40
    }
41
42
43
    public static function has(string $key): bool
44
    {
45
        return array_key_exists($key, $_COOKIE);
46
    }
47
48
49
    /**
50
     * @param string $name
51
     * @throws Exception
52
     */
53
    public function delete(string $name): void
54
    {
55
        $this->set($name, '', '-1 day');
56
    }
57
58
59
    /**
60
     * @param string $key
61
     * @param string|null $value
62
     * @param bool|int|string $ttl
63
     * @param array<mixed> $options
64
     * @throws Exception
65
     */
66
    public function set(string $key, ?string $value, $ttl = true, array $options = []): void
67
    {
68
        if (headers_sent($filename, $linenum)) {
69
            throw new Exception(
70
                sprintf(
71
                    "Куки не установлены\nЗаголовки уже были отправлены в %s в строке %s\n",
72
                    $filename,
73
                    $linenum
74
                )
75
            );
76
        }
77
78
        //Если $value равно NULL, то удаляем эту куку
79
        if ($value === null) {
80
            $ttl = '-1 day';
81
        }
82
83
        $this->setExpires($ttl);
84
85
        setcookie($key, (string)$value, $this->mergeOptions($options));
86
    }
87
88
    /**
89
     * @param array<mixed> $options
90
     * @return array<mixed>
91
     */
92
    private function mergeOptions(array $options): array
93
    {
94
        $mergedOptions = $this->options;
95
        foreach ($options as $key => $option) {
96
            if (isset($this->options[$key])) {
97
                $mergedOptions[$key] = $option;
98
            }
99
        }
100
101
        return $mergedOptions;
102
    }
103
104
    /**
105
     * @param mixed $ttl
106
     * @return void
107
     * @throws Exception
108
     * @see http://php.net/manual/ru/datetime.formats.relative.php
109
     */
110
    private function setExpires($ttl): void
111
    {
112
        //Срок действия cookie истечет с окончанием сессии (при закрытии браузера).
113
        if ($ttl === false || strtolower((string)$ttl) === 'session') {
114
            $this->options['expires'] = 0;
115
            return;
116
        }
117
118
119
        // Если число то прибавляем значение к метке времени timestamp
120
        // Для установки сессионной куки надо использовать FALSE
121
        if (is_numeric($ttl)) {
122
            $this->options['expires'] = time() + (int)$ttl;
123
            return;
124
        }
125
126
127
        // Устанавливаем время жизни на год
128
        if ($ttl === true) {
129
            $ttl = '+1 year';
130
        }
131
132
        if (is_string($ttl)) {
133
            if (false !== $returnTtl = strtotime($ttl)) {
134
                $this->options['expires'] = $returnTtl;
135
                return;
136
            }
137
            throw new Exception(sprintf('strtotime() failed to convert string "%s" to timestamp', $ttl));
138
        }
139
//        $this->options['expires'] = (int)$ttl;
140
    }
141
142
143
    /**
144
     * @param false|string $domain
145
     */
146
    public function setDomain($domain = false): void
147
    {
148
        if ($domain === false) {
149
            if ($this->serverRequest->server('SERVER_NAME') != 'localhost') {
150
                $domain = (preg_replace(
151
                    '#^www\.#',
152
                    '',
153
                    strtolower((string)$this->serverRequest->server('SERVER_NAME'))
154
                ));
155
            }
156
        }
157
158
        $this->options['domain'] = $domain ?? false;
159
        $this->options['secure'] = ($this->serverRequest->server('HTTPS') == 'on');
160
    }
161
162
163
    public function setPath(string $path): void
164
    {
165
        $this->options['path'] = $path;
166
    }
167
168
    /**
169
     * @param bool $httpOnly
170
     */
171
    public function setHttponly(bool $httpOnly): void
172
    {
173
        $this->options['httponly'] = $httpOnly;
174
    }
175
176
    /**
177
     * @param bool $secure
178
     */
179
    public function setSecure(bool $secure): void
180
    {
181
        $this->options['secure'] = $secure;
182
    }
183
184
    /**
185
     * @param string $sameSite
186
     */
187
    public function setSameSite(string $sameSite): void
188
    {
189
        $this->options['samesite'] = $sameSite;
190
    }
191
}
192