|
1
|
|
|
<?php |
|
2
|
|
|
namespace Rmccue\Requests; |
|
3
|
|
|
|
|
4
|
|
|
Use Rmccue\Requests as Requests; |
|
5
|
|
|
Use Rmccue\Requests\IRI as IRI; |
|
6
|
|
|
Use Rmccue\Requests\Response\Headers as Headers; |
|
7
|
|
|
/** |
|
8
|
|
|
* Cookie storage object |
|
9
|
|
|
* |
|
10
|
|
|
* @package Rmccue\Requests |
|
11
|
|
|
* @subpackage Cookies |
|
12
|
|
|
*/ |
|
13
|
|
|
|
|
14
|
|
|
/** |
|
15
|
|
|
* Cookie storage object |
|
16
|
|
|
* |
|
17
|
|
|
* @package Rmccue\Requests |
|
18
|
|
|
* @subpackage Cookies |
|
19
|
|
|
*/ |
|
20
|
|
|
class Cookie { |
|
21
|
|
|
/** |
|
22
|
|
|
* Cookie name. |
|
23
|
|
|
* |
|
24
|
|
|
* @var string |
|
25
|
|
|
*/ |
|
26
|
|
|
public $name; |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* Cookie value. |
|
30
|
|
|
* |
|
31
|
|
|
* @var string |
|
32
|
|
|
*/ |
|
33
|
|
|
public $value; |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* Cookie attributes |
|
37
|
|
|
* |
|
38
|
|
|
* Valid keys are (currently) path, domain, expires, max-age, secure and |
|
39
|
|
|
* httponly. |
|
40
|
|
|
* |
|
41
|
|
|
* @var Rmccue\Requests\Utility\CaseInsensitiveDictionary|array Array-like object |
|
42
|
|
|
*/ |
|
43
|
|
|
public $attributes = array(); |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* Cookie flags |
|
47
|
|
|
* |
|
48
|
|
|
* Valid keys are (currently) creation, last-access, persistent and |
|
49
|
|
|
* host-only. |
|
50
|
|
|
* |
|
51
|
|
|
* @var array |
|
52
|
|
|
*/ |
|
53
|
|
|
public $flags = array(); |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* Reference time for relative calculations |
|
57
|
|
|
* |
|
58
|
|
|
* This is used in place of `time()` when calculating Max-Age expiration and |
|
59
|
|
|
* checking time validity. |
|
60
|
|
|
* |
|
61
|
|
|
* @var int |
|
62
|
|
|
*/ |
|
63
|
|
|
public $reference_time = 0; |
|
64
|
|
|
|
|
65
|
|
|
/** |
|
66
|
|
|
* Create a new cookie object |
|
67
|
|
|
* |
|
68
|
|
|
* @param string $name |
|
69
|
|
|
* @param string $value |
|
70
|
|
|
* @param array|\Rmccue\Requests\Utility\CaseInsensitiveDictionary $attributes Associative array of attribute data |
|
71
|
|
|
*/ |
|
72
|
|
|
public function __construct($name, $value, $attributes = array(), $flags = array(), $reference_time = null) { |
|
73
|
|
|
$this->name = $name; |
|
74
|
|
|
$this->value = $value; |
|
75
|
|
|
$this->attributes = $attributes; |
|
|
|
|
|
|
76
|
|
|
$default_flags = array( |
|
77
|
|
|
'creation' => time(), |
|
78
|
|
|
'last-access' => time(), |
|
79
|
|
|
'persistent' => false, |
|
80
|
|
|
'host-only' => true, |
|
81
|
|
|
); |
|
82
|
|
|
$this->flags = array_merge($default_flags, $flags); |
|
83
|
|
|
|
|
84
|
|
|
$this->reference_time = time(); |
|
85
|
|
|
if ($reference_time !== null) { |
|
86
|
|
|
$this->reference_time = $reference_time; |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
$this->normalize(); |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
/** |
|
93
|
|
|
* Check if a cookie is expired. |
|
94
|
|
|
* |
|
95
|
|
|
* Checks the age against $this->reference_time to determine if the cookie |
|
96
|
|
|
* is expired. |
|
97
|
|
|
* |
|
98
|
|
|
* @return boolean True if expired, false if time is valid. |
|
99
|
|
|
*/ |
|
100
|
|
|
public function is_expired() { |
|
101
|
|
|
// RFC6265, s. 4.1.2.2: |
|
|
|
|
|
|
102
|
|
|
// If a cookie has both the Max-Age and the Expires attribute, the Max- |
|
103
|
|
|
// Age attribute has precedence and controls the expiration date of the |
|
104
|
|
|
// cookie. |
|
105
|
|
|
if (isset($this->attributes['max-age'])) { |
|
106
|
|
|
$max_age = $this->attributes['max-age']; |
|
107
|
|
|
return $max_age < $this->reference_time; |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
if (isset($this->attributes['expires'])) { |
|
111
|
|
|
$expires = $this->attributes['expires']; |
|
112
|
|
|
return $expires < $this->reference_time; |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
return false; |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
/** |
|
119
|
|
|
* Check if a cookie is valid for a given URI |
|
120
|
|
|
* |
|
121
|
|
|
* @param \Rmccue\Requests\IRI $uri URI to check |
|
122
|
|
|
* @return boolean Whether the cookie is valid for the given URI |
|
123
|
|
|
*/ |
|
124
|
|
|
public function uri_matches(IRI $uri) { |
|
125
|
|
|
if (!$this->domain_matches($uri->host)) { |
|
126
|
|
|
return false; |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
if (!$this->path_matches($uri->path)) { |
|
130
|
|
|
return false; |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
|
|
return empty($this->attributes['secure']) || $uri->scheme === 'https'; |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
|
|
/** |
|
137
|
|
|
* Check if a cookie is valid for a given domain |
|
138
|
|
|
* |
|
139
|
|
|
* @param string $string Domain to check |
|
140
|
|
|
* @return boolean Whether the cookie is valid for the given domain |
|
141
|
|
|
*/ |
|
142
|
|
|
public function domain_matches($string) { |
|
143
|
|
|
if (!isset($this->attributes['domain'])) { |
|
144
|
|
|
// Cookies created manually; cookies created by Requests will set |
|
145
|
|
|
// the domain to the requested domain |
|
146
|
|
|
return true; |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
$domain_string = $this->attributes['domain']; |
|
150
|
|
|
if ($domain_string === $string) { |
|
151
|
|
|
// The domain string and the string are identical. |
|
152
|
|
|
return true; |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
// If the cookie is marked as host-only and we don't have an exact |
|
156
|
|
|
// match, reject the cookie |
|
157
|
|
|
if ($this->flags['host-only'] === true) { |
|
158
|
|
|
return false; |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
if (strlen($string) <= strlen($domain_string)) { |
|
162
|
|
|
// For obvious reasons, the string cannot be a suffix if the domain |
|
163
|
|
|
// is shorter than the domain string |
|
164
|
|
|
return false; |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
if (substr($string, -1 * strlen($domain_string)) !== $domain_string) { |
|
168
|
|
|
// The domain string should be a suffix of the string. |
|
169
|
|
|
return false; |
|
170
|
|
|
} |
|
171
|
|
|
|
|
172
|
|
|
$prefix = substr($string, 0, strlen($string) - strlen($domain_string)); |
|
173
|
|
|
if (substr($prefix, -1) !== '.') { |
|
174
|
|
|
// The last character of the string that is not included in the |
|
175
|
|
|
// domain string should be a %x2E (".") character. |
|
176
|
|
|
return false; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
// The string should be a host name (i.e., not an IP address). |
|
180
|
|
|
return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $string); |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* Check if a cookie is valid for a given path |
|
185
|
|
|
* |
|
186
|
|
|
* From the path-match check in RFC 6265 section 5.1.4 |
|
187
|
|
|
* |
|
188
|
|
|
* @param string $request_path Path to check |
|
189
|
|
|
* @return boolean Whether the cookie is valid for the given path |
|
190
|
|
|
*/ |
|
191
|
|
|
public function path_matches($request_path) { |
|
192
|
|
|
if (empty($request_path)) { |
|
193
|
|
|
// Normalize empty path to root |
|
194
|
|
|
$request_path = '/'; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
if (!isset($this->attributes['path'])) { |
|
198
|
|
|
// Cookies created manually; cookies created by Requests will set |
|
199
|
|
|
// the path to the requested path |
|
200
|
|
|
return true; |
|
201
|
|
|
} |
|
202
|
|
|
|
|
203
|
|
|
$cookie_path = $this->attributes['path']; |
|
204
|
|
|
|
|
205
|
|
|
if ($cookie_path === $request_path) { |
|
206
|
|
|
// The cookie-path and the request-path are identical. |
|
207
|
|
|
return true; |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
if (strlen($request_path) > strlen($cookie_path) && substr($request_path, 0, strlen($cookie_path)) === $cookie_path) { |
|
211
|
|
|
if (substr($cookie_path, -1) === '/') { |
|
212
|
|
|
// The cookie-path is a prefix of the request-path, and the last |
|
213
|
|
|
// character of the cookie-path is %x2F ("/"). |
|
214
|
|
|
return true; |
|
215
|
|
|
} |
|
216
|
|
|
|
|
217
|
|
|
if (substr($request_path, strlen($cookie_path), 1) === '/') { |
|
218
|
|
|
// The cookie-path is a prefix of the request-path, and the |
|
219
|
|
|
// first character of the request-path that is not included in |
|
220
|
|
|
// the cookie-path is a %x2F ("/") character. |
|
221
|
|
|
return true; |
|
222
|
|
|
} |
|
223
|
|
|
} |
|
224
|
|
|
|
|
225
|
|
|
return false; |
|
226
|
|
|
} |
|
227
|
|
|
|
|
228
|
|
|
/** |
|
229
|
|
|
* Normalize cookie and attributes |
|
230
|
|
|
* |
|
231
|
|
|
* @return boolean Whether the cookie was successfully normalized |
|
232
|
|
|
*/ |
|
233
|
|
|
public function normalize() { |
|
234
|
|
|
foreach ($this->attributes as $key => $value) { |
|
235
|
|
|
$orig_value = $value; |
|
236
|
|
|
$value = $this->normalize_attribute($key, $value); |
|
237
|
|
|
if ($value === null) { |
|
238
|
|
|
unset($this->attributes[$key]); |
|
239
|
|
|
continue; |
|
240
|
|
|
} |
|
241
|
|
|
|
|
242
|
|
|
if ($value !== $orig_value) { |
|
243
|
|
|
$this->attributes[$key] = $value; |
|
244
|
|
|
} |
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
|
|
return true; |
|
248
|
|
|
} |
|
249
|
|
|
|
|
250
|
|
|
/** |
|
251
|
|
|
* Parse an individual cookie attribute |
|
252
|
|
|
* |
|
253
|
|
|
* Handles parsing individual attributes from the cookie values. |
|
254
|
|
|
* |
|
255
|
|
|
* @param string $name Attribute name |
|
256
|
|
|
* @param string|boolean $value Attribute value (string value, or true if empty/flag) |
|
257
|
|
|
* @return mixed Value if available, or null if the attribute value is invalid (and should be skipped) |
|
258
|
|
|
*/ |
|
259
|
|
|
protected function normalize_attribute($name, $value) { |
|
260
|
|
|
switch (strtolower($name)) { |
|
261
|
|
|
case 'expires': |
|
262
|
|
|
// Expiration parsing, as per RFC 6265 section 5.2.1 |
|
263
|
|
|
if (is_int($value)) { |
|
264
|
|
|
return $value; |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
|
|
$expiry_time = strtotime($value); |
|
268
|
|
|
if ($expiry_time === false) { |
|
269
|
|
|
return null; |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
|
return $expiry_time; |
|
273
|
|
|
|
|
274
|
|
|
case 'max-age': |
|
275
|
|
|
// Expiration parsing, as per RFC 6265 section 5.2.2 |
|
276
|
|
|
if (is_int($value)) { |
|
277
|
|
|
return $value; |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
|
|
// Check that we have a valid age |
|
281
|
|
|
if (!preg_match('/^-?\d+$/', $value)) { |
|
282
|
|
|
return null; |
|
283
|
|
|
} |
|
284
|
|
|
|
|
285
|
|
|
$delta_seconds = (int) $value; |
|
286
|
|
|
if ($delta_seconds <= 0) { |
|
287
|
|
|
$expiry_time = 0; |
|
288
|
|
|
} |
|
289
|
|
|
else { |
|
290
|
|
|
$expiry_time = $this->reference_time + $delta_seconds; |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
return $expiry_time; |
|
294
|
|
|
|
|
295
|
|
|
case 'domain': |
|
296
|
|
|
// Domain normalization, as per RFC 6265 section 5.2.3 |
|
297
|
|
|
if ($value[0] === '.') { |
|
298
|
|
|
$value = substr($value, 1); |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
return $value; |
|
302
|
|
|
|
|
303
|
|
|
default: |
|
304
|
|
|
return $value; |
|
305
|
|
|
} |
|
306
|
|
|
} |
|
307
|
|
|
|
|
308
|
|
|
/** |
|
309
|
|
|
* Format a cookie for a Cookie header |
|
310
|
|
|
* |
|
311
|
|
|
* This is used when sending cookies to a server. |
|
312
|
|
|
* |
|
313
|
|
|
* @return string Cookie formatted for Cookie header |
|
314
|
|
|
*/ |
|
315
|
|
|
public function format_for_header() { |
|
316
|
|
|
return sprintf('%s=%s', $this->name, $this->value); |
|
317
|
|
|
} |
|
318
|
|
|
|
|
319
|
|
|
/** |
|
320
|
|
|
* Format a cookie for a Cookie header |
|
321
|
|
|
* |
|
322
|
|
|
* @codeCoverageIgnore |
|
323
|
|
|
* @deprecated Use {@see Rmccue\Requests\Cookie::format_for_header} |
|
324
|
|
|
* @return string |
|
325
|
|
|
*/ |
|
326
|
|
|
public function formatForHeader() { |
|
327
|
|
|
return $this->format_for_header(); |
|
328
|
|
|
} |
|
329
|
|
|
|
|
330
|
|
|
/** |
|
331
|
|
|
* Format a cookie for a Set-Cookie header |
|
332
|
|
|
* |
|
333
|
|
|
* This is used when sending cookies to clients. This isn't really |
|
334
|
|
|
* applicable to client-side usage, but might be handy for debugging. |
|
335
|
|
|
* |
|
336
|
|
|
* @return string Cookie formatted for Set-Cookie header |
|
337
|
|
|
*/ |
|
338
|
|
|
public function format_for_set_cookie() { |
|
339
|
|
|
$header_value = $this->format_for_header(); |
|
340
|
|
|
if (!empty($this->attributes)) { |
|
341
|
|
|
$parts = array(); |
|
342
|
|
|
foreach ($this->attributes as $key => $value) { |
|
343
|
|
|
// Ignore non-associative attributes |
|
344
|
|
|
if (is_numeric($key)) { |
|
345
|
|
|
$parts[] = $value; |
|
346
|
|
|
} |
|
347
|
|
|
else { |
|
348
|
|
|
$parts[] = sprintf('%s=%s', $key, $value); |
|
349
|
|
|
} |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
$header_value .= '; ' . implode('; ', $parts); |
|
353
|
|
|
} |
|
354
|
|
|
return $header_value; |
|
355
|
|
|
} |
|
356
|
|
|
|
|
357
|
|
|
/** |
|
358
|
|
|
* Format a cookie for a Set-Cookie header |
|
359
|
|
|
* |
|
360
|
|
|
* @codeCoverageIgnore |
|
361
|
|
|
* @deprecated Use {@see Rmccue\Requests\Cookie::format_for_set_cookie} |
|
362
|
|
|
* @return string |
|
363
|
|
|
*/ |
|
364
|
|
|
public function formatForSetCookie() { |
|
365
|
|
|
return $this->format_for_set_cookie(); |
|
366
|
|
|
} |
|
367
|
|
|
|
|
368
|
|
|
/** |
|
369
|
|
|
* Get the cookie value |
|
370
|
|
|
* |
|
371
|
|
|
* Attributes and other data can be accessed via methods. |
|
372
|
|
|
*/ |
|
373
|
|
|
public function __toString() { |
|
374
|
|
|
return $this->value; |
|
375
|
|
|
} |
|
376
|
|
|
|
|
377
|
|
|
/** |
|
378
|
|
|
* Parse a cookie string into a cookie object |
|
379
|
|
|
* |
|
380
|
|
|
* Based on Mozilla's parsing code in Firefox and related projects, which |
|
381
|
|
|
* is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265 |
|
382
|
|
|
* specifies some of this handling, but not in a thorough manner. |
|
383
|
|
|
* |
|
384
|
|
|
* @param string Cookie header value (from a Set-Cookie header) |
|
385
|
|
|
* @return Rmccue\Requests\Cookie Parsed cookie object |
|
386
|
|
|
*/ |
|
387
|
|
|
public static function parse($string, $name = '', $reference_time = null) { |
|
388
|
|
|
$parts = explode(';', $string); |
|
389
|
|
|
$kvparts = array_shift($parts); |
|
390
|
|
|
|
|
391
|
|
|
if (!empty($name)) { |
|
392
|
|
|
$value = $string; |
|
393
|
|
|
} |
|
394
|
|
|
elseif (strpos($kvparts, '=') === false) { |
|
395
|
|
|
// Some sites might only have a value without the equals separator. |
|
396
|
|
|
// Deviate from RFC 6265 and pretend it was actually a blank name |
|
397
|
|
|
// (`=foo`) |
|
|
|
|
|
|
398
|
|
|
// |
|
399
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=169091 |
|
400
|
|
|
$name = ''; |
|
401
|
|
|
$value = $kvparts; |
|
402
|
|
|
} |
|
403
|
|
|
else { |
|
404
|
|
|
list($name, $value) = explode('=', $kvparts, 2); |
|
405
|
|
|
} |
|
406
|
|
|
$name = trim($name); |
|
407
|
|
|
$value = trim($value); |
|
408
|
|
|
|
|
409
|
|
|
// Attribute key are handled case-insensitively |
|
410
|
|
|
$attributes = new \Rmccue\Requests\Utility\CaseInsensitiveDictionary(); |
|
411
|
|
|
|
|
412
|
|
|
if (!empty($parts)) { |
|
413
|
|
|
foreach ($parts as $part) { |
|
414
|
|
|
if (strpos($part, '=') === false) { |
|
415
|
|
|
$part_key = $part; |
|
416
|
|
|
$part_value = true; |
|
417
|
|
|
} |
|
418
|
|
|
else { |
|
419
|
|
|
list($part_key, $part_value) = explode('=', $part, 2); |
|
420
|
|
|
$part_value = trim($part_value); |
|
421
|
|
|
} |
|
422
|
|
|
|
|
423
|
|
|
$part_key = trim($part_key); |
|
424
|
|
|
$attributes[$part_key] = $part_value; |
|
425
|
|
|
} |
|
426
|
|
|
} |
|
427
|
|
|
|
|
428
|
|
|
return new \Rmccue\Requests\Cookie($name, $value, $attributes, array(), $reference_time); |
|
429
|
|
|
} |
|
430
|
|
|
|
|
431
|
|
|
/** |
|
432
|
|
|
* Parse all Set-Cookie headers from request headers |
|
433
|
|
|
* |
|
434
|
|
|
* @param Rmccue\Requests\Response\Headers $headers Headers to parse from |
|
|
|
|
|
|
435
|
|
|
* @param Rmccue\Requests\IRI|null $origin URI for comparing cookie origins |
|
|
|
|
|
|
436
|
|
|
* @param int|null $time Reference time for expiration calculation |
|
437
|
|
|
* @return array |
|
438
|
|
|
*/ |
|
439
|
|
|
public static function parse_from_headers(Headers $headers, IRI $origin = null, $time = null) { |
|
440
|
|
|
$cookie_headers = $headers->getValues('Set-Cookie'); |
|
441
|
|
|
if (empty($cookie_headers)) { |
|
442
|
|
|
return array(); |
|
443
|
|
|
} |
|
444
|
|
|
|
|
445
|
|
|
$cookies = array(); |
|
446
|
|
|
foreach ($cookie_headers as $header) { |
|
447
|
|
|
$parsed = self::parse($header, '', $time); |
|
448
|
|
|
|
|
449
|
|
|
// Default domain/path attributes |
|
450
|
|
|
if (empty($parsed->attributes['domain']) && !empty($origin)) { |
|
451
|
|
|
$parsed->attributes['domain'] = $origin->host; |
|
452
|
|
|
$parsed->flags['host-only'] = true; |
|
453
|
|
|
} |
|
454
|
|
|
else { |
|
455
|
|
|
$parsed->flags['host-only'] = false; |
|
456
|
|
|
} |
|
457
|
|
|
|
|
458
|
|
|
$path_is_valid = (!empty($parsed->attributes['path']) && $parsed->attributes['path'][0] === '/'); |
|
459
|
|
|
if (!$path_is_valid && !empty($origin)) { |
|
460
|
|
|
$path = $origin->path; |
|
461
|
|
|
|
|
462
|
|
|
// Default path normalization as per RFC 6265 section 5.1.4 |
|
463
|
|
|
if (substr($path, 0, 1) !== '/') { |
|
464
|
|
|
// If the uri-path is empty or if the first character of |
|
465
|
|
|
// the uri-path is not a %x2F ("/") character, output |
|
466
|
|
|
// %x2F ("/") and skip the remaining steps. |
|
467
|
|
|
$path = '/'; |
|
468
|
|
|
} |
|
469
|
|
|
elseif (substr_count($path, '/') === 1) { |
|
470
|
|
|
// If the uri-path contains no more than one %x2F ("/") |
|
471
|
|
|
// character, output %x2F ("/") and skip the remaining |
|
472
|
|
|
// step. |
|
473
|
|
|
$path = '/'; |
|
474
|
|
|
} |
|
475
|
|
|
else { |
|
476
|
|
|
// Output the characters of the uri-path from the first |
|
477
|
|
|
// character up to, but not including, the right-most |
|
478
|
|
|
// %x2F ("/"). |
|
|
|
|
|
|
479
|
|
|
$path = substr($path, 0, strrpos($path, '/')); |
|
480
|
|
|
} |
|
481
|
|
|
$parsed->attributes['path'] = $path; |
|
482
|
|
|
} |
|
483
|
|
|
|
|
484
|
|
|
// Reject invalid cookie domains |
|
485
|
|
|
if (!empty($origin) && !$parsed->domain_matches($origin->host)) { |
|
486
|
|
|
continue; |
|
487
|
|
|
} |
|
488
|
|
|
|
|
489
|
|
|
$cookies[$parsed->name] = $parsed; |
|
490
|
|
|
} |
|
491
|
|
|
|
|
492
|
|
|
return $cookies; |
|
493
|
|
|
} |
|
494
|
|
|
|
|
495
|
|
|
/** |
|
496
|
|
|
* Parse all Set-Cookie headers from request headers |
|
497
|
|
|
* |
|
498
|
|
|
* @codeCoverageIgnore |
|
499
|
|
|
* @deprecated Use {@see Rmccue\Requests\Cookie::parse_from_headers} |
|
500
|
|
|
* @return string |
|
501
|
|
|
*/ |
|
502
|
|
|
public static function parseFromHeaders(Rmccue\Requests\Response\Headers $headers) { |
|
503
|
|
|
return self::parse_from_headers($headers); |
|
504
|
|
|
} |
|
505
|
|
|
} |
|
506
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountIdthat can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theidproperty of an instance of theAccountclass. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.