Version 1
[yaffs-website] / vendor / guzzlehttp / guzzle / src / Cookie / SetCookie.php
1 <?php
2 namespace GuzzleHttp\Cookie;
3
4 /**
5  * Set-Cookie object
6  */
7 class SetCookie
8 {
9     /** @var array */
10     private static $defaults = [
11         'Name'     => null,
12         'Value'    => null,
13         'Domain'   => null,
14         'Path'     => '/',
15         'Max-Age'  => null,
16         'Expires'  => null,
17         'Secure'   => false,
18         'Discard'  => false,
19         'HttpOnly' => false
20     ];
21
22     /** @var array Cookie data */
23     private $data;
24
25     /**
26      * Create a new SetCookie object from a string
27      *
28      * @param string $cookie Set-Cookie header string
29      *
30      * @return self
31      */
32     public static function fromString($cookie)
33     {
34         // Create the default return array
35         $data = self::$defaults;
36         // Explode the cookie string using a series of semicolons
37         $pieces = array_filter(array_map('trim', explode(';', $cookie)));
38         // The name of the cookie (first kvp) must include an equal sign.
39         if (empty($pieces) || !strpos($pieces[0], '=')) {
40             return new self($data);
41         }
42
43         // Add the cookie pieces into the parsed data array
44         foreach ($pieces as $part) {
45
46             $cookieParts = explode('=', $part, 2);
47             $key = trim($cookieParts[0]);
48             $value = isset($cookieParts[1])
49                 ? trim($cookieParts[1], " \n\r\t\0\x0B")
50                 : true;
51
52             // Only check for non-cookies when cookies have been found
53             if (empty($data['Name'])) {
54                 $data['Name'] = $key;
55                 $data['Value'] = $value;
56             } else {
57                 foreach (array_keys(self::$defaults) as $search) {
58                     if (!strcasecmp($search, $key)) {
59                         $data[$search] = $value;
60                         continue 2;
61                     }
62                 }
63                 $data[$key] = $value;
64             }
65         }
66
67         return new self($data);
68     }
69
70     /**
71      * @param array $data Array of cookie data provided by a Cookie parser
72      */
73     public function __construct(array $data = [])
74     {
75         $this->data = array_replace(self::$defaults, $data);
76         // Extract the Expires value and turn it into a UNIX timestamp if needed
77         if (!$this->getExpires() && $this->getMaxAge()) {
78             // Calculate the Expires date
79             $this->setExpires(time() + $this->getMaxAge());
80         } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
81             $this->setExpires($this->getExpires());
82         }
83     }
84
85     public function __toString()
86     {
87         $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
88         foreach ($this->data as $k => $v) {
89             if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
90                 if ($k === 'Expires') {
91                     $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
92                 } else {
93                     $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
94                 }
95             }
96         }
97
98         return rtrim($str, '; ');
99     }
100
101     public function toArray()
102     {
103         return $this->data;
104     }
105
106     /**
107      * Get the cookie name
108      *
109      * @return string
110      */
111     public function getName()
112     {
113         return $this->data['Name'];
114     }
115
116     /**
117      * Set the cookie name
118      *
119      * @param string $name Cookie name
120      */
121     public function setName($name)
122     {
123         $this->data['Name'] = $name;
124     }
125
126     /**
127      * Get the cookie value
128      *
129      * @return string
130      */
131     public function getValue()
132     {
133         return $this->data['Value'];
134     }
135
136     /**
137      * Set the cookie value
138      *
139      * @param string $value Cookie value
140      */
141     public function setValue($value)
142     {
143         $this->data['Value'] = $value;
144     }
145
146     /**
147      * Get the domain
148      *
149      * @return string|null
150      */
151     public function getDomain()
152     {
153         return $this->data['Domain'];
154     }
155
156     /**
157      * Set the domain of the cookie
158      *
159      * @param string $domain
160      */
161     public function setDomain($domain)
162     {
163         $this->data['Domain'] = $domain;
164     }
165
166     /**
167      * Get the path
168      *
169      * @return string
170      */
171     public function getPath()
172     {
173         return $this->data['Path'];
174     }
175
176     /**
177      * Set the path of the cookie
178      *
179      * @param string $path Path of the cookie
180      */
181     public function setPath($path)
182     {
183         $this->data['Path'] = $path;
184     }
185
186     /**
187      * Maximum lifetime of the cookie in seconds
188      *
189      * @return int|null
190      */
191     public function getMaxAge()
192     {
193         return $this->data['Max-Age'];
194     }
195
196     /**
197      * Set the max-age of the cookie
198      *
199      * @param int $maxAge Max age of the cookie in seconds
200      */
201     public function setMaxAge($maxAge)
202     {
203         $this->data['Max-Age'] = $maxAge;
204     }
205
206     /**
207      * The UNIX timestamp when the cookie Expires
208      *
209      * @return mixed
210      */
211     public function getExpires()
212     {
213         return $this->data['Expires'];
214     }
215
216     /**
217      * Set the unix timestamp for which the cookie will expire
218      *
219      * @param int $timestamp Unix timestamp
220      */
221     public function setExpires($timestamp)
222     {
223         $this->data['Expires'] = is_numeric($timestamp)
224             ? (int) $timestamp
225             : strtotime($timestamp);
226     }
227
228     /**
229      * Get whether or not this is a secure cookie
230      *
231      * @return null|bool
232      */
233     public function getSecure()
234     {
235         return $this->data['Secure'];
236     }
237
238     /**
239      * Set whether or not the cookie is secure
240      *
241      * @param bool $secure Set to true or false if secure
242      */
243     public function setSecure($secure)
244     {
245         $this->data['Secure'] = $secure;
246     }
247
248     /**
249      * Get whether or not this is a session cookie
250      *
251      * @return null|bool
252      */
253     public function getDiscard()
254     {
255         return $this->data['Discard'];
256     }
257
258     /**
259      * Set whether or not this is a session cookie
260      *
261      * @param bool $discard Set to true or false if this is a session cookie
262      */
263     public function setDiscard($discard)
264     {
265         $this->data['Discard'] = $discard;
266     }
267
268     /**
269      * Get whether or not this is an HTTP only cookie
270      *
271      * @return bool
272      */
273     public function getHttpOnly()
274     {
275         return $this->data['HttpOnly'];
276     }
277
278     /**
279      * Set whether or not this is an HTTP only cookie
280      *
281      * @param bool $httpOnly Set to true or false if this is HTTP only
282      */
283     public function setHttpOnly($httpOnly)
284     {
285         $this->data['HttpOnly'] = $httpOnly;
286     }
287
288     /**
289      * Check if the cookie matches a path value.
290      *
291      * A request-path path-matches a given cookie-path if at least one of
292      * the following conditions holds:
293      *
294      * - The cookie-path and the request-path are identical.
295      * - The cookie-path is a prefix of the request-path, and the last
296      *   character of the cookie-path is %x2F ("/").
297      * - The cookie-path is a prefix of the request-path, and the first
298      *   character of the request-path that is not included in the cookie-
299      *   path is a %x2F ("/") character.
300      *
301      * @param string $requestPath Path to check against
302      *
303      * @return bool
304      */
305     public function matchesPath($requestPath)
306     {
307         $cookiePath = $this->getPath();
308
309         // Match on exact matches or when path is the default empty "/"
310         if ($cookiePath === '/' || $cookiePath == $requestPath) {
311             return true;
312         }
313
314         // Ensure that the cookie-path is a prefix of the request path.
315         if (0 !== strpos($requestPath, $cookiePath)) {
316             return false;
317         }
318
319         // Match if the last character of the cookie-path is "/"
320         if (substr($cookiePath, -1, 1) === '/') {
321             return true;
322         }
323
324         // Match if the first character not included in cookie path is "/"
325         return substr($requestPath, strlen($cookiePath), 1) === '/';
326     }
327
328     /**
329      * Check if the cookie matches a domain value
330      *
331      * @param string $domain Domain to check against
332      *
333      * @return bool
334      */
335     public function matchesDomain($domain)
336     {
337         // Remove the leading '.' as per spec in RFC 6265.
338         // http://tools.ietf.org/html/rfc6265#section-5.2.3
339         $cookieDomain = ltrim($this->getDomain(), '.');
340
341         // Domain not set or exact match.
342         if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
343             return true;
344         }
345
346         // Matching the subdomain according to RFC 6265.
347         // http://tools.ietf.org/html/rfc6265#section-5.1.3
348         if (filter_var($domain, FILTER_VALIDATE_IP)) {
349             return false;
350         }
351
352         return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/', $domain);
353     }
354
355     /**
356      * Check if the cookie is expired
357      *
358      * @return bool
359      */
360     public function isExpired()
361     {
362         return $this->getExpires() && time() > $this->getExpires();
363     }
364
365     /**
366      * Check if the cookie is valid according to RFC 6265
367      *
368      * @return bool|string Returns true if valid or an error message if invalid
369      */
370     public function validate()
371     {
372         // Names must not be empty, but can be 0
373         $name = $this->getName();
374         if (empty($name) && !is_numeric($name)) {
375             return 'The cookie name must not be empty';
376         }
377
378         // Check if any of the invalid characters are present in the cookie name
379         if (preg_match(
380             '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
381             $name)
382         ) {
383             return 'Cookie name must not contain invalid characters: ASCII '
384                 . 'Control characters (0-31;127), space, tab and the '
385                 . 'following characters: ()<>@,;:\"/?={}';
386         }
387
388         // Value must not be empty, but can be 0
389         $value = $this->getValue();
390         if (empty($value) && !is_numeric($value)) {
391             return 'The cookie value must not be empty';
392         }
393
394         // Domains must not be empty, but can be 0
395         // A "0" is not a valid internet domain, but may be used as server name
396         // in a private network.
397         $domain = $this->getDomain();
398         if (empty($domain) && !is_numeric($domain)) {
399             return 'The cookie domain must not be empty';
400         }
401
402         return true;
403     }
404 }