1 | <?php
|
---|
2 | /**
|
---|
3 | * Stores cookies and passes them between HTTP requests
|
---|
4 | *
|
---|
5 | * PHP version 5
|
---|
6 | *
|
---|
7 | * LICENSE:
|
---|
8 | *
|
---|
9 | * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>
|
---|
10 | * All rights reserved.
|
---|
11 | *
|
---|
12 | * Redistribution and use in source and binary forms, with or without
|
---|
13 | * modification, are permitted provided that the following conditions
|
---|
14 | * are met:
|
---|
15 | *
|
---|
16 | * * Redistributions of source code must retain the above copyright
|
---|
17 | * notice, this list of conditions and the following disclaimer.
|
---|
18 | * * Redistributions in binary form must reproduce the above copyright
|
---|
19 | * notice, this list of conditions and the following disclaimer in the
|
---|
20 | * documentation and/or other materials provided with the distribution.
|
---|
21 | * * The names of the authors may not be used to endorse or promote products
|
---|
22 | * derived from this software without specific prior written permission.
|
---|
23 | *
|
---|
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
---|
25 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
---|
26 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
---|
27 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
---|
28 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
---|
29 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
---|
30 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
---|
31 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
---|
32 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
---|
33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
---|
34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
35 | *
|
---|
36 | * @category HTTP
|
---|
37 | * @package HTTP_Request2
|
---|
38 | * @author Alexey Borzov <avb@php.net>
|
---|
39 | * @license http://opensource.org/licenses/bsd-license.php New BSD License
|
---|
40 | * @version SVN: $Id: CookieJar.php 324415 2012-03-21 10:50:50Z avb $
|
---|
41 | * @link http://pear.php.net/package/HTTP_Request2
|
---|
42 | */
|
---|
43 |
|
---|
44 | /** Class representing a HTTP request message */
|
---|
45 | require_once 'HTTP/Request2.php';
|
---|
46 |
|
---|
47 | /**
|
---|
48 | * Stores cookies and passes them between HTTP requests
|
---|
49 | *
|
---|
50 | * @category HTTP
|
---|
51 | * @package HTTP_Request2
|
---|
52 | * @author Alexey Borzov <avb@php.net>
|
---|
53 | * @license http://opensource.org/licenses/bsd-license.php New BSD License
|
---|
54 | * @version Release: 2.1.1
|
---|
55 | * @link http://pear.php.net/package/HTTP_Request2
|
---|
56 | */
|
---|
57 | class HTTP_Request2_CookieJar implements Serializable
|
---|
58 | {
|
---|
59 | /**
|
---|
60 | * Array of stored cookies
|
---|
61 | *
|
---|
62 | * The array is indexed by domain, path and cookie name
|
---|
63 | * .example.com
|
---|
64 | * /
|
---|
65 | * some_cookie => cookie data
|
---|
66 | * /subdir
|
---|
67 | * other_cookie => cookie data
|
---|
68 | * .example.org
|
---|
69 | * ...
|
---|
70 | *
|
---|
71 | * @var array
|
---|
72 | */
|
---|
73 | protected $cookies = array();
|
---|
74 |
|
---|
75 | /**
|
---|
76 | * Whether session cookies should be serialized when serializing the jar
|
---|
77 | * @var bool
|
---|
78 | */
|
---|
79 | protected $serializeSession = false;
|
---|
80 |
|
---|
81 | /**
|
---|
82 | * Whether Public Suffix List should be used for domain matching
|
---|
83 | * @var bool
|
---|
84 | */
|
---|
85 | protected $useList = true;
|
---|
86 |
|
---|
87 | /**
|
---|
88 | * Array with Public Suffix List data
|
---|
89 | * @var array
|
---|
90 | * @link http://publicsuffix.org/
|
---|
91 | */
|
---|
92 | protected static $psl = array();
|
---|
93 |
|
---|
94 | /**
|
---|
95 | * Class constructor, sets various options
|
---|
96 | *
|
---|
97 | * @param bool $serializeSessionCookies Controls serializing session cookies,
|
---|
98 | * see {@link serializeSessionCookies()}
|
---|
99 | * @param bool $usePublicSuffixList Controls using Public Suffix List,
|
---|
100 | * see {@link usePublicSuffixList()}
|
---|
101 | */
|
---|
102 | public function __construct(
|
---|
103 | $serializeSessionCookies = false, $usePublicSuffixList = true
|
---|
104 | ) {
|
---|
105 | $this->serializeSessionCookies($serializeSessionCookies);
|
---|
106 | $this->usePublicSuffixList($usePublicSuffixList);
|
---|
107 | }
|
---|
108 |
|
---|
109 | /**
|
---|
110 | * Returns current time formatted in ISO-8601 at UTC timezone
|
---|
111 | *
|
---|
112 | * @return string
|
---|
113 | */
|
---|
114 | protected function now()
|
---|
115 | {
|
---|
116 | $dt = new DateTime();
|
---|
117 | $dt->setTimezone(new DateTimeZone('UTC'));
|
---|
118 | return $dt->format(DateTime::ISO8601);
|
---|
119 | }
|
---|
120 |
|
---|
121 | /**
|
---|
122 | * Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields
|
---|
123 | *
|
---|
124 | * The checks are as follows:
|
---|
125 | * - cookie array should contain 'name' and 'value' fields;
|
---|
126 | * - name and value should not contain disallowed symbols;
|
---|
127 | * - 'expires' should be either empty parseable by DateTime;
|
---|
128 | * - 'domain' and 'path' should be either not empty or an URL where
|
---|
129 | * cookie was set should be provided.
|
---|
130 | * - if $setter is provided, then document at that URL should be allowed
|
---|
131 | * to set a cookie for that 'domain'. If $setter is not provided,
|
---|
132 | * then no domain checks will be made.
|
---|
133 | *
|
---|
134 | * 'expires' field will be converted to ISO8601 format from COOKIE format,
|
---|
135 | * 'domain' and 'path' will be set from setter URL if empty.
|
---|
136 | *
|
---|
137 | * @param array $cookie cookie data, as returned by
|
---|
138 | * {@link HTTP_Request2_Response::getCookies()}
|
---|
139 | * @param Net_URL2 $setter URL of the document that sent Set-Cookie header
|
---|
140 | *
|
---|
141 | * @return array Updated cookie array
|
---|
142 | * @throws HTTP_Request2_LogicException
|
---|
143 | * @throws HTTP_Request2_MessageException
|
---|
144 | */
|
---|
145 | protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null)
|
---|
146 | {
|
---|
147 | if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) {
|
---|
148 | throw new HTTP_Request2_LogicException(
|
---|
149 | "Cookie array should contain 'name' and 'value' fields",
|
---|
150 | HTTP_Request2_Exception::MISSING_VALUE
|
---|
151 | );
|
---|
152 | }
|
---|
153 | if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['name'])) {
|
---|
154 | throw new HTTP_Request2_LogicException(
|
---|
155 | "Invalid cookie name: '{$cookie['name']}'",
|
---|
156 | HTTP_Request2_Exception::INVALID_ARGUMENT
|
---|
157 | );
|
---|
158 | }
|
---|
159 | if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['value'])) {
|
---|
160 | throw new HTTP_Request2_LogicException(
|
---|
161 | "Invalid cookie value: '{$cookie['value']}'",
|
---|
162 | HTTP_Request2_Exception::INVALID_ARGUMENT
|
---|
163 | );
|
---|
164 | }
|
---|
165 | $cookie += array('domain' => '', 'path' => '', 'expires' => null, 'secure' => false);
|
---|
166 |
|
---|
167 | // Need ISO-8601 date @ UTC timezone
|
---|
168 | if (!empty($cookie['expires'])
|
---|
169 | && !preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+0000$/', $cookie['expires'])
|
---|
170 | ) {
|
---|
171 | try {
|
---|
172 | $dt = new DateTime($cookie['expires']);
|
---|
173 | $dt->setTimezone(new DateTimeZone('UTC'));
|
---|
174 | $cookie['expires'] = $dt->format(DateTime::ISO8601);
|
---|
175 | } catch (Exception $e) {
|
---|
176 | throw new HTTP_Request2_LogicException($e->getMessage());
|
---|
177 | }
|
---|
178 | }
|
---|
179 |
|
---|
180 | if (empty($cookie['domain']) || empty($cookie['path'])) {
|
---|
181 | if (!$setter) {
|
---|
182 | throw new HTTP_Request2_LogicException(
|
---|
183 | 'Cookie misses domain and/or path component, cookie setter URL needed',
|
---|
184 | HTTP_Request2_Exception::MISSING_VALUE
|
---|
185 | );
|
---|
186 | }
|
---|
187 | if (empty($cookie['domain'])) {
|
---|
188 | if ($host = $setter->getHost()) {
|
---|
189 | $cookie['domain'] = $host;
|
---|
190 | } else {
|
---|
191 | throw new HTTP_Request2_LogicException(
|
---|
192 | 'Setter URL does not contain host part, can\'t set cookie domain',
|
---|
193 | HTTP_Request2_Exception::MISSING_VALUE
|
---|
194 | );
|
---|
195 | }
|
---|
196 | }
|
---|
197 | if (empty($cookie['path'])) {
|
---|
198 | $path = $setter->getPath();
|
---|
199 | $cookie['path'] = empty($path)? '/': substr($path, 0, strrpos($path, '/') + 1);
|
---|
200 | }
|
---|
201 | }
|
---|
202 |
|
---|
203 | if ($setter && !$this->domainMatch($setter->getHost(), $cookie['domain'])) {
|
---|
204 | throw new HTTP_Request2_MessageException(
|
---|
205 | "Domain " . $setter->getHost() . " cannot set cookies for "
|
---|
206 | . $cookie['domain']
|
---|
207 | );
|
---|
208 | }
|
---|
209 |
|
---|
210 | return $cookie;
|
---|
211 | }
|
---|
212 |
|
---|
213 | /**
|
---|
214 | * Stores a cookie in the jar
|
---|
215 | *
|
---|
216 | * @param array $cookie cookie data, as returned by
|
---|
217 | * {@link HTTP_Request2_Response::getCookies()}
|
---|
218 | * @param Net_URL2 $setter URL of the document that sent Set-Cookie header
|
---|
219 | *
|
---|
220 | * @throws HTTP_Request2_Exception
|
---|
221 | */
|
---|
222 | public function store(array $cookie, Net_URL2 $setter = null)
|
---|
223 | {
|
---|
224 | $cookie = $this->checkAndUpdateFields($cookie, $setter);
|
---|
225 |
|
---|
226 | if (strlen($cookie['value'])
|
---|
227 | && (is_null($cookie['expires']) || $cookie['expires'] > $this->now())
|
---|
228 | ) {
|
---|
229 | if (!isset($this->cookies[$cookie['domain']])) {
|
---|
230 | $this->cookies[$cookie['domain']] = array();
|
---|
231 | }
|
---|
232 | if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {
|
---|
233 | $this->cookies[$cookie['domain']][$cookie['path']] = array();
|
---|
234 | }
|
---|
235 | $this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;
|
---|
236 |
|
---|
237 | } elseif (isset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']])) {
|
---|
238 | unset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']]);
|
---|
239 | }
|
---|
240 | }
|
---|
241 |
|
---|
242 | /**
|
---|
243 | * Adds cookies set in HTTP response to the jar
|
---|
244 | *
|
---|
245 | * @param HTTP_Request2_Response $response HTTP response message
|
---|
246 | * @param Net_URL2 $setter original request URL, needed for
|
---|
247 | * setting default domain/path
|
---|
248 | */
|
---|
249 | public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter)
|
---|
250 | {
|
---|
251 | foreach ($response->getCookies() as $cookie) {
|
---|
252 | $this->store($cookie, $setter);
|
---|
253 | }
|
---|
254 | }
|
---|
255 |
|
---|
256 | /**
|
---|
257 | * Returns all cookies matching a given request URL
|
---|
258 | *
|
---|
259 | * The following checks are made:
|
---|
260 | * - cookie domain should match request host
|
---|
261 | * - cookie path should be a prefix for request path
|
---|
262 | * - 'secure' cookies will only be sent for HTTPS requests
|
---|
263 | *
|
---|
264 | * @param Net_URL2 $url Request url
|
---|
265 | * @param bool $asString Whether to return cookies as string for "Cookie: " header
|
---|
266 | *
|
---|
267 | * @return array|string Matching cookies
|
---|
268 | */
|
---|
269 | public function getMatching(Net_URL2 $url, $asString = false)
|
---|
270 | {
|
---|
271 | $host = $url->getHost();
|
---|
272 | $path = $url->getPath();
|
---|
273 | $secure = 0 == strcasecmp($url->getScheme(), 'https');
|
---|
274 |
|
---|
275 | $matched = $ret = array();
|
---|
276 | foreach (array_keys($this->cookies) as $domain) {
|
---|
277 | if ($this->domainMatch($host, $domain)) {
|
---|
278 | foreach (array_keys($this->cookies[$domain]) as $cPath) {
|
---|
279 | if (0 === strpos($path, $cPath)) {
|
---|
280 | foreach ($this->cookies[$domain][$cPath] as $name => $cookie) {
|
---|
281 | if (!$cookie['secure'] || $secure) {
|
---|
282 | $matched[$name][strlen($cookie['path'])] = $cookie;
|
---|
283 | }
|
---|
284 | }
|
---|
285 | }
|
---|
286 | }
|
---|
287 | }
|
---|
288 | }
|
---|
289 | foreach ($matched as $cookies) {
|
---|
290 | krsort($cookies);
|
---|
291 | $ret = array_merge($ret, $cookies);
|
---|
292 | }
|
---|
293 | if (!$asString) {
|
---|
294 | return $ret;
|
---|
295 | } else {
|
---|
296 | $str = '';
|
---|
297 | foreach ($ret as $c) {
|
---|
298 | $str .= (empty($str)? '': '; ') . $c['name'] . '=' . $c['value'];
|
---|
299 | }
|
---|
300 | return $str;
|
---|
301 | }
|
---|
302 | }
|
---|
303 |
|
---|
304 | /**
|
---|
305 | * Returns all cookies stored in a jar
|
---|
306 | *
|
---|
307 | * @return array
|
---|
308 | */
|
---|
309 | public function getAll()
|
---|
310 | {
|
---|
311 | $cookies = array();
|
---|
312 | foreach (array_keys($this->cookies) as $domain) {
|
---|
313 | foreach (array_keys($this->cookies[$domain]) as $path) {
|
---|
314 | foreach ($this->cookies[$domain][$path] as $name => $cookie) {
|
---|
315 | $cookies[] = $cookie;
|
---|
316 | }
|
---|
317 | }
|
---|
318 | }
|
---|
319 | return $cookies;
|
---|
320 | }
|
---|
321 |
|
---|
322 | /**
|
---|
323 | * Sets whether session cookies should be serialized when serializing the jar
|
---|
324 | *
|
---|
325 | * @param boolean $serialize serialize?
|
---|
326 | */
|
---|
327 | public function serializeSessionCookies($serialize)
|
---|
328 | {
|
---|
329 | $this->serializeSession = (bool)$serialize;
|
---|
330 | }
|
---|
331 |
|
---|
332 | /**
|
---|
333 | * Sets whether Public Suffix List should be used for restricting cookie-setting
|
---|
334 | *
|
---|
335 | * Without PSL {@link domainMatch()} will only prevent setting cookies for
|
---|
336 | * top-level domains like '.com' or '.org'. However, it will not prevent
|
---|
337 | * setting a cookie for '.co.uk' even though only third-level registrations
|
---|
338 | * are possible in .uk domain.
|
---|
339 | *
|
---|
340 | * With the List it is possible to find the highest level at which a domain
|
---|
341 | * may be registered for a particular top-level domain and consequently
|
---|
342 | * prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by
|
---|
343 | * Firefox, Chrome and Opera browsers to restrict cookie setting.
|
---|
344 | *
|
---|
345 | * Note that PSL is licensed differently to HTTP_Request2 package (refer to
|
---|
346 | * the license information in public-suffix-list.php), so you can disable
|
---|
347 | * its use if this is an issue for you.
|
---|
348 | *
|
---|
349 | * @param boolean $useList use the list?
|
---|
350 | *
|
---|
351 | * @link http://publicsuffix.org/learn/
|
---|
352 | */
|
---|
353 | public function usePublicSuffixList($useList)
|
---|
354 | {
|
---|
355 | $this->useList = (bool)$useList;
|
---|
356 | }
|
---|
357 |
|
---|
358 | /**
|
---|
359 | * Returns string representation of object
|
---|
360 | *
|
---|
361 | * @return string
|
---|
362 | *
|
---|
363 | * @see Serializable::serialize()
|
---|
364 | */
|
---|
365 | public function serialize()
|
---|
366 | {
|
---|
367 | $cookies = $this->getAll();
|
---|
368 | if (!$this->serializeSession) {
|
---|
369 | for ($i = count($cookies) - 1; $i >= 0; $i--) {
|
---|
370 | if (empty($cookies[$i]['expires'])) {
|
---|
371 | unset($cookies[$i]);
|
---|
372 | }
|
---|
373 | }
|
---|
374 | }
|
---|
375 | return serialize(array(
|
---|
376 | 'cookies' => $cookies,
|
---|
377 | 'serializeSession' => $this->serializeSession,
|
---|
378 | 'useList' => $this->useList
|
---|
379 | ));
|
---|
380 | }
|
---|
381 |
|
---|
382 | /**
|
---|
383 | * Constructs the object from serialized string
|
---|
384 | *
|
---|
385 | * @param string $serialized string representation
|
---|
386 | *
|
---|
387 | * @see Serializable::unserialize()
|
---|
388 | */
|
---|
389 | public function unserialize($serialized)
|
---|
390 | {
|
---|
391 | $data = unserialize($serialized);
|
---|
392 | $now = $this->now();
|
---|
393 | $this->serializeSessionCookies($data['serializeSession']);
|
---|
394 | $this->usePublicSuffixList($data['useList']);
|
---|
395 | foreach ($data['cookies'] as $cookie) {
|
---|
396 | if (!empty($cookie['expires']) && $cookie['expires'] <= $now) {
|
---|
397 | continue;
|
---|
398 | }
|
---|
399 | if (!isset($this->cookies[$cookie['domain']])) {
|
---|
400 | $this->cookies[$cookie['domain']] = array();
|
---|
401 | }
|
---|
402 | if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {
|
---|
403 | $this->cookies[$cookie['domain']][$cookie['path']] = array();
|
---|
404 | }
|
---|
405 | $this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;
|
---|
406 | }
|
---|
407 | }
|
---|
408 |
|
---|
409 | /**
|
---|
410 | * Checks whether a cookie domain matches a request host.
|
---|
411 | *
|
---|
412 | * The method is used by {@link store()} to check for whether a document
|
---|
413 | * at given URL can set a cookie with a given domain attribute and by
|
---|
414 | * {@link getMatching()} to find cookies matching the request URL.
|
---|
415 | *
|
---|
416 | * @param string $requestHost request host
|
---|
417 | * @param string $cookieDomain cookie domain
|
---|
418 | *
|
---|
419 | * @return bool match success
|
---|
420 | */
|
---|
421 | public function domainMatch($requestHost, $cookieDomain)
|
---|
422 | {
|
---|
423 | if ($requestHost == $cookieDomain) {
|
---|
424 | return true;
|
---|
425 | }
|
---|
426 | // IP address, we require exact match
|
---|
427 | if (preg_match('/^(?:\d{1,3}\.){3}\d{1,3}$/', $requestHost)) {
|
---|
428 | return false;
|
---|
429 | }
|
---|
430 | if ('.' != $cookieDomain[0]) {
|
---|
431 | $cookieDomain = '.' . $cookieDomain;
|
---|
432 | }
|
---|
433 | // prevents setting cookies for '.com' and similar domains
|
---|
434 | if (!$this->useList && substr_count($cookieDomain, '.') < 2
|
---|
435 | || $this->useList && !self::getRegisteredDomain($cookieDomain)
|
---|
436 | ) {
|
---|
437 | return false;
|
---|
438 | }
|
---|
439 | return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain;
|
---|
440 | }
|
---|
441 |
|
---|
442 | /**
|
---|
443 | * Removes subdomains to get the registered domain (the first after top-level)
|
---|
444 | *
|
---|
445 | * The method will check Public Suffix List to find out where top-level
|
---|
446 | * domain ends and registered domain starts. It will remove domain parts
|
---|
447 | * to the left of registered one.
|
---|
448 | *
|
---|
449 | * @param string $domain domain name
|
---|
450 | *
|
---|
451 | * @return string|bool registered domain, will return false if $domain is
|
---|
452 | * either invalid or a TLD itself
|
---|
453 | */
|
---|
454 | public static function getRegisteredDomain($domain)
|
---|
455 | {
|
---|
456 | $domainParts = explode('.', ltrim($domain, '.'));
|
---|
457 |
|
---|
458 | // load the list if needed
|
---|
459 | if (empty(self::$psl)) {
|
---|
460 | $path = 'data/module//data' . DIRECTORY_SEPARATOR . 'HTTP_Request2';
|
---|
461 | if (0 === strpos($path, '@' . 'data_dir@')) {
|
---|
462 | $path = realpath(
|
---|
463 | dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'
|
---|
464 | . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data'
|
---|
465 | );
|
---|
466 | }
|
---|
467 | self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php';
|
---|
468 | }
|
---|
469 |
|
---|
470 | if (!($result = self::checkDomainsList($domainParts, self::$psl))) {
|
---|
471 | // known TLD, invalid domain name
|
---|
472 | return false;
|
---|
473 | }
|
---|
474 |
|
---|
475 | // unknown TLD
|
---|
476 | if (!strpos($result, '.')) {
|
---|
477 | // fallback to checking that domain "has at least two dots"
|
---|
478 | if (2 > ($count = count($domainParts))) {
|
---|
479 | return false;
|
---|
480 | }
|
---|
481 | return $domainParts[$count - 2] . '.' . $domainParts[$count - 1];
|
---|
482 | }
|
---|
483 | return $result;
|
---|
484 | }
|
---|
485 |
|
---|
486 | /**
|
---|
487 | * Recursive helper method for {@link getRegisteredDomain()}
|
---|
488 | *
|
---|
489 | * @param array $domainParts remaining domain parts
|
---|
490 | * @param mixed $listNode node in {@link HTTP_Request2_CookieJar::$psl} to check
|
---|
491 | *
|
---|
492 | * @return string|null concatenated domain parts, null in case of error
|
---|
493 | */
|
---|
494 | protected static function checkDomainsList(array $domainParts, $listNode)
|
---|
495 | {
|
---|
496 | $sub = array_pop($domainParts);
|
---|
497 | $result = null;
|
---|
498 |
|
---|
499 | if (!is_array($listNode) || is_null($sub)
|
---|
500 | || array_key_exists('!' . $sub, $listNode)
|
---|
501 | ) {
|
---|
502 | return $sub;
|
---|
503 |
|
---|
504 | } elseif (array_key_exists($sub, $listNode)) {
|
---|
505 | $result = self::checkDomainsList($domainParts, $listNode[$sub]);
|
---|
506 |
|
---|
507 | } elseif (array_key_exists('*', $listNode)) {
|
---|
508 | $result = self::checkDomainsList($domainParts, $listNode['*']);
|
---|
509 |
|
---|
510 | } else {
|
---|
511 | return $sub;
|
---|
512 | }
|
---|
513 |
|
---|
514 | return (strlen($result) > 0) ? ($result . '.' . $sub) : null;
|
---|
515 | }
|
---|
516 | }
|
---|
517 | ?> |
---|