Seditio Source
Root |
./othercms/croogo-4.0.7/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php
<?php
/**
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link          http://cakephp.org CakePHP(tm) Project
 * @since         3.5.0
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 */
namespace Cake\Http\Cookie;

use
ArrayIterator;
use
Countable;
use
DateTimeImmutable;
use
DateTimeZone;
use
Exception;
use
InvalidArgumentException;
use
IteratorAggregate;
use
Psr\Http\Message\RequestInterface;
use
Psr\Http\Message\ResponseInterface;
use
Psr\Http\Message\ServerRequestInterface;

/**
 * Cookie Collection
 *
 * Provides an immutable collection of cookies objects. Adding or removing
 * to a collection returns a *new* collection that you must retain.
 */
class CookieCollection implements IteratorAggregate, Countable
{
   
/**
     * Cookie objects
     *
     * @var \Cake\Http\Cookie\CookieInterface[]
     */
   
protected $cookies = [];

   
/**
     * Constructor
     *
     * @param array $cookies Array of cookie objects
     */
   
public function __construct(array $cookies = [])
    {
       
$this->checkCookies($cookies);
        foreach (
$cookies as $cookie) {
           
$this->cookies[$cookie->getId()] = $cookie;
        }
    }

   
/**
     * Create a Cookie Collection from an array of Set-Cookie Headers
     *
     * @param array $header The array of set-cookie header values.
     * @return static
     */
   
public static function createFromHeader(array $header)
    {
       
$cookies = static::parseSetCookieHeader($header);

        return new static(
$cookies);
    }

   
/**
     * Create a new collection from the cookies in a ServerRequest
     *
     * @param \Psr\Http\Message\ServerRequestInterface $request The request to extract cookie data from
     * @return static
     */
   
public static function createFromServerRequest(ServerRequestInterface $request)
    {
       
$data = $request->getCookieParams();
       
$cookies = [];
        foreach (
$data as $name => $value) {
           
$cookies[] = new Cookie($name, $value);
        }

        return new static(
$cookies);
    }

   
/**
     * Get the number of cookies in the collection.
     *
     * @return int
     */
   
public function count()
    {
        return
count($this->cookies);
    }

   
/**
     * Add a cookie and get an updated collection.
     *
     * Cookies are stored by id. This means that there can be duplicate
     * cookies if a cookie collection is used for cookies across multiple
     * domains. This can impact how get(), has() and remove() behave.
     *
     * @param \Cake\Http\Cookie\CookieInterface $cookie Cookie instance to add.
     * @return static
     */
   
public function add(CookieInterface $cookie)
    {
       
$new = clone $this;
       
$new->cookies[$cookie->getId()] = $cookie;

        return
$new;
    }

   
/**
     * Get the first cookie by name.
     *
     * @param string $name The name of the cookie.
     * @return \Cake\Http\Cookie\CookieInterface|null
     */
   
public function get($name)
    {
       
$key = mb_strtolower($name);
        foreach (
$this->cookies as $cookie) {
            if (
mb_strtolower($cookie->getName()) === $key) {
                return
$cookie;
            }
        }

        return
null;
    }

   
/**
     * Check if a cookie with the given name exists
     *
     * @param string $name The cookie name to check.
     * @return bool True if the cookie exists, otherwise false.
     */
   
public function has($name)
    {
       
$key = mb_strtolower($name);
        foreach (
$this->cookies as $cookie) {
            if (
mb_strtolower($cookie->getName()) === $key) {
                return
true;
            }
        }

        return
false;
    }

   
/**
     * Create a new collection with all cookies matching $name removed.
     *
     * If the cookie is not in the collection, this method will do nothing.
     *
     * @param string $name The name of the cookie to remove.
     * @return static
     */
   
public function remove($name)
    {
       
$new = clone $this;
       
$key = mb_strtolower($name);
        foreach (
$new->cookies as $i => $cookie) {
            if (
mb_strtolower($cookie->getName()) === $key) {
                unset(
$new->cookies[$i]);
            }
        }

        return
$new;
    }

   
/**
     * Checks if only valid cookie objects are in the array
     *
     * @param array $cookies Array of cookie objects
     * @return void
     * @throws \InvalidArgumentException
     */
   
protected function checkCookies(array $cookies)
    {
        foreach (
$cookies as $index => $cookie) {
            if (!
$cookie instanceof CookieInterface) {
                throw new
InvalidArgumentException(
                   
sprintf(
                       
'Expected `%s[]` as $cookies but instead got `%s` at index %d',
                        static::class,
                       
getTypeName($cookie),
                       
$index
                   
)
                );
            }
        }
    }

   
/**
     * Gets the iterator
     *
     * @return \ArrayIterator
     */
   
public function getIterator()
    {
        return new
ArrayIterator($this->cookies);
    }

   
/**
     * Add cookies that match the path/domain/expiration to the request.
     *
     * This allows CookieCollections to be used as a 'cookie jar' in an HTTP client
     * situation. Cookies that match the request's domain + path that are not expired
     * when this method is called will be applied to the request.
     *
     * @param \Psr\Http\Message\RequestInterface $request The request to update.
     * @param array $extraCookies Associative array of additional cookies to add into the request. This
     *   is useful when you have cookie data from outside the collection you want to send.
     * @return \Psr\Http\Message\RequestInterface An updated request.
     */
   
public function addToRequest(RequestInterface $request, array $extraCookies = [])
    {
       
$uri = $request->getUri();
       
$cookies = $this->findMatchingCookies(
           
$uri->getScheme(),
           
$uri->getHost(),
           
$uri->getPath() ?: '/'
       
);
       
$cookies = array_merge($cookies, $extraCookies);
       
$cookiePairs = [];
        foreach (
$cookies as $key => $value) {
           
$cookie = sprintf("%s=%s", rawurlencode($key), rawurlencode($value));
           
$size = strlen($cookie);
            if (
$size > 4096) {
               
triggerWarning(sprintf(
                   
'The cookie `%s` exceeds the recommended maximum cookie length of 4096 bytes.',
                   
$key
               
));
            }
           
$cookiePairs[] = $cookie;
        }

        if (empty(
$cookiePairs)) {
            return
$request;
        }

        return
$request->withHeader('Cookie', implode('; ', $cookiePairs));
    }

   
/**
     * Find cookies matching the scheme, host, and path
     *
     * @param string $scheme The http scheme to match
     * @param string $host The host to match.
     * @param string $path The path to match
     * @return array An array of cookie name/value pairs
     */
   
protected function findMatchingCookies($scheme, $host, $path)
    {
       
$out = [];
       
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
        foreach (
$this->cookies as $cookie) {
            if (
$scheme === 'http' && $cookie->isSecure()) {
                continue;
            }
            if (
strpos($path, $cookie->getPath()) !== 0) {
                continue;
            }
           
$domain = $cookie->getDomain();
           
$leadingDot = substr($domain, 0, 1) === '.';
            if (
$leadingDot) {
               
$domain = ltrim($domain, '.');
            }

            if (
$cookie->isExpired($now)) {
                continue;
            }

           
$pattern = '/' . preg_quote($domain, '/') . '$/';
            if (!
preg_match($pattern, $host)) {
                continue;
            }

           
$out[$cookie->getName()] = $cookie->getValue();
        }

        return
$out;
    }

   
/**
     * Create a new collection that includes cookies from the response.
     *
     * @param \Psr\Http\Message\ResponseInterface $response Response to extract cookies from.
     * @param \Psr\Http\Message\RequestInterface $request Request to get cookie context from.
     * @return static
     */
   
public function addFromResponse(ResponseInterface $response, RequestInterface $request)
    {
       
$uri = $request->getUri();
       
$host = $uri->getHost();
       
$path = $uri->getPath() ?: '/';

       
$cookies = static::parseSetCookieHeader($response->getHeader('Set-Cookie'));
       
$cookies = $this->setRequestDefaults($cookies, $host, $path);
       
$new = clone $this;
        foreach (
$cookies as $cookie) {
           
$new->cookies[$cookie->getId()] = $cookie;
        }
       
$new->removeExpiredCookies($host, $path);

        return
$new;
    }

   
/**
     * Apply path and host to the set of cookies if they are not set.
     *
     * @param array $cookies An array of cookies to update.
     * @param string $host The host to set.
     * @param string $path The path to set.
     * @return array An array of updated cookies.
     */
   
protected function setRequestDefaults(array $cookies, $host, $path)
    {
       
$out = [];
        foreach (
$cookies as $name => $cookie) {
            if (!
$cookie->getDomain()) {
               
$cookie = $cookie->withDomain($host);
            }
            if (!
$cookie->getPath()) {
               
$cookie = $cookie->withPath($path);
            }
           
$out[] = $cookie;
        }

        return
$out;
    }

   
/**
     * Parse Set-Cookie headers into array
     *
     * @param array $values List of Set-Cookie Header values.
     * @return \Cake\Http\Cookie\Cookie[] An array of cookie objects
     */
   
protected static function parseSetCookieHeader($values)
    {
       
$cookies = [];
        foreach (
$values as $value) {
           
$value = rtrim($value, ';');
           
$parts = preg_split('/\;[ \t]*/', $value);

           
$name = false;
           
$cookie = [
               
'value' => '',
               
'path' => '',
               
'domain' => '',
               
'secure' => false,
               
'httponly' => false,
               
'expires' => null,
               
'max-age' => null,
            ];
            foreach (
$parts as $i => $part) {
                if (
strpos($part, '=') !== false) {
                    list(
$key, $value) = explode('=', $part, 2);
                } else {
                   
$key = $part;
                   
$value = true;
                }
                if (
$i === 0) {
                   
$name = $key;
                   
$cookie['value'] = urldecode($value);
                    continue;
                }
               
$key = strtolower($key);
                if (
array_key_exists($key, $cookie) && !strlen($cookie[$key])) {
                   
$cookie[$key] = $value;
                }
            }
            try {
               
$expires = null;
                if (
$cookie['max-age'] !== null) {
                   
$expires = new DateTimeImmutable('@' . (time() + $cookie['max-age']));
                } elseif (
$cookie['expires']) {
                   
$expires = new DateTimeImmutable('@' . strtotime($cookie['expires']));
                }
            } catch (
Exception $e) {
               
$expires = null;
            }

            try {
               
$cookies[] = new Cookie(
                   
$name,
                   
$cookie['value'],
                   
$expires,
                   
$cookie['path'],
                   
$cookie['domain'],
                   
$cookie['secure'],
                   
$cookie['httponly']
                );
            } catch (
Exception $e) {
               
// Don't blow up on invalid cookies
           
}
        }

        return
$cookies;
    }

   
/**
     * Remove expired cookies from the collection.
     *
     * @param string $host The host to check for expired cookies on.
     * @param string $path The path to check for expired cookies on.
     * @return void
     */
   
protected function removeExpiredCookies($host, $path)
    {
       
$time = new DateTimeImmutable('now', new DateTimeZone('UTC'));
       
$hostPattern = '/' . preg_quote($host, '/') . '$/';

        foreach (
$this->cookies as $i => $cookie) {
           
$expired = $cookie->isExpired($time);
           
$pathMatches = strpos($path, $cookie->getPath()) === 0;
           
$hostMatches = preg_match($hostPattern, $cookie->getDomain());
            if (
$pathMatches && $hostMatches && $expired) {
                unset(
$this->cookies[$i]);
            }
        }
    }
}