Browse code

added appinfo/info.xml appinfo/signature.json CHANGELOG.txt lib/AppInfo/Application.php css/style.css providers/Plivo

DoubleBastionAdmin authored on 05/11/2025 13:35:09
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,307 @@
1
+<?php
2
+
3
+namespace GuzzleHttp\Cookie;
4
+
5
+use Psr\Http\Message\RequestInterface;
6
+use Psr\Http\Message\ResponseInterface;
7
+
8
+/**
9
+ * Cookie jar that stores cookies as an array
10
+ */
11
+class CookieJar implements CookieJarInterface
12
+{
13
+    /**
14
+     * @var SetCookie[] Loaded cookie data
15
+     */
16
+    private $cookies = [];
17
+
18
+    /**
19
+     * @var bool
20
+     */
21
+    private $strictMode;
22
+
23
+    /**
24
+     * @param bool  $strictMode  Set to true to throw exceptions when invalid
25
+     *                           cookies are added to the cookie jar.
26
+     * @param array $cookieArray Array of SetCookie objects or a hash of
27
+     *                           arrays that can be used with the SetCookie
28
+     *                           constructor
29
+     */
30
+    public function __construct(bool $strictMode = false, array $cookieArray = [])
31
+    {
32
+        $this->strictMode = $strictMode;
33
+
34
+        foreach ($cookieArray as $cookie) {
35
+            if (!($cookie instanceof SetCookie)) {
36
+                $cookie = new SetCookie($cookie);
37
+            }
38
+            $this->setCookie($cookie);
39
+        }
40
+    }
41
+
42
+    /**
43
+     * Create a new Cookie jar from an associative array and domain.
44
+     *
45
+     * @param array  $cookies Cookies to create the jar from
46
+     * @param string $domain  Domain to set the cookies to
47
+     */
48
+    public static function fromArray(array $cookies, string $domain): self
49
+    {
50
+        $cookieJar = new self();
51
+        foreach ($cookies as $name => $value) {
52
+            $cookieJar->setCookie(new SetCookie([
53
+                'Domain' => $domain,
54
+                'Name' => $name,
55
+                'Value' => $value,
56
+                'Discard' => true,
57
+            ]));
58
+        }
59
+
60
+        return $cookieJar;
61
+    }
62
+
63
+    /**
64
+     * Evaluate if this cookie should be persisted to storage
65
+     * that survives between requests.
66
+     *
67
+     * @param SetCookie $cookie              Being evaluated.
68
+     * @param bool      $allowSessionCookies If we should persist session cookies
69
+     */
70
+    public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool
71
+    {
72
+        if ($cookie->getExpires() || $allowSessionCookies) {
73
+            if (!$cookie->getDiscard()) {
74
+                return true;
75
+            }
76
+        }
77
+
78
+        return false;
79
+    }
80
+
81
+    /**
82
+     * Finds and returns the cookie based on the name
83
+     *
84
+     * @param string $name cookie name to search for
85
+     *
86
+     * @return SetCookie|null cookie that was found or null if not found
87
+     */
88
+    public function getCookieByName(string $name): ?SetCookie
89
+    {
90
+        foreach ($this->cookies as $cookie) {
91
+            if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
92
+                return $cookie;
93
+            }
94
+        }
95
+
96
+        return null;
97
+    }
98
+
99
+    public function toArray(): array
100
+    {
101
+        return \array_map(static function (SetCookie $cookie): array {
102
+            return $cookie->toArray();
103
+        }, $this->getIterator()->getArrayCopy());
104
+    }
105
+
106
+    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
107
+    {
108
+        if (!$domain) {
109
+            $this->cookies = [];
110
+
111
+            return;
112
+        } elseif (!$path) {
113
+            $this->cookies = \array_filter(
114
+                $this->cookies,
115
+                static function (SetCookie $cookie) use ($domain): bool {
116
+                    return !$cookie->matchesDomain($domain);
117
+                }
118
+            );
119
+        } elseif (!$name) {
120
+            $this->cookies = \array_filter(
121
+                $this->cookies,
122
+                static function (SetCookie $cookie) use ($path, $domain): bool {
123
+                    return !($cookie->matchesPath($path)
124
+                        && $cookie->matchesDomain($domain));
125
+                }
126
+            );
127
+        } else {
128
+            $this->cookies = \array_filter(
129
+                $this->cookies,
130
+                static function (SetCookie $cookie) use ($path, $domain, $name) {
131
+                    return !($cookie->getName() == $name
132
+                        && $cookie->matchesPath($path)
133
+                        && $cookie->matchesDomain($domain));
134
+                }
135
+            );
136
+        }
137
+    }
138
+
139
+    public function clearSessionCookies(): void
140
+    {
141
+        $this->cookies = \array_filter(
142
+            $this->cookies,
143
+            static function (SetCookie $cookie): bool {
144
+                return !$cookie->getDiscard() && $cookie->getExpires();
145
+            }
146
+        );
147
+    }
148
+
149
+    public function setCookie(SetCookie $cookie): bool
150
+    {
151
+        // If the name string is empty (but not 0), ignore the set-cookie
152
+        // string entirely.
153
+        $name = $cookie->getName();
154
+        if (!$name && $name !== '0') {
155
+            return false;
156
+        }
157
+
158
+        // Only allow cookies with set and valid domain, name, value
159
+        $result = $cookie->validate();
160
+        if ($result !== true) {
161
+            if ($this->strictMode) {
162
+                throw new \RuntimeException('Invalid cookie: '.$result);
163
+            }
164
+            $this->removeCookieIfEmpty($cookie);
165
+
166
+            return false;
167
+        }
168
+
169
+        // Resolve conflicts with previously set cookies
170
+        foreach ($this->cookies as $i => $c) {
171
+            // Two cookies are identical, when their path, and domain are
172
+            // identical.
173
+            if ($c->getPath() != $cookie->getPath()
174
+                || $c->getDomain() != $cookie->getDomain()
175
+                || $c->getName() != $cookie->getName()
176
+            ) {
177
+                continue;
178
+            }
179
+
180
+            // The previously set cookie is a discard cookie and this one is
181
+            // not so allow the new cookie to be set
182
+            if (!$cookie->getDiscard() && $c->getDiscard()) {
183
+                unset($this->cookies[$i]);
184
+                continue;
185
+            }
186
+
187
+            // If the new cookie's expiration is further into the future, then
188
+            // replace the old cookie
189
+            if ($cookie->getExpires() > $c->getExpires()) {
190
+                unset($this->cookies[$i]);
191
+                continue;
192
+            }
193
+
194
+            // If the value has changed, we better change it
195
+            if ($cookie->getValue() !== $c->getValue()) {
196
+                unset($this->cookies[$i]);
197
+                continue;
198
+            }
199
+
200
+            // The cookie exists, so no need to continue
201
+            return false;
202
+        }
203
+
204
+        $this->cookies[] = $cookie;
205
+
206
+        return true;
207
+    }
208
+
209
+    public function count(): int
210
+    {
211
+        return \count($this->cookies);
212
+    }
213
+
214
+    /**
215
+     * @return \ArrayIterator<int, SetCookie>
216
+     */
217
+    public function getIterator(): \ArrayIterator
218
+    {
219
+        return new \ArrayIterator(\array_values($this->cookies));
220
+    }
221
+
222
+    public function extractCookies(RequestInterface $request, ResponseInterface $response): void
223
+    {
224
+        if ($cookieHeader = $response->getHeader('Set-Cookie')) {
225
+            foreach ($cookieHeader as $cookie) {
226
+                $sc = SetCookie::fromString($cookie);
227
+                if (!$sc->getDomain()) {
228
+                    $sc->setDomain($request->getUri()->getHost());
229
+                }
230
+                if (0 !== \strpos($sc->getPath(), '/')) {
231
+                    $sc->setPath($this->getCookiePathFromRequest($request));
232
+                }
233
+                if (!$sc->matchesDomain($request->getUri()->getHost())) {
234
+                    continue;
235
+                }
236
+                // Note: At this point `$sc->getDomain()` being a public suffix should
237
+                // be rejected, but we don't want to pull in the full PSL dependency.
238
+                $this->setCookie($sc);
239
+            }
240
+        }
241
+    }
242
+
243
+    /**
244
+     * Computes cookie path following RFC 6265 section 5.1.4
245
+     *
246
+     * @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4
247
+     */
248
+    private function getCookiePathFromRequest(RequestInterface $request): string
249
+    {
250
+        $uriPath = $request->getUri()->getPath();
251
+        if ('' === $uriPath) {
252
+            return '/';
253
+        }
254
+        if (0 !== \strpos($uriPath, '/')) {
255
+            return '/';
256
+        }
257
+        if ('/' === $uriPath) {
258
+            return '/';
259
+        }
260
+        $lastSlashPos = \strrpos($uriPath, '/');
261
+        if (0 === $lastSlashPos || false === $lastSlashPos) {
262
+            return '/';
263
+        }
264
+
265
+        return \substr($uriPath, 0, $lastSlashPos);
266
+    }
267
+
268
+    public function withCookieHeader(RequestInterface $request): RequestInterface
269
+    {
270
+        $values = [];
271
+        $uri = $request->getUri();
272
+        $scheme = $uri->getScheme();
273
+        $host = $uri->getHost();
274
+        $path = $uri->getPath() ?: '/';
275
+
276
+        foreach ($this->cookies as $cookie) {
277
+            if ($cookie->matchesPath($path)
278
+                && $cookie->matchesDomain($host)
279
+                && !$cookie->isExpired()
280
+                && (!$cookie->getSecure() || $scheme === 'https')
281
+            ) {
282
+                $values[] = $cookie->getName().'='
283
+                    .$cookie->getValue();
284
+            }
285
+        }
286
+
287
+        return $values
288
+            ? $request->withHeader('Cookie', \implode('; ', $values))
289
+            : $request;
290
+    }
291
+
292
+    /**
293
+     * If a cookie already exists and the server asks to set it again with a
294
+     * null value, the cookie must be deleted.
295
+     */
296
+    private function removeCookieIfEmpty(SetCookie $cookie): void
297
+    {
298
+        $cookieValue = $cookie->getValue();
299
+        if ($cookieValue === null || $cookieValue === '') {
300
+            $this->clear(
301
+                $cookie->getDomain(),
302
+                $cookie->getPath(),
303
+                $cookie->getName()
304
+            );
305
+        }
306
+    }
307
+}
Browse code

