<?php 
 
/* 
 * This file is part of the Symfony package. 
 * 
 * (c) Fabien Potencier <[email protected]> 
 * 
 * For the full copyright and license information, please view the LICENSE 
 * file that was distributed with this source code. 
 */ 
 
namespace Symfony\Component\HttpFoundation; 
 
/** 
 * Represents a cookie. 
 * 
 * @author Johannes M. Schmitt <[email protected]> 
 */ 
class Cookie 
{ 
    protected $name; 
    protected $value; 
    protected $domain; 
    protected $expire; 
    protected $path; 
    protected $secure; 
    protected $httpOnly; 
    private $raw; 
    private $sameSite; 
 
    const SAMESITE_LAX = 'lax'; 
    const SAMESITE_STRICT = 'strict'; 
 
    /** 
     * Creates cookie from raw header string. 
     * 
     * @param string $cookie 
     * @param bool   $decode 
     * 
     * @return static 
     */ 
    public static function fromString($cookie, $decode = false) 
    { 
        $data = array( 
            'expires' => 0, 
            'path' => '/', 
            'domain' => null, 
            'secure' => false, 
            'httponly' => true, 
            'raw' => !$decode, 
            'samesite' => null, 
        ); 
        foreach (explode(';', $cookie) as $part) { 
            if (false === strpos($part, '=')) { 
                $key = trim($part); 
                $value = true; 
            } else { 
                list($key, $value) = explode('=', trim($part), 2); 
                $key = trim($key); 
                $value = trim($value); 
            } 
            if (!isset($data['name'])) { 
                $data['name'] = $decode ? urldecode($key) : $key; 
                $data['value'] = true === $value ? null : ($decode ? urldecode($value) : $value); 
                continue; 
            } 
            switch ($key = strtolower($key)) { 
                case 'name': 
                case 'value': 
                    break; 
                case 'max-age': 
                    $data['expires'] = time() + (int) $value; 
                    break; 
                default: 
                    $data[$key] = $value; 
                    break; 
            } 
        } 
 
        return new static($data['name'], $data['value'], $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']); 
    } 
 
    /** 
     * Constructor. 
     * 
     * @param string                        $name     The name of the cookie 
     * @param string|null                   $value    The value of the cookie 
     * @param int|string|\DateTimeInterface $expire   The time the cookie expires 
     * @param string                        $path     The path on the server in which the cookie will be available on 
     * @param string|null                   $domain   The domain that the cookie is available to 
     * @param bool                          $secure   Whether the cookie should only be transmitted over a secure HTTPS connection from the client 
     * @param bool                          $httpOnly Whether the cookie will be made accessible only through the HTTP protocol 
     * @param bool                          $raw      Whether the cookie value should be sent with no url encoding 
     * @param string|null                   $sameSite Whether the cookie will be available for cross-site requests 
     * 
     * @throws \InvalidArgumentException 
     */ 
    public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true, $raw = false, $sameSite = null) 
    { 
        // from PHP source code 
        if (preg_match("/[=,; \t\r\n\013\014]/", $name)) { 
            throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name)); 
        } 
 
        if (empty($name)) { 
            throw new \InvalidArgumentException('The cookie name cannot be empty.'); 
        } 
 
        // convert expiration time to a Unix timestamp 
        if ($expire instanceof \DateTimeInterface) { 
            $expire = $expire->format('U'); 
        } elseif (!is_numeric($expire)) { 
            $expire = strtotime($expire); 
 
            if (false === $expire) { 
                throw new \InvalidArgumentException('The cookie expiration time is not valid.'); 
            } 
        } 
 
        $this->name = $name; 
        $this->value = $value; 
        $this->domain = $domain; 
        $this->expire = 0 < $expire ? (int) $expire : 0; 
        $this->path = empty($path) ? '/' : $path; 
        $this->secure = (bool) $secure; 
        $this->httpOnly = (bool) $httpOnly; 
        $this->raw = (bool) $raw; 
 
        if (!in_array($sameSite, array(self::SAMESITE_LAX, self::SAMESITE_STRICT, null), true)) { 
            throw new \InvalidArgumentException('The "sameSite" parameter value is not valid.'); 
        } 
 
        $this->sameSite = $sameSite; 
    } 
 
    /** 
     * Returns the cookie as a string. 
     * 
     * @return string The cookie 
     */ 
    public function __toString() 
    { 
        $str = ($this->isRaw() ? $this->getName() : urlencode($this->getName())).'='; 
 
        if ('' === (string) $this->getValue()) { 
            $str .= 'deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; max-age=-31536001'; 
        } else { 
            $str .= $this->isRaw() ? $this->getValue() : urlencode($this->getValue()); 
 
            if (0 !== $this->getExpiresTime()) { 
                $str .= '; expires='.gmdate('D, d-M-Y H:i:s T', $this->getExpiresTime()).'; max-age='.$this->getMaxAge(); 
            } 
        } 
 
        if ($this->getPath()) { 
            $str .= '; path='.$this->getPath(); 
        } 
 
        if ($this->getDomain()) { 
            $str .= '; domain='.$this->getDomain(); 
        } 
 
        if (true === $this->isSecure()) { 
            $str .= '; secure'; 
        } 
 
        if (true === $this->isHttpOnly()) { 
            $str .= '; httponly'; 
        } 
 
        if (null !== $this->getSameSite()) { 
            $str .= '; samesite='.$this->getSameSite(); 
        } 
 
        return $str; 
    } 
 
    /** 
     * Gets the name of the cookie. 
     * 
     * @return string 
     */ 
    public function getName() 
    { 
        return $this->name; 
    } 
 
    /** 
     * Gets the value of the cookie. 
     * 
     * @return string|null 
     */ 
    public function getValue() 
    { 
        return $this->value; 
    } 
 
    /** 
     * Gets the domain that the cookie is available to. 
     * 
     * @return string|null 
     */ 
    public function getDomain() 
    { 
        return $this->domain; 
    } 
 
    /** 
     * Gets the time the cookie expires. 
     * 
     * @return int 
     */ 
    public function getExpiresTime() 
    { 
        return $this->expire; 
    } 
 
    /** 
     * Gets the max-age attribute. 
     * 
     * @return int 
     */ 
    public function getMaxAge() 
    { 
        return 0 !== $this->expire ? $this->expire - time() : 0; 
    } 
 
    /** 
     * Gets the path on the server in which the cookie will be available on. 
     * 
     * @return string 
     */ 
    public function getPath() 
    { 
        return $this->path; 
    } 
 
    /** 
     * Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client. 
     * 
     * @return bool 
     */ 
    public function isSecure() 
    { 
        return $this->secure; 
    } 
 
    /** 
     * Checks whether the cookie will be made accessible only through the HTTP protocol. 
     * 
     * @return bool 
     */ 
    public function isHttpOnly() 
    { 
        return $this->httpOnly; 
    } 
 
    /** 
     * Whether this cookie is about to be cleared. 
     * 
     * @return bool 
     */ 
    public function isCleared() 
    { 
        return $this->expire < time(); 
    } 
 
    /** 
     * Checks if the cookie value should be sent with no url encoding. 
     * 
     * @return bool 
     */ 
    public function isRaw() 
    { 
        return $this->raw; 
    } 
 
    /** 
     * Gets the SameSite attribute. 
     * 
     * @return string|null 
     */ 
    public function getSameSite() 
    { 
        return $this->sameSite; 
    } 
} 
 
 |