scratch – Blame information for rev

Subversion Repositories:
Rev:
Rev Author Line No. Line
87 office 1 <?php
2  
3 namespace GuzzleHttp\Cookie;
4  
5 use GuzzleHttp\Message\RequestInterface;
6 use GuzzleHttp\Message\ResponseInterface;
7 use GuzzleHttp\ToArrayInterface;
8  
9 /**
10 * Cookie jar that stores cookies an an array
11 */
12 class CookieJar implements CookieJarInterface, ToArrayInterface
13 {
14 /** @var SetCookie[] Loaded cookie data */
15 private $cookies = [];
16  
17 /** @var bool */
18 private $strictMode;
19  
20 /**
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
25 */
26 public function __construct($strictMode = false, $cookieArray = [])
27 {
28 $this->strictMode = $strictMode;
29  
30 foreach ($cookieArray as $cookie) {
31 if (!($cookieArray instanceof SetCookie)) {
32 $cookie = new SetCookie($cookie);
33 }
34 $this->setCookie($cookie);
35 }
36 }
37  
38 /**
39 * Create a new Cookie jar from an associative array and domain.
40 *
41 * @param array $cookies Cookies to create the jar from
42 * @param string $domain Domain to set the cookies to
43 *
44 * @return self
45 */
46 public static function fromArray(array $cookies, $domain)
47 {
48 $cookieJar = new self();
49 foreach ($cookies as $name => $value) {
50 $cookieJar->setCookie(new SetCookie([
51 'Domain' => $domain,
52 'Name' => $name,
53 'Value' => $value,
54 'Discard' => true
55 ]));
56 }
57  
58 return $cookieJar;
59 }
60  
61 /**
62 * Quote the cookie value if it is not already quoted and it contains
63 * problematic characters.
64 *
65 * @param string $value Value that may or may not need to be quoted
66 *
67 * @return string
68 */
69 public static function getCookieValue($value)
70 {
71 if (substr($value, 0, 1) !== '"' &&
72 substr($value, -1, 1) !== '"' &&
73 strpbrk($value, ';,')
74 ) {
75 $value = '"' . $value . '"';
76 }
77  
78 return $value;
79 }
80  
81 public function toArray()
82 {
83 return array_map(function (SetCookie $cookie) {
84 return $cookie->toArray();
85 }, $this->getIterator()->getArrayCopy());
86 }
87  
88 public function clear($domain = null, $path = null, $name = null)
89 {
90 if (!$domain) {
91 $this->cookies = [];
92 return;
93 } elseif (!$path) {
94 $this->cookies = array_filter(
95 $this->cookies,
96 function (SetCookie $cookie) use ($path, $domain) {
97 return !$cookie->matchesDomain($domain);
98 }
99 );
100 } elseif (!$name) {
101 $this->cookies = array_filter(
102 $this->cookies,
103 function (SetCookie $cookie) use ($path, $domain) {
104 return !($cookie->matchesPath($path) &&
105 $cookie->matchesDomain($domain));
106 }
107 );
108 } else {
109 $this->cookies = array_filter(
110 $this->cookies,
111 function (SetCookie $cookie) use ($path, $domain, $name) {
112 return !($cookie->getName() == $name &&
113 $cookie->matchesPath($path) &&
114 $cookie->matchesDomain($domain));
115 }
116 );
117 }
118 }
119  
120 public function clearSessionCookies()
121 {
122 $this->cookies = array_filter(
123 $this->cookies,
124 function (SetCookie $cookie) {
125 return !$cookie->getDiscard() && $cookie->getExpires();
126 }
127 );
128 }
129  
130 public function setCookie(SetCookie $cookie)
131 {
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);
137 } else {
138 $this->removeCookieIfEmpty($cookie);
139 return false;
140 }
141 }
142  
143 // Resolve conflicts with previously set cookies
144 foreach ($this->cookies as $i => $c) {
145  
146 // Two cookies are identical, when their path, and domain are
147 // identical.
148 if ($c->getPath() != $cookie->getPath() ||
149 $c->getDomain() != $cookie->getDomain() ||
150 $c->getName() != $cookie->getName()
151 ) {
152 continue;
153 }
154  
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]);
159 continue;
160 }
161  
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]);
166 continue;
167 }
168  
169 // If the value has changed, we better change it
170 if ($cookie->getValue() !== $c->getValue()) {
171 unset($this->cookies[$i]);
172 continue;
173 }
174  
175 // The cookie exists, so no need to continue
176 return false;
177 }
178  
179 $this->cookies[] = $cookie;
180  
181 return true;
182 }
183  
184 public function count()
185 {
186 return count($this->cookies);
187 }
188  
189 public function getIterator()
190 {
191 return new \ArrayIterator(array_values($this->cookies));
192 }
193  
194 public function extractCookies(
195 RequestInterface $request,
196 ResponseInterface $response
197 ) {
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());
203 }
204 $this->setCookie($sc);
205 }
206 }
207 }
208  
209 public function addCookieHeader(RequestInterface $request)
210 {
211 $values = [];
212 $scheme = $request->getScheme();
213 $host = $request->getHost();
214 $path = $request->getPath();
215  
216 foreach ($this->cookies as $cookie) {
217 if ($cookie->matchesPath($path) &&
218 $cookie->matchesDomain($host) &&
219 !$cookie->isExpired() &&
220 (!$cookie->getSecure() || $scheme == 'https')
221 ) {
222 $values[] = $cookie->getName() . '='
223 . self::getCookieValue($cookie->getValue());
224 }
225 }
226  
227 if ($values) {
228 $request->setHeader('Cookie', implode('; ', $values));
229 }
230 }
231  
232 /**
233 * If a cookie already exists and the server asks to set it again with a
234 * null value, the cookie must be deleted.
235 *
236 * @param SetCookie $cookie
237 */
238 private function removeCookieIfEmpty(SetCookie $cookie)
239 {
240 $cookieValue = $cookie->getValue();
241 if ($cookieValue === null || $cookieValue === '') {
242 $this->clear(
243 $cookie->getDomain(),
244 $cookie->getPath(),
245 $cookie->getName()
246 );
247 }
248 }
249 }