2011-01-15 17:53:30 +00:00
< ? php
2011-01-29 14:45:10 +00:00
/*
* This file is part of the Symfony package .
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2011-01-29 14:45:10 +00:00
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2011-01-15 17:53:30 +00:00
namespace Symfony\Component\HttpFoundation ;
/**
2014-12-21 17:00:50 +00:00
* Represents a cookie .
2011-01-15 17:53:30 +00:00
*
* @ author Johannes M . Schmitt < schmittjoh @ gmail . com >
*/
class Cookie
{
protected $name ;
protected $value ;
protected $domain ;
protected $expire ;
protected $path ;
protected $secure ;
2011-03-03 13:49:34 +00:00
protected $httpOnly ;
2016-03-11 09:58:00 +00:00
private $raw ;
2016-06-18 21:28:23 +01:00
private $sameSite ;
2018-09-11 17:15:43 +01:00
private $secureDefault = false ;
2016-06-18 21:28:23 +01:00
2019-05-10 20:58:31 +01:00
const SAMESITE_NONE = 'none' ;
2016-06-18 21:28:23 +01:00
const SAMESITE_LAX = 'lax' ;
const SAMESITE_STRICT = 'strict' ;
2011-01-15 17:53:30 +00:00
2016-11-19 14:10:17 +00:00
/**
* Creates cookie from raw header string .
*
* @ param string $cookie
* @ param bool $decode
*
* @ return static
*/
public static function fromString ( $cookie , $decode = false )
{
2019-01-16 18:24:45 +00:00
$data = [
2016-11-19 14:10:17 +00:00
'expires' => 0 ,
'path' => '/' ,
'domain' => null ,
'secure' => false ,
2017-07-06 09:48:01 +01:00
'httponly' => false ,
2016-11-19 14:10:17 +00:00
'raw' => ! $decode ,
'samesite' => null ,
2019-01-16 18:24:45 +00:00
];
2018-04-20 15:29:33 +01: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 ;
2018-04-29 10:29:07 +01:00
$data = HeaderUtils :: combine ( $parts ) + $data ;
2018-04-20 15:29:33 +01:00
if ( isset ( $data [ 'max-age' ])) {
$data [ 'expires' ] = time () + ( int ) $data [ 'max-age' ];
2016-11-19 14:10:17 +00:00
}
2018-04-20 15:29:33 +01:00
return new static ( $name , $value , $data [ 'expires' ], $data [ 'path' ], $data [ 'domain' ], $data [ 'secure' ], $data [ 'httponly' ], $data [ 'raw' ], $data [ 'samesite' ]);
2016-11-19 14:10:17 +00:00
}
2018-09-11 17:15:43 +01: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 );
}
2011-06-10 07:59:49 +01:00
/**
2016-06-16 06:18:30 +01:00
* @ param string $name The name of the cookie
2016-11-19 14:10:17 +00:00
* @ param string | null $value The value of the cookie
2016-06-16 06:18:30 +01:00
* @ 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
2016-11-19 14:10:17 +00:00
* @ param string | null $domain The domain that the cookie is available to
2018-09-11 17:15:43 +01: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
2016-06-16 06:18:30 +01:00
* @ param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
2016-06-16 06:20:30 +01:00
* @ param bool $raw Whether the cookie value should be sent with no url encoding
2016-06-18 21:28:23 +01:00
* @ param string | null $sameSite Whether the cookie will be available for cross - site requests
2011-07-20 09:06:02 +01:00
*
2012-12-16 12:02:54 +00:00
* @ throws \InvalidArgumentException
2011-06-10 07:59:49 +01:00
*/
2018-09-11 17:15:43 +01: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 )
2011-01-15 17:53:30 +00:00
{
2018-09-11 17:15:43 +01: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 );
}
2011-01-15 17:53:30 +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 )) {
2011-06-10 07:59:49 +01:00
throw new \InvalidArgumentException ( 'The cookie name cannot be empty.' );
2011-01-15 17:53:30 +00:00
}
2011-03-06 09:39:33 +00:00
2011-04-13 19:12:14 +01:00
// convert expiration time to a Unix timestamp
2016-05-11 14:21:50 +01:00
if ( $expire instanceof \DateTimeInterface ) {
2011-04-13 19:12:14 +01:00
$expire = $expire -> format ( 'U' );
} elseif ( ! is_numeric ( $expire )) {
$expire = strtotime ( $expire );
2016-12-14 18:35:20 +00:00
if ( false === $expire ) {
2011-04-13 19:12:14 +01:00
throw new \InvalidArgumentException ( 'The cookie expiration time is not valid.' );
}
2011-03-05 23:13:47 +00:00
}
2011-01-15 17:53:30 +00:00
$this -> name = $name ;
$this -> value = $value ;
$this -> domain = $domain ;
2016-12-14 18:35:20 +00:00
$this -> expire = 0 < $expire ? ( int ) $expire : 0 ;
2011-09-28 09:49:50 +01:00
$this -> path = empty ( $path ) ? '/' : $path ;
2017-10-28 19:15:32 +01:00
$this -> secure = $secure ;
$this -> httpOnly = $httpOnly ;
$this -> raw = $raw ;
2016-06-18 21:28:23 +01:00
2018-09-11 17:15:43 +01:00
if ( '' === $sameSite ) {
$sameSite = null ;
} elseif ( null !== $sameSite ) {
2017-07-19 12:17:30 +01:00
$sameSite = strtolower ( $sameSite );
}
2019-05-10 20:58:31 +01:00
if ( ! \in_array ( $sameSite , [ self :: SAMESITE_LAX , self :: SAMESITE_STRICT , self :: SAMESITE_NONE , null ], true )) {
2016-06-23 14:33:17 +01:00
throw new \InvalidArgumentException ( 'The "sameSite" parameter value is not valid.' );
2016-06-18 21:28:23 +01:00
}
$this -> sameSite = $sameSite ;
2011-01-15 17:53:30 +00:00
}
2011-05-19 16:38:16 +01:00
2012-06-25 17:21:41 +01:00
/**
* Returns the cookie as a string .
*
* @ return string The cookie
*/
2011-05-19 08:48:58 +01:00
public function __toString ()
{
2016-12-13 18:58:15 +00:00
$str = ( $this -> isRaw () ? $this -> getName () : urlencode ( $this -> getName ())) . '=' ;
2011-05-19 08:48:58 +01:00
2011-05-19 16:12:16 +01:00
if ( '' === ( string ) $this -> getValue ()) {
2018-04-05 13:19:22 +01:00
$str .= 'deleted; expires=' . gmdate ( 'D, d-M-Y H:i:s T' , time () - 31536001 ) . '; Max-Age=0' ;
2011-05-19 08:48:58 +01:00
} else {
2017-07-12 14:02:55 +01:00
$str .= $this -> isRaw () ? $this -> getValue () : rawurlencode ( $this -> getValue ());
2011-05-19 08:48:58 +01:00
2016-12-14 18:35:20 +00:00
if ( 0 !== $this -> getExpiresTime ()) {
2018-04-05 13:19:22 +01:00
$str .= '; expires=' . gmdate ( 'D, d-M-Y H:i:s T' , $this -> getExpiresTime ()) . '; Max-Age=' . $this -> getMaxAge ();
2011-05-19 08:48:58 +01:00
}
}
2016-12-13 18:58:15 +00:00
if ( $this -> getPath ()) {
$str .= '; path=' . $this -> getPath ();
2011-05-19 08:48:58 +01:00
}
2013-04-20 18:50:53 +01:00
if ( $this -> getDomain ()) {
2011-05-19 08:48:58 +01:00
$str .= '; domain=' . $this -> getDomain ();
}
if ( true === $this -> isSecure ()) {
$str .= '; secure' ;
}
if ( true === $this -> isHttpOnly ()) {
$str .= '; httponly' ;
}
2016-06-18 21:28:23 +01:00
if ( null !== $this -> getSameSite ()) {
$str .= '; samesite=' . $this -> getSameSite ();
}
2011-05-19 08:48:58 +01:00
return $str ;
}
2011-01-15 17:53:30 +00:00
2011-06-10 07:59:49 +01:00
/**
* Gets the name of the cookie .
*
* @ return string
*/
2011-01-15 17:53:30 +00:00
public function getName ()
{
return $this -> name ;
}
2011-06-10 07:59:49 +01:00
/**
* Gets the value of the cookie .
*
2016-12-13 18:58:15 +00:00
* @ return string | null
2011-06-10 07:59:49 +01:00
*/
2011-01-15 17:53:30 +00:00
public function getValue ()
{
return $this -> value ;
}
2011-06-10 07:59:49 +01:00
/**
* Gets the domain that the cookie is available to .
*
2016-12-13 18:58:15 +00:00
* @ return string | null
2011-06-10 07:59:49 +01:00
*/
2011-01-15 17:53:30 +00:00
public function getDomain ()
{
return $this -> domain ;
}
2011-06-10 07:59:49 +01:00
/**
* Gets the time the cookie expires .
*
2014-04-16 11:30:19 +01:00
* @ return int
2011-06-10 07:59:49 +01:00
*/
2011-04-13 19:09:04 +01:00
public function getExpiresTime ()
2011-01-15 17:53:30 +00:00
{
return $this -> expire ;
}
2016-11-26 11:57:47 +00:00
/**
* Gets the max - age attribute .
*
* @ return int
*/
public function getMaxAge ()
{
2018-04-05 13:19:22 +01:00
$maxAge = $this -> expire - time ();
return 0 >= $maxAge ? 0 : $maxAge ;
2016-11-26 11:57:47 +00:00
}
2011-06-10 07:59:49 +01:00
/**
* Gets the path on the server in which the cookie will be available on .
*
* @ return string
*/
2011-01-15 17:53:30 +00:00
public function getPath ()
{
2011-09-28 09:49:50 +01:00
return $this -> path ;
2011-01-15 17:53:30 +00:00
}
2011-06-10 07:59:49 +01:00
/**
* Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client .
*
2014-04-16 11:30:19 +01:00
* @ return bool
2011-06-10 07:59:49 +01:00
*/
2011-01-15 17:53:30 +00:00
public function isSecure ()
{
2018-09-11 17:15:43 +01:00
return $this -> secure ? ? $this -> secureDefault ;
2011-01-15 17:53:30 +00:00
}
2011-06-10 07:59:49 +01:00
/**
* Checks whether the cookie will be made accessible only through the HTTP protocol .
*
2014-04-16 11:30:19 +01:00
* @ return bool
2011-06-10 07:59:49 +01:00
*/
2011-03-03 13:49:34 +00:00
public function isHttpOnly ()
2011-01-15 17:53:30 +00:00
{
2011-03-03 13:49:34 +00:00
return $this -> httpOnly ;
2011-01-15 17:53:30 +00:00
}
/**
2014-12-21 17:00:50 +00:00
* Whether this cookie is about to be cleared .
2011-01-15 17:53:30 +00:00
*
2014-04-16 11:30:19 +01:00
* @ return bool
2011-01-15 17:53:30 +00:00
*/
public function isCleared ()
{
2018-07-23 19:55:22 +01:00
return 0 !== $this -> expire && $this -> expire < time ();
2011-01-15 17:53:30 +00:00
}
2016-03-11 09:58:00 +00:00
/**
* Checks if the cookie value should be sent with no url encoding .
*
* @ return bool
*/
public function isRaw ()
{
return $this -> raw ;
}
2016-06-18 21:28:23 +01:00
/**
* Gets the SameSite attribute .
*
* @ return string | null
*/
public function getSameSite ()
{
return $this -> sameSite ;
}
2018-09-11 17:15:43 +01: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 ;
}
2011-06-08 11:16:48 +01:00
}