3
namespace GuzzleHttp\Cookie;
5
use GuzzleHttp\Message\RequestInterface;
6
use GuzzleHttp\Message\ResponseInterface;
7
use GuzzleHttp\ToArrayInterface;
10
* Cookie jar that stores cookies an an array
12
class CookieJar implements CookieJarInterface, ToArrayInterface
14
/** @var SetCookie[] Loaded cookie data */
15
private $cookies = [];
21
* @param bool $strictMode Set to true to throw exceptions when invalid
22
* cookies are added to the cookie jar.
23
* @param array $cookieArray Array of SetCookie objects or a hash of arrays
24
* that can be used with the SetCookie constructor
26
public function __construct($strictMode = false, $cookieArray = [])
28
$this->strictMode = $strictMode;
30
foreach ($cookieArray as $cookie) {
31
if (!($cookieArray instanceof SetCookie)) {
32
$cookie = new SetCookie($cookie);
34
$this->setCookie($cookie);
39
* Create a new Cookie jar from an associative array and domain.
41
* @param array $cookies Cookies to create the jar from
42
* @param string $domain Domain to set the cookies to
46
public static function fromArray(array $cookies, $domain)
48
$cookieJar = new self();
49
foreach ($cookies as $name => $value) {
50
$cookieJar->setCookie(new SetCookie([
62
* Quote the cookie value if it is not already quoted and it contains
63
* problematic characters.
65
* @param string $value Value that may or may not need to be quoted
69
public static function getCookieValue($value)
71
if (substr($value, 0, 1) !== '"' &&
72
substr($value, -1, 1) !== '"' &&
75
$value = '"' . $value . '"';
81
public function toArray()
83
return array_map(function (SetCookie $cookie) {
84
return $cookie->toArray();
85
}, $this->getIterator()->getArrayCopy());
88
public function clear($domain = null, $path = null, $name = null)
94
$this->cookies = array_filter(
96
function (SetCookie $cookie) use ($path, $domain) {
97
return !$cookie->matchesDomain($domain);
101
$this->cookies = array_filter(
103
function (SetCookie $cookie) use ($path, $domain) {
104
return !($cookie->matchesPath($path) &&
105
$cookie->matchesDomain($domain));
109
$this->cookies = array_filter(
111
function (SetCookie $cookie) use ($path, $domain, $name) {
112
return !($cookie->getName() == $name &&
113
$cookie->matchesPath($path) &&
114
$cookie->matchesDomain($domain));
120
public function clearSessionCookies()
122
$this->cookies = array_filter(
124
function (SetCookie $cookie) {
125
return !$cookie->getDiscard() && $cookie->getExpires();
130
public function setCookie(SetCookie $cookie)
132
// Only allow cookies with set and valid domain, name, value
133
$result = $cookie->validate();
134
if ($result !== true) {
135
if ($this->strictMode) {
136
throw new \RuntimeException('Invalid cookie: ' . $result);
138
$this->removeCookieIfEmpty($cookie);
143
// Resolve conflicts with previously set cookies
144
foreach ($this->cookies as $i => $c) {
146
// Two cookies are identical, when their path, and domain are
148
if ($c->getPath() != $cookie->getPath() ||
149
$c->getDomain() != $cookie->getDomain() ||
150
$c->getName() != $cookie->getName()
155
// The previously set cookie is a discard cookie and this one is
156
// not so allow the new cookie to be set
157
if (!$cookie->getDiscard() && $c->getDiscard()) {
158
unset($this->cookies[$i]);
162
// If the new cookie's expiration is further into the future, then
163
// replace the old cookie
164
if ($cookie->getExpires() > $c->getExpires()) {
165
unset($this->cookies[$i]);
169
// If the value has changed, we better change it
170
if ($cookie->getValue() !== $c->getValue()) {
171
unset($this->cookies[$i]);
175
// The cookie exists, so no need to continue
179
$this->cookies[] = $cookie;
184
public function count()
186
return count($this->cookies);
189
public function getIterator()
191
return new \ArrayIterator(array_values($this->cookies));
194
public function extractCookies(
195
RequestInterface $request,
196
ResponseInterface $response
198
if ($cookieHeader = $response->getHeader('Set-Cookie', true)) {
199
foreach ($cookieHeader as $cookie) {
200
$sc = SetCookie::fromString($cookie);
201
if (!$sc->getDomain()) {
202
$sc->setDomain($request->getHost());
204
$this->setCookie($sc);
209
public function addCookieHeader(RequestInterface $request)
212
$scheme = $request->getScheme();
213
$host = $request->getHost();
214
$path = $request->getPath();
216
foreach ($this->cookies as $cookie) {
217
if ($cookie->matchesPath($path) &&
218
$cookie->matchesDomain($host) &&
219
!$cookie->isExpired() &&
220
(!$cookie->getSecure() || $scheme == 'https')
222
$values[] = $cookie->getName() . '='
223
. self::getCookieValue($cookie->getValue());
228
$request->setHeader('Cookie', implode('; ', $values));
233
* If a cookie already exists and the server asks to set it again with a
234
* null value, the cookie must be deleted.
236
* @param SetCookie $cookie
238
private function removeCookieIfEmpty(SetCookie $cookie)
240
$cookieValue = $cookie->getValue();
241
if ($cookieValue === null || $cookieValue === '') {
243
$cookie->getDomain(),