removed appinfo/info.xml appinfo/signature.json CHANGELOG.txt lib/AppInfo/Application.php css/style.css providers/Plivo

DoubleBastionAdmin authored on 05/11/2025 13:12:22
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,313 +0,0 @@
1
-<?php
2
-
3
-namespace GuzzleHttp\Cookie;
4
-
5
-use Psr\Http\Message\RequestInterface;
6
-use Psr\Http\Message\ResponseInterface;
7
-
8
-/**
9
- * Cookie jar that stores cookies as an array
10
- */
11
-class CookieJar implements CookieJarInterface
12
-{
13
-    /**
14
-     * @var SetCookie[] Loaded cookie data
15
-     */
16
-    private $cookies = [];
17
-
18
-    /**
19
-     * @var bool
20
-     */
21
-    private $strictMode;
22
-
23
-    /**
24
-     * @param bool  $strictMode  Set to true to throw exceptions when invalid
25
-     *                           cookies are added to the cookie jar.
26
-     * @param array $cookieArray Array of SetCookie objects or a hash of
27
-     *                           arrays that can be used with the SetCookie
28
-     *                           constructor
29
-     */
30
-    public function __construct(bool $strictMode = false, array $cookieArray = [])
31
-    {
32
-        $this->strictMode = $strictMode;
33
-
34
-        foreach ($cookieArray as $cookie) {
35
-            if (!($cookie instanceof SetCookie)) {
36
-                $cookie = new SetCookie($cookie);
37
-            }
38
-            $this->setCookie($cookie);
39
-        }
40
-    }
41
-
42
-    /**
43
-     * Create a new Cookie jar from an associative array and domain.
44
-     *
45
-     * @param array  $cookies Cookies to create the jar from
46
-     * @param string $domain  Domain to set the cookies to
47
-     */
48
-    public static function fromArray(array $cookies, string $domain): self
49
-    {
50
-        $cookieJar = new self();
51
-        foreach ($cookies as $name => $value) {
52
-            $cookieJar->setCookie(new SetCookie([
53
-                'Domain'  => $domain,
54
-                'Name'    => $name,
55
-                'Value'   => $value,
56
-                'Discard' => true
57
-            ]));
58
-        }
59
-
60
-        return $cookieJar;
61
-    }
62
-
63
-    /**
64
-     * Evaluate if this cookie should be persisted to storage
65
-     * that survives between requests.
66
-     *
67
-     * @param SetCookie $cookie              Being evaluated.
68
-     * @param bool      $allowSessionCookies If we should persist session cookies
69
-     */
70
-    public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool
71
-    {
72
-        if ($cookie->getExpires() || $allowSessionCookies) {
73
-            if (!$cookie->getDiscard()) {
74
-                return true;
75
-            }
76
-        }
77
-
78
-        return false;
79
-    }
80
-
81
-    /**
82
-     * Finds and returns the cookie based on the name
83
-     *
84
-     * @param string $name cookie name to search for
85
-     *
86
-     * @return SetCookie|null cookie that was found or null if not found
87
-     */
88
-    public function getCookieByName(string $name): ?SetCookie
89
-    {
90
-        foreach ($this->cookies as $cookie) {
91
-            if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
92
-                return $cookie;
93
-            }
94
-        }
95
-
96
-        return null;
97
-    }
98
-
99
-    /**
100
-     * @inheritDoc
101
-     */
102
-    public function toArray(): array
103
-    {
104
-        return \array_map(static function (SetCookie $cookie): array {
105
-            return $cookie->toArray();
106
-        }, $this->getIterator()->getArrayCopy());
107
-    }
108
-
109
-    /**
110
-     * @inheritDoc
111
-     */
112
-    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
113
-    {
114
-        if (!$domain) {
115
-            $this->cookies = [];
116
-            return;
117
-        } elseif (!$path) {
118
-            $this->cookies = \array_filter(
119
-                $this->cookies,
120
-                static function (SetCookie $cookie) use ($domain): bool {
121
-                    return !$cookie->matchesDomain($domain);
122
-                }
123
-            );
124
-        } elseif (!$name) {
125
-            $this->cookies = \array_filter(
126
-                $this->cookies,
127
-                static function (SetCookie $cookie) use ($path, $domain): bool {
128
-                    return !($cookie->matchesPath($path) &&
129
-                        $cookie->matchesDomain($domain));
130
-                }
131
-            );
132
-        } else {
133
-            $this->cookies = \array_filter(
134
-                $this->cookies,
135
-                static function (SetCookie $cookie) use ($path, $domain, $name) {
136
-                    return !($cookie->getName() == $name &&
137
-                        $cookie->matchesPath($path) &&
138
-                        $cookie->matchesDomain($domain));
139
-                }
140
-            );
141
-        }
142
-    }
143
-
144
-    /**
145
-     * @inheritDoc
146
-     */
147
-    public function clearSessionCookies(): void
148
-    {
149
-        $this->cookies = \array_filter(
150
-            $this->cookies,
151
-            static function (SetCookie $cookie): bool {
152
-                return !$cookie->getDiscard() && $cookie->getExpires();
153
-            }
154
-        );
155
-    }
156
-
157
-    /**
158
-     * @inheritDoc
159
-     */
160
-    public function setCookie(SetCookie $cookie): bool
161
-    {
162
-        // If the name string is empty (but not 0), ignore the set-cookie
163
-        // string entirely.
164
-        $name = $cookie->getName();
165
-        if (!$name && $name !== '0') {
166
-            return false;
167
-        }
168
-
169
-        // Only allow cookies with set and valid domain, name, value
170
-        $result = $cookie->validate();
171
-        if ($result !== true) {
172
-            if ($this->strictMode) {
173
-                throw new \RuntimeException('Invalid cookie: ' . $result);
174
-            }
175
-            $this->removeCookieIfEmpty($cookie);
176
-            return false;
177
-        }
178
-
179
-        // Resolve conflicts with previously set cookies
180
-        foreach ($this->cookies as $i => $c) {
181
-
182
-            // Two cookies are identical, when their path, and domain are
183
-            // identical.
184
-            if ($c->getPath() != $cookie->getPath() ||
185
-                $c->getDomain() != $cookie->getDomain() ||
186
-                $c->getName() != $cookie->getName()
187
-            ) {
188
-                continue;
189
-            }
190
-
191
-            // The previously set cookie is a discard cookie and this one is
192
-            // not so allow the new cookie to be set
193
-            if (!$cookie->getDiscard() && $c->getDiscard()) {
194
-                unset($this->cookies[$i]);
195
-                continue;
196
-            }
197
-
198
-            // If the new cookie's expiration is further into the future, then
199
-            // replace the old cookie
200
-            if ($cookie->getExpires() > $c->getExpires()) {
201
-                unset($this->cookies[$i]);
202
-                continue;
203
-            }
204
-
205
-            // If the value has changed, we better change it
206
-            if ($cookie->getValue() !== $c->getValue()) {
207
-                unset($this->cookies[$i]);
208
-                continue;
209
-            }
210
-
211
-            // The cookie exists, so no need to continue
212
-            return false;
213
-        }
214
-
215
-        $this->cookies[] = $cookie;
216
-
217
-        return true;
218
-    }
219
-
220
-    public function count(): int
221
-    {
222
-        return \count($this->cookies);
223
-    }
224
-
225
-    /**
226
-     * @return \ArrayIterator<int, SetCookie>
227
-     */
228
-    public function getIterator(): \ArrayIterator
229
-    {
230
-        return new \ArrayIterator(\array_values($this->cookies));
231
-    }
232
-
233
-    public function extractCookies(RequestInterface $request, ResponseInterface $response): void
234
-    {
235
-        if ($cookieHeader = $response->getHeader('Set-Cookie')) {
236
-            foreach ($cookieHeader as $cookie) {
237
-                $sc = SetCookie::fromString($cookie);
238
-                if (!$sc->getDomain()) {
239
-                    $sc->setDomain($request->getUri()->getHost());
240
-                }
241
-                if (0 !== \strpos($sc->getPath(), '/')) {
242
-                    $sc->setPath($this->getCookiePathFromRequest($request));
243
-                }
244
-                $this->setCookie($sc);
245
-            }
246
-        }
247
-    }
248
-
249
-    /**
250
-     * Computes cookie path following RFC 6265 section 5.1.4
251
-     *
252
-     * @link https://tools.ietf.org/html/rfc6265#section-5.1.4
253
-     */
254
-    private function getCookiePathFromRequest(RequestInterface $request): string
255
-    {
256
-        $uriPath = $request->getUri()->getPath();
257
-        if ('' === $uriPath) {
258
-            return '/';
259
-        }
260
-        if (0 !== \strpos($uriPath, '/')) {
261
-            return '/';
262
-        }
263
-        if ('/' === $uriPath) {
264
-            return '/';
265
-        }
266
-        $lastSlashPos = \strrpos($uriPath, '/');
267
-        if (0 === $lastSlashPos || false === $lastSlashPos) {
268
-            return '/';
269
-        }
270
-
271
-        return \substr($uriPath, 0, $lastSlashPos);
272
-    }
273
-
274
-    public function withCookieHeader(RequestInterface $request): RequestInterface
275
-    {
276
-        $values = [];
277
-        $uri = $request->getUri();
278
-        $scheme = $uri->getScheme();
279
-        $host = $uri->getHost();
280
-        $path = $uri->getPath() ?: '/';
281
-
282
-        foreach ($this->cookies as $cookie) {
283
-            if ($cookie->matchesPath($path) &&
284
-                $cookie->matchesDomain($host) &&
285
-                !$cookie->isExpired() &&
286
-                (!$cookie->getSecure() || $scheme === 'https')
287
-            ) {
288
-                $values[] = $cookie->getName() . '='
289
-                    . $cookie->getValue();
290
-            }
291
-        }
292
-
293
-        return $values
294
-            ? $request->withHeader('Cookie', \implode('; ', $values))
295
-            : $request;
296
-    }
297
-
298
-    /**
299
-     * If a cookie already exists and the server asks to set it again with a
300
-     * null value, the cookie must be deleted.
301
-     */
302
-    private function removeCookieIfEmpty(SetCookie $cookie): void
303
-    {
304
-        $cookieValue = $cookie->getValue();
305
-        if ($cookieValue === null || $cookieValue === '') {
306
-            $this->clear(
307
-                $cookie->getDomain(),
308
-                $cookie->getPath(),
309
-                $cookie->getName()
310
-            );
311
-        }
312
-    }
313
-}
Browse code

Added README.md appinfo/info.xml appinfo/signature.json lib/Controller/AuthorApiController.php and the providers directory

DoubleBastionAdmin authored on 20/08/2022 16:33:00
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,313 @@
1
+<?php
2
+
3
+namespace GuzzleHttp\Cookie;
4
+
5
+use Psr\Http\Message\RequestInterface;
6
+use Psr\Http\Message\ResponseInterface;
7
+
8
+/**
9
+ * Cookie jar that stores cookies as an array
10
+ */
11
+class CookieJar implements CookieJarInterface
12
+{
13
+    /**
14
+     * @var SetCookie[] Loaded cookie data
15
+     */
16
+    private $cookies = [];
17
+
18
+    /**
19
+     * @var bool
20
+     */
21
+    private $strictMode;
22
+
23
+    /**
24
+     * @param bool  $strictMode  Set to true to throw exceptions when invalid
25
+     *                           cookies are added to the cookie jar.
26
+     * @param array $cookieArray Array of SetCookie objects or a hash of
27
+     *                           arrays that can be used with the SetCookie
28
+     *                           constructor
29
+     */
30
+    public function __construct(bool $strictMode = false, array $cookieArray = [])
31
+    {
32
+        $this->strictMode = $strictMode;
33
+
34
+        foreach ($cookieArray as $cookie) {
35
+            if (!($cookie instanceof SetCookie)) {
36
+                $cookie = new SetCookie($cookie);
37
+            }
38
+            $this->setCookie($cookie);
39
+        }
40
+    }
41
+
42
+    /**
43
+     * Create a new Cookie jar from an associative array and domain.
44
+     *
45
+     * @param array  $cookies Cookies to create the jar from
46
+     * @param string $domain  Domain to set the cookies to
47
+     */
48
+    public static function fromArray(array $cookies, string $domain): self
49
+    {
50
+        $cookieJar = new self();
51
+        foreach ($cookies as $name => $value) {
52
+            $cookieJar->setCookie(new SetCookie([
53
+                'Domain'  => $domain,
54
+                'Name'    => $name,
55
+                'Value'   => $value,
56
+                'Discard' => true
57
+            ]));
58
+        }
59
+
60
+        return $cookieJar;
61
+    }
62
+
63
+    /**
64
+     * Evaluate if this cookie should be persisted to storage
65
+     * that survives between requests.
66
+     *
67
+     * @param SetCookie $cookie              Being evaluated.
68
+     * @param bool      $allowSessionCookies If we should persist session cookies
69
+     */
70
+    public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool
71
+    {
72
+        if ($cookie->getExpires() || $allowSessionCookies) {
73
+            if (!$cookie->getDiscard()) {
74
+                return true;
75
+            }
76
+        }
77
+
78
+        return false;
79
+    }
80
+
81
+    /**
82
+     * Finds and returns the cookie based on the name
83
+     *
84
+     * @param string $name cookie name to search for
85
+     *
86
+     * @return SetCookie|null cookie that was found or null if not found
87
+     */
88
+    public function getCookieByName(string $name): ?SetCookie
89
+    {
90
+        foreach ($this->cookies as $cookie) {
91
+            if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
92
+                return $cookie;
93
+            }
94
+        }
95
+
96
+        return null;
97
+    }
98
+
99
+    /**
100
+     * @inheritDoc
101
+     */
102
+    public function toArray(): array
103
+    {
104
+        return \array_map(static function (SetCookie $cookie): array {
105
+            return $cookie->toArray();
106
+        }, $this->getIterator()->getArrayCopy());
107
+    }
108
+
109
+    /**
110
+     * @inheritDoc
111
+     */
112
+    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
113
+    {
114
+        if (!$domain) {
115
+            $this->cookies = [];
116
+            return;
117
+        } elseif (!$path) {
118
+            $this->cookies = \array_filter(
119
+                $this->cookies,
120
+                static function (SetCookie $cookie) use ($domain): bool {
121
+                    return !$cookie->matchesDomain($domain);
122
+                }
123
+            );
124
+        } elseif (!$name) {
125
+            $this->cookies = \array_filter(
126
+                $this->cookies,
127
+                static function (SetCookie $cookie) use ($path, $domain): bool {
128
+                    return !($cookie->matchesPath($path) &&
129
+                        $cookie->matchesDomain($domain));
130
+                }
131
+            );
132
+        } else {
133
+            $this->cookies = \array_filter(
134
+                $this->cookies,
135
+                static function (SetCookie $cookie) use ($path, $domain, $name) {
136
+                    return !($cookie->getName() == $name &&
137
+                        $cookie->matchesPath($path) &&
138
+                        $cookie->matchesDomain($domain));
139
+                }
140
+            );
141
+        }
142
+    }
143
+
144
+    /**
145
+     * @inheritDoc
146
+     */
147
+    public function clearSessionCookies(): void
148
+    {
149
+        $this->cookies = \array_filter(
150
+            $this->cookies,
151
+            static function (SetCookie $cookie): bool {
152
+                return !$cookie->getDiscard() && $cookie->getExpires();
153
+            }
154
+        );
155
+    }
156
+
157
+    /**
158
+     * @inheritDoc
159
+     */
160
+    public function setCookie(SetCookie $cookie): bool
161
+    {
162
+        // If the name string is empty (but not 0), ignore the set-cookie
163
+        // string entirely.
164
+        $name = $cookie->getName();
165
+        if (!$name && $name !== '0') {
166
+            return false;
167
+        }
168
+
169
+        // Only allow cookies with set and valid domain, name, value
170
+        $result = $cookie->validate();
171
+        if ($result !== true) {
172
+            if ($this->strictMode) {
173
+                throw new \RuntimeException('Invalid cookie: ' . $result);
174
+            }
175
+            $this->removeCookieIfEmpty($cookie);
176
+            return false;
177
+        }
178
+
179
+        // Resolve conflicts with previously set cookies
180
+        foreach ($this->cookies as $i => $c) {
181
+
182
+            // Two cookies are identical, when their path, and domain are
183
+            // identical.
184
+            if ($c->getPath() != $cookie->getPath() ||
185
+                $c->getDomain() != $cookie->getDomain() ||
186
+                $c->getName() != $cookie->getName()
187
+            ) {
188
+                continue;
189
+            }
190
+
191
+            // The previously set cookie is a discard cookie and this one is
192
+            // not so allow the new cookie to be set
193
+            if (!$cookie->getDiscard() && $c->getDiscard()) {
194
+                unset($this->cookies[$i]);
195
+                continue;
196
+            }
197
+
198
+            // If the new cookie's expiration is further into the future, then
199
+            // replace the old cookie
200
+            if ($cookie->getExpires() > $c->getExpires()) {
201
+                unset($this->cookies[$i]);
202
+                continue;
203
+            }
204
+
205
+            // If the value has changed, we better change it
206
+            if ($cookie->getValue() !== $c->getValue()) {
207
+                unset($this->cookies[$i]);
208
+                continue;
209
+            }
210
+
211
+            // The cookie exists, so no need to continue
212
+            return false;
213
+        }
214
+
215
+        $this->cookies[] = $cookie;
216
+
217
+        return true;
218
+    }
219
+
220
+    public function count(): int
221
+    {
222
+        return \count($this->cookies);
223
+    }
224
+
225
+    /**
226
+     * @return \ArrayIterator<int, SetCookie>
227
+     */
228
+    public function getIterator(): \ArrayIterator
229
+    {
230
+        return new \ArrayIterator(\array_values($this->cookies));
231
+    }
232
+
233
+    public function extractCookies(RequestInterface $request, ResponseInterface $response): void
234
+    {
235
+        if ($cookieHeader = $response->getHeader('Set-Cookie')) {
236
+            foreach ($cookieHeader as $cookie) {
237
+                $sc = SetCookie::fromString($cookie);
238
+                if (!$sc->getDomain()) {
239
+                    $sc->setDomain($request->getUri()->getHost());
240
+                }
241
+                if (0 !== \strpos($sc->getPath(), '/')) {
242
+                    $sc->setPath($this->getCookiePathFromRequest($request));
243
+                }
244
+                $this->setCookie($sc);
245
+            }
246
+        }
247
+    }
248
+
249
+    /**
250
+     * Computes cookie path following RFC 6265 section 5.1.4
251
+     *
252
+     * @link https://tools.ietf.org/html/rfc6265#section-5.1.4
253
+     */
254
+    private function getCookiePathFromRequest(RequestInterface $request): string
255
+    {
256
+        $uriPath = $request->getUri()->getPath();
257
+        if ('' === $uriPath) {
258
+            return '/';
259
+        }
260
+        if (0 !== \strpos($uriPath, '/')) {
261
+            return '/';
262
+        }
263
+        if ('/' === $uriPath) {
264
+            return '/';
265
+        }
266
+        $lastSlashPos = \strrpos($uriPath, '/');
267
+        if (0 === $lastSlashPos || false === $lastSlashPos) {
268
+            return '/';
269
+        }
270
+
271
+        return \substr($uriPath, 0, $lastSlashPos);
272
+    }
273
+
274
+    public function withCookieHeader(RequestInterface $request): RequestInterface
275
+    {
276
+        $values = [];
277
+        $uri = $request->getUri();
278
+        $scheme = $uri->getScheme();
279
+        $host = $uri->getHost();
280
+        $path = $uri->getPath() ?: '/';
281
+
282
+        foreach ($this->cookies as $cookie) {
283
+            if ($cookie->matchesPath($path) &&
284
+                $cookie->matchesDomain($host) &&
285
+                !$cookie->isExpired() &&
286
+                (!$cookie->getSecure() || $scheme === 'https')
287
+            ) {
288
+                $values[] = $cookie->getName() . '='
289
+                    . $cookie->getValue();
290
+            }
291
+        }
292
+
293
+        return $values
294
+            ? $request->withHeader('Cookie', \implode('; ', $values))
295
+            : $request;
296
+    }
297
+
298
+    /**
299
+     * If a cookie already exists and the server asks to set it again with a
300
+     * null value, the cookie must be deleted.
301
+     */
302
+    private function removeCookieIfEmpty(SetCookie $cookie): void
303
+    {
304
+        $cookieValue = $cookie->getValue();
305
+        if ($cookieValue === null || $cookieValue === '') {
306
+            $this->clear(
307
+                $cookie->getDomain(),
308
+                $cookie->getPath(),
309
+                $cookie->getName()
310
+            );
311
+        }
312
+    }
313
+}