Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. CookieJar.php

class CookieJar

Same name in this branch
  1. 11.1.x vendor/symfony/browser-kit/CookieJar.php \Symfony\Component\BrowserKit\CookieJar

Cookie jar that stores cookies as an array

Hierarchy

  • class \GuzzleHttp\Cookie\CookieJar implements \GuzzleHttp\Cookie\CookieJarInterface

Expanded class hierarchy of CookieJar

1 file declares its use of CookieJar
Client.php in vendor/guzzlehttp/guzzle/src/Client.php

File

vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php, line 11

Namespace

GuzzleHttp\Cookie
View source
class CookieJar implements CookieJarInterface {
    
    /**
     * @var SetCookie[] Loaded cookie data
     */
    private $cookies = [];
    
    /**
     * @var bool
     */
    private $strictMode;
    
    /**
     * @param bool  $strictMode  Set to true to throw exceptions when invalid
     *                           cookies are added to the cookie jar.
     * @param array $cookieArray Array of SetCookie objects or a hash of
     *                           arrays that can be used with the SetCookie
     *                           constructor
     */
    public function __construct(bool $strictMode = false, array $cookieArray = []) {
        $this->strictMode = $strictMode;
        foreach ($cookieArray as $cookie) {
            if (!$cookie instanceof SetCookie) {
                $cookie = new SetCookie($cookie);
            }
            $this->setCookie($cookie);
        }
    }
    
    /**
     * Create a new Cookie jar from an associative array and domain.
     *
     * @param array  $cookies Cookies to create the jar from
     * @param string $domain  Domain to set the cookies to
     */
    public static function fromArray(array $cookies, string $domain) : self {
        $cookieJar = new self();
        foreach ($cookies as $name => $value) {
            $cookieJar->setCookie(new SetCookie([
                'Domain' => $domain,
                'Name' => $name,
                'Value' => $value,
                'Discard' => true,
            ]));
        }
        return $cookieJar;
    }
    
