2015-08-17 17:00:26 -07:00
< ? php
namespace GuzzleHttp\Cookie ;
2015-08-27 12:03:05 -07:00
use Psr\Http\Message\RequestInterface ;
use Psr\Http\Message\ResponseInterface ;
2015-08-17 17:00:26 -07:00
/**
2016-07-18 09:07:48 -07:00
* Cookie jar that stores cookies as an array
2015-08-17 17:00:26 -07:00
*/
2015-08-27 12:03:05 -07:00
class CookieJar implements CookieJarInterface
2015-08-17 17:00:26 -07:00
{
/** @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 .
2015-10-08 11:40:12 -07:00
* @ param array $cookieArray Array of SetCookie objects or a hash of
* arrays that can be used with the SetCookie
* constructor
2015-08-17 17:00:26 -07:00
*/
public function __construct ( $strictMode = false , $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
*
* @ return self
*/
public static function fromArray ( array $cookies , $domain )
{
$cookieJar = new self ();
foreach ( $cookies as $name => $value ) {
$cookieJar -> setCookie ( new SetCookie ([
'Domain' => $domain ,
'Name' => $name ,
'Value' => $value ,
'Discard' => true
]));
}
return $cookieJar ;
}
/**
2016-07-18 09:07:48 -07:00
* @ deprecated
2015-08-17 17:00:26 -07:00
*/
public static function getCookieValue ( $value )
{
return $value ;
}
2015-10-08 11:40:12 -07:00
/**
* Evaluate if this cookie should be persisted to storage
* that survives between requests .
*
* @ param SetCookie $cookie Being evaluated .
2016-07-18 09:07:48 -07:00
* @ param bool $allowSessionCookies If we should persist session cookies
2015-10-08 11:40:12 -07:00
* @ return bool
*/
public static function shouldPersist (
SetCookie $cookie ,
$allowSessionCookies = false
) {
if ( $cookie -> getExpires () || $allowSessionCookies ) {
if ( ! $cookie -> getDiscard ()) {
return true ;
}
}
return false ;
}
2015-08-17 17:00:26 -07:00
public function toArray ()
{
return array_map ( function ( SetCookie $cookie ) {
return $cookie -> toArray ();
}, $this -> getIterator () -> getArrayCopy ());
}
public function clear ( $domain = null , $path = null , $name = null )
{
if ( ! $domain ) {
$this -> cookies = [];
return ;
} elseif ( ! $path ) {
$this -> cookies = array_filter (
$this -> cookies ,
function ( SetCookie $cookie ) use ( $path , $domain ) {
return ! $cookie -> matchesDomain ( $domain );
}
);
} elseif ( ! $name ) {
$this -> cookies = array_filter (
$this -> cookies ,
function ( SetCookie $cookie ) use ( $path , $domain ) {
return ! ( $cookie -> matchesPath ( $path ) &&
$cookie -> matchesDomain ( $domain ));
}
);
} else {
$this -> cookies = array_filter (
$this -> cookies ,
function ( SetCookie $cookie ) use ( $path , $domain , $name ) {
return ! ( $cookie -> getName () == $name &&
$cookie -> matchesPath ( $path ) &&
$cookie -> matchesDomain ( $domain ));
}
);
}
}
public function clearSessionCookies ()
{
$this -> cookies = array_filter (
$this -> cookies ,
function ( SetCookie $cookie ) {
return ! $cookie -> getDiscard () && $cookie -> getExpires ();
}
);
}
public function setCookie ( SetCookie $cookie )
{
2015-10-08 11:40:12 -07:00
// If the name string is empty (but not 0), ignore the set-cookie
// string entirely.
$name = $cookie -> getName ();
if ( ! $name && $name !== '0' ) {
return false ;
}
2015-08-17 17:00:26 -07:00
// 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 );
} else {
$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 ()
{
return count ( $this -> cookies );
}
public function getIterator ()
{
return new \ArrayIterator ( array_values ( $this -> cookies ));
}
public function extractCookies (
RequestInterface $request ,
ResponseInterface $response
) {
2015-08-27 12:03:05 -07:00
if ( $cookieHeader = $response -> getHeader ( 'Set-Cookie' )) {
2015-08-17 17:00:26 -07:00
foreach ( $cookieHeader as $cookie ) {
$sc = SetCookie :: fromString ( $cookie );
if ( ! $sc -> getDomain ()) {
2015-08-27 12:03:05 -07:00
$sc -> setDomain ( $request -> getUri () -> getHost ());
2015-08-17 17:00:26 -07:00
}
$this -> setCookie ( $sc );
}
}
}
2015-08-27 12:03:05 -07:00
public function withCookieHeader ( RequestInterface $request )
2015-08-17 17:00:26 -07:00
{
$values = [];
2015-08-27 12:03:05 -07:00
$uri = $request -> getUri ();
$scheme = $uri -> getScheme ();
$host = $uri -> getHost ();
$path = $uri -> getPath () ? : '/' ;
2015-08-17 17:00:26 -07:00
foreach ( $this -> cookies as $cookie ) {
if ( $cookie -> matchesPath ( $path ) &&
$cookie -> matchesDomain ( $host ) &&
! $cookie -> isExpired () &&
2016-07-18 09:07:48 -07:00
( ! $cookie -> getSecure () || $scheme === 'https' )
2015-08-17 17:00:26 -07:00
) {
$values [] = $cookie -> getName () . '='
2016-07-18 09:07:48 -07:00
. $cookie -> getValue ();
2015-08-17 17:00:26 -07:00
}
}
2015-08-27 12:03:05 -07:00
return $values
? $request -> withHeader ( 'Cookie' , implode ( '; ' , $values ))
: $request ;
2015-08-17 17:00:26 -07:00
}
/**
* If a cookie already exists and the server asks to set it again with a
* null value , the cookie must be deleted .
*
* @ param SetCookie $cookie
*/
private function removeCookieIfEmpty ( SetCookie $cookie )
{
$cookieValue = $cookie -> getValue ();
if ( $cookieValue === null || $cookieValue === '' ) {
$this -> clear (
$cookie -> getDomain (),
$cookie -> getPath (),
$cookie -> getName ()
);
}
}
}