2018-02-01 20:01:12 +00:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* 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 < schmittjoh @ gmail . com >
*/
class Cookie
{
protected $name ;
protected $value ;
protected $domain ;
protected $expire ;
protected $path ;
protected $secure ;
protected $httpOnly ;
private $raw ;
private $sameSite ;
2019-01-18 18:33:28 +00:00
private $secureDefault = false ;
2018-02-01 20:01:12 +00:00
2019-06-11 11:29:32 +00:00
const SAMESITE_NONE = 'none' ;
2018-02-01 20:01:12 +00:00
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 )
{
2019-06-11 11:29:32 +00:00
$data = [
2018-02-01 20:01:12 +00:00
'expires' => 0 ,
'path' => '/' ,
'domain' => null ,
'secure' => false ,
'httponly' => false ,
'raw' => ! $decode ,
'samesite' => null ,
2019-06-11 11:29:32 +00:00
];
2018-10-14 19:50:32 +00:00
$parts = HeaderUtils :: split ( $cookie , ';=' );
$part = array_shift ( $parts );
$name = $decode ? urldecode ( $part [ 0 ]) : $part [ 0 ];
$value = isset ( $part [ 1 ]) ? ( $decode ? urldecode ( $part [ 1 ]) : $part [ 1 ]) : null ;
$data = HeaderUtils :: combine ( $parts ) + $data ;
if ( isset ( $data [ 'max-age' ])) {
$data [ 'expires' ] = time () + ( int ) $data [ 'max-age' ];
2018-02-01 20:01:12 +00:00
}
2018-10-14 19:50:32 +00:00
return new static ( $name , $value , $data [ 'expires' ], $data [ 'path' ], $data [ 'domain' ], $data [ 'secure' ], $data [ 'httponly' ], $data [ 'raw' ], $data [ 'samesite' ]);
2018-02-01 20:01:12 +00:00
}
2019-01-18 18:33:28 +00:00
public static function create ( string $name , string $value = null , $expire = 0 , ? string $path = '/' , string $domain = null , bool $secure = null , bool $httpOnly = true , bool $raw = false , ? string $sameSite = self :: SAMESITE_LAX ) : self
{
return new self ( $name , $value , $expire , $path , $domain , $secure , $httpOnly , $raw , $sameSite );
}
2018-02-01 20:01:12 +00:00
/**
* @ 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
2019-01-18 18:33:28 +00:00
* @ param bool | null $secure Whether the client should send back the cookie only over HTTPS or null to auto - enable this when the request is already using HTTPS
2018-02-01 20:01:12 +00:00
* @ 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
*/
2019-01-18 18:33:28 +00:00
public function __construct ( string $name , string $value = null , $expire = 0 , ? string $path = '/' , string $domain = null , ? bool $secure = false , bool $httpOnly = true , bool $raw = false , string $sameSite = null )
2018-02-01 20:01:12 +00:00
{
2019-01-18 18:33:28 +00:00
if ( 9 > \func_num_args ()) {
@ trigger_error ( sprintf ( 'The default value of the "$secure" and "$samesite" arguments of "%s"\'s constructor will respectively change from "false" to "null" and from "null" to "lax" in Symfony 5.0, you should define their values explicitly or use "Cookie::create()" instead.' , __METHOD__ ), E_USER_DEPRECATED );
}
2018-02-01 20:01:12 +00:00
// 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 ;
2018-10-14 19:50:32 +00:00
$this -> secure = $secure ;
$this -> httpOnly = $httpOnly ;
$this -> raw = $raw ;
2018-02-01 20:01:12 +00:00
2019-01-18 18:33:28 +00:00
if ( '' === $sameSite ) {
$sameSite = null ;
} elseif ( null !== $sameSite ) {
2018-02-01 20:01:12 +00:00
$sameSite = strtolower ( $sameSite );
}
2019-06-11 11:29:32 +00:00
if ( ! \in_array ( $sameSite , [ self :: SAMESITE_LAX , self :: SAMESITE_STRICT , self :: SAMESITE_NONE , null ], true )) {
2018-02-01 20:01:12 +00:00
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 ()) {
2018-06-13 18:35:28 +00:00
$str .= 'deleted; expires=' . gmdate ( 'D, d-M-Y H:i:s T' , time () - 31536001 ) . '; Max-Age=0' ;
2018-02-01 20:01:12 +00:00
} else {
$str .= $this -> isRaw () ? $this -> getValue () : rawurlencode ( $this -> getValue ());
if ( 0 !== $this -> getExpiresTime ()) {
2018-06-13 18:35:28 +00:00
$str .= '; expires=' . gmdate ( 'D, d-M-Y H:i:s T' , $this -> getExpiresTime ()) . '; Max-Age=' . $this -> getMaxAge ();
2018-02-01 20:01:12 +00:00
}
}
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 ()
{
2018-06-13 18:35:28 +00:00
$maxAge = $this -> expire - time ();
return 0 >= $maxAge ? 0 : $maxAge ;
2018-02-01 20:01:12 +00:00
}
/**
* 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 ()
{
2019-01-18 18:33:28 +00:00
return $this -> secure ? ? $this -> secureDefault ;
2018-02-01 20:01:12 +00:00
}
/**
* 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 ()
{
2018-10-14 19:50:32 +00:00
return 0 !== $this -> expire && $this -> expire < time ();
2018-02-01 20:01:12 +00:00
}
/**
* 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 ;
}
2019-01-18 18:33:28 +00:00
/**
* @ param bool $default The default value of the " secure " flag when it is set to null
*/
public function setSecureDefault ( bool $default ) : void
{
$this -> secureDefault = $default ;
}
2018-02-01 20:01:12 +00:00
}