    /**
     * Evaluate if this cookie should be persisted to storage
     * that survives between requests.
     *
     * @param SetCookie $cookie              Being evaluated.
     * @param bool      $allowSessionCookies If we should persist session cookies
     */
    public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false) : bool {
        if ($cookie->getExpires() || $allowSessionCookies) {
            if (!$cookie->getDiscard()) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Finds and returns the cookie based on the name
     *
     * @param string $name cookie name to search for
     *
     * @return SetCookie|null cookie that was found or null if not found
     */
    public function getCookieByName(string $name) : ?SetCookie {
        foreach ($this->cookies as $cookie) {
            if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
                return $cookie;
            }
        }
        return null;
    }
    public function toArray() : array {
        return \array_map(static function (SetCookie $cookie) : array {
            return $cookie->toArray();
        }, $this->getIterator()
            ->getArrayCopy());
    }
    public function clear(?string $domain = null, ?string $path = null, ?string $name = null) : void {
        if (!$domain) {
            $this->cookies = [];
            return;
        }
        elseif (!$path) {
            $this->cookies = \array_filter($this->cookies, static function (SetCookie $cookie) use ($domain) : bool {
                return !$cookie->matchesDomain($domain);
            });
        }
        elseif (!$name) {
            $this->cookies = \array_filter($this->cookies, static function (SetCookie $cookie) use ($path, $domain) : bool {
                return !($cookie->matchesPath($path) && $cookie->matchesDomain($domain));
            });
        }
        else {
            $this->cookies = \array_filter($this->cookies, static function (SetCookie $cookie) use ($path, $domain, $name) {
                return !($cookie->getName() == $name && $cookie->matchesPath($path) && $cookie->matchesDomain($domain));
            });
        }
    }
    public function clearSessionCookies() : void {
        $this->cookies = \array_filter($this->cookies, static function (SetCookie $cookie) : bool {
            return !$cookie->getDiscard() && $cookie->getExpires();
        });
    }
    public function setCookie(SetCookie $cookie) : bool {
        // If the name string is empty (but not 0), ignore the set-cookie
        // string entirely.
        $name = $cookie->getName();
        if (!$name && $name !== '0') {
            return false;
        }
        // Only allow cookies with set and valid domain, name, value
        $result = $cookie->validate();
        if ($result !== true) {
            if ($this->strictMode) {
                throw new \RuntimeException('Invalid cookie: ' . $result);
            }
            $this->removeCookieIfEmpty($cookie);
            return false;
        }
        // Resolve conflicts with previously set cookies
        foreach ($this->cookies as $i => $c) {
            // Two cookies are identical, when their path, and domain are
            // identical.
            if ($c->getPath() != $cookie->getPath() || $c->getDomain() != $cookie->getDomain() || $c->getName() != $cookie->getName()) {
                continue;
            }
            // The previously set cookie is a discard cookie and this one is
            // not so allow the new cookie to be set
            if (!$cookie->getDiscard() && $c->getDiscard()) {
                unset($this->cookies[$i]);
                continue;
            }
            // If the new cookie's expiration is further into the future, then
            // replace the old cookie
            if ($cookie->getExpires() > $c->getExpires()) {
                unset($this->cookies[$i]);
                continue;
            }
            // If the value has changed, we better change it
            if ($cookie->getValue() !== $c->getValue()) {
                unset($this->cookies[$i]);
                continue;
            }
            // The cookie exists, so no need to continue
            return false;
        }
        $this->cookies[] = $cookie;
        return true;
    }
    public function count() : int {
        return \count($this->cookies);
    }
    
    /**
     * @return \ArrayIterator<int, SetCookie>
     */
    public function getIterator() : \ArrayIterator {
        return new \ArrayIterator(\array_values($this->cookies));
    }
    public function extractCookies(RequestInterface $request, ResponseInterface $response) : void {
        if ($cookieHeader = $response->getHeader('Set-Cookie')) {
            foreach ($cookieHeader as $cookie) {
                $sc = SetCookie::fromString($cookie);
                if (!$sc->getDomain()) {
                    $sc->setDomain($request->getUri()
                        ->getHost());
                }
                if (0 !== \strpos($sc->getPath(), '/')) {
                    $sc->setPath($this->getCookiePathFromRequest($request));
                }
                if (!$sc->matchesDomain($request->getUri()
                    ->getHost())) {
                    continue;
                }
                // Note: At this point `$sc->getDomain()` being a public suffix should
                // be rejected, but we don't want to pull in the full PSL dependency.
                $this->setCookie($sc);
            }
        }
    }
    
    /**
     * Computes cookie path following RFC 6265 section 5.1.4
     *
     * @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4
     */
    private function getCookiePathFromRequest(RequestInterface $request) : string {
        $uriPath = $request->getUri()
            ->getPath();
        if ('' === $uriPath) {
            return '/';
        }
        if (0 !== \strpos($uriPath, '/')) {
            return '/';
        }
        if ('/' === $uriPath) {
            return '/';
        }
        $lastSlashPos = \strrpos($uriPath, '/');
        if (0 === $lastSlashPos || false === $lastSlashPos) {
            return '/';
        }
        return \substr($uriPath, 0, $lastSlashPos);
    }
    public function withCookieHeader(RequestInterface $request) : RequestInterface {
        $values = [];
        $uri = $request->getUri();
        $scheme = $uri->getScheme();
        $host = $uri->getHost();
        $path = $uri->getPath() ?: '/';
        foreach ($this->cookies as $cookie) {
            if ($cookie->matchesPath($path) && $cookie->matchesDomain($host) && !$cookie->isExpired() && (!$cookie->getSecure() || $scheme === 'https')) {
                $values[] = $cookie->getName() . '=' . $cookie->getValue();
            }
        }
        return $values ? $request->withHeader('Cookie', \implode('; ', $values)) : $request;
    }
    
    /**
     * If a cookie already exists and the server asks to set it again with a
     * null value, the cookie must be deleted.
     */
    private function removeCookieIfEmpty(SetCookie $cookie) : void {
        $cookieValue = $cookie->getValue();
        if ($cookieValue === null || $cookieValue === '') {
            $this->clear($cookie->getDomain(), $cookie->getPath(), $cookie->getName());
        }
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
CookieJar::$cookies private property
CookieJar::$strictMode private property
CookieJar::clear public function Remove cookies currently held in the cookie jar. Overrides CookieJarInterface::clear
CookieJar::clearSessionCookies public function Discard all sessions cookies. Overrides CookieJarInterface::clearSessionCookies
CookieJar::count public function
CookieJar::extractCookies public function Extract cookies from an HTTP response and store them in the CookieJar. Overrides CookieJarInterface::extractCookies
CookieJar::fromArray public static function Create a new Cookie jar from an associative array and domain.
CookieJar::getCookieByName public function Finds and returns the cookie based on the name
CookieJar::getCookiePathFromRequest private function Computes cookie path following RFC 6265 section 5.1.4
CookieJar::getIterator public function
CookieJar::removeCookieIfEmpty private function If a cookie already exists and the server asks to set it again with a
null value, the cookie must be deleted.
CookieJar::setCookie public function Sets a cookie in the cookie jar. Overrides CookieJarInterface::setCookie
CookieJar::shouldPersist public static function Evaluate if this cookie should be persisted to storage
that survives between requests.
CookieJar::toArray public function Converts the cookie jar to an array. Overrides CookieJarInterface::toArray
CookieJar::withCookieHeader public function Create a request with added cookie headers. Overrides CookieJarInterface::withCookieHeader
CookieJar::__construct public function 2

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal