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