Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of the Symfony package.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Symfony\Component\BrowserKit;
|
Chris@0
|
13
|
Chris@0
|
14 /**
|
Chris@0
|
15 * CookieJar.
|
Chris@0
|
16 *
|
Chris@0
|
17 * @author Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
18 */
|
Chris@0
|
19 class CookieJar
|
Chris@0
|
20 {
|
Chris@17
|
21 protected $cookieJar = [];
|
Chris@0
|
22
|
Chris@0
|
23 public function set(Cookie $cookie)
|
Chris@0
|
24 {
|
Chris@0
|
25 $this->cookieJar[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
|
Chris@0
|
26 }
|
Chris@0
|
27
|
Chris@0
|
28 /**
|
Chris@0
|
29 * Gets a cookie by name.
|
Chris@0
|
30 *
|
Chris@0
|
31 * You should never use an empty domain, but if you do so,
|
Chris@0
|
32 * this method returns the first cookie for the given name/path
|
Chris@0
|
33 * (this behavior ensures a BC behavior with previous versions of
|
Chris@0
|
34 * Symfony).
|
Chris@0
|
35 *
|
Chris@0
|
36 * @param string $name The cookie name
|
Chris@0
|
37 * @param string $path The cookie path
|
Chris@0
|
38 * @param string $domain The cookie domain
|
Chris@0
|
39 *
|
Chris@0
|
40 * @return Cookie|null A Cookie instance or null if the cookie does not exist
|
Chris@0
|
41 */
|
Chris@0
|
42 public function get($name, $path = '/', $domain = null)
|
Chris@0
|
43 {
|
Chris@0
|
44 $this->flushExpiredCookies();
|
Chris@0
|
45
|
Chris@13
|
46 foreach ($this->cookieJar as $cookieDomain => $pathCookies) {
|
Chris@13
|
47 if ($cookieDomain && $domain) {
|
Chris@13
|
48 $cookieDomain = '.'.ltrim($cookieDomain, '.');
|
Chris@13
|
49 if ($cookieDomain !== substr('.'.$domain, -\strlen($cookieDomain))) {
|
Chris@13
|
50 continue;
|
Chris@0
|
51 }
|
Chris@0
|
52 }
|
Chris@0
|
53
|
Chris@13
|
54 foreach ($pathCookies as $cookiePath => $namedCookies) {
|
Chris@13
|
55 if (0 !== strpos($path, $cookiePath)) {
|
Chris@13
|
56 continue;
|
Chris@13
|
57 }
|
Chris@13
|
58 if (isset($namedCookies[$name])) {
|
Chris@13
|
59 return $namedCookies[$name];
|
Chris@13
|
60 }
|
Chris@0
|
61 }
|
Chris@0
|
62 }
|
Chris@0
|
63 }
|
Chris@0
|
64
|
Chris@0
|
65 /**
|
Chris@0
|
66 * Removes a cookie by name.
|
Chris@0
|
67 *
|
Chris@0
|
68 * You should never use an empty domain, but if you do so,
|
Chris@0
|
69 * all cookies for the given name/path expire (this behavior
|
Chris@0
|
70 * ensures a BC behavior with previous versions of Symfony).
|
Chris@0
|
71 *
|
Chris@0
|
72 * @param string $name The cookie name
|
Chris@0
|
73 * @param string $path The cookie path
|
Chris@0
|
74 * @param string $domain The cookie domain
|
Chris@0
|
75 */
|
Chris@0
|
76 public function expire($name, $path = '/', $domain = null)
|
Chris@0
|
77 {
|
Chris@0
|
78 if (null === $path) {
|
Chris@0
|
79 $path = '/';
|
Chris@0
|
80 }
|
Chris@0
|
81
|
Chris@0
|
82 if (empty($domain)) {
|
Chris@0
|
83 // an empty domain means any domain
|
Chris@0
|
84 // this should never happen but it allows for a better BC
|
Chris@0
|
85 $domains = array_keys($this->cookieJar);
|
Chris@0
|
86 } else {
|
Chris@17
|
87 $domains = [$domain];
|
Chris@0
|
88 }
|
Chris@0
|
89
|
Chris@0
|
90 foreach ($domains as $domain) {
|
Chris@0
|
91 unset($this->cookieJar[$domain][$path][$name]);
|
Chris@0
|
92
|
Chris@0
|
93 if (empty($this->cookieJar[$domain][$path])) {
|
Chris@0
|
94 unset($this->cookieJar[$domain][$path]);
|
Chris@0
|
95
|
Chris@0
|
96 if (empty($this->cookieJar[$domain])) {
|
Chris@0
|
97 unset($this->cookieJar[$domain]);
|
Chris@0
|
98 }
|
Chris@0
|
99 }
|
Chris@0
|
100 }
|
Chris@0
|
101 }
|
Chris@0
|
102
|
Chris@0
|
103 /**
|
Chris@0
|
104 * Removes all the cookies from the jar.
|
Chris@0
|
105 */
|
Chris@0
|
106 public function clear()
|
Chris@0
|
107 {
|
Chris@17
|
108 $this->cookieJar = [];
|
Chris@0
|
109 }
|
Chris@0
|
110
|
Chris@0
|
111 /**
|
Chris@0
|
112 * Updates the cookie jar from a response Set-Cookie headers.
|
Chris@0
|
113 *
|
Chris@0
|
114 * @param array $setCookies Set-Cookie headers from an HTTP response
|
Chris@0
|
115 * @param string $uri The base URL
|
Chris@0
|
116 */
|
Chris@0
|
117 public function updateFromSetCookie(array $setCookies, $uri = null)
|
Chris@0
|
118 {
|
Chris@17
|
119 $cookies = [];
|
Chris@0
|
120
|
Chris@0
|
121 foreach ($setCookies as $cookie) {
|
Chris@0
|
122 foreach (explode(',', $cookie) as $i => $part) {
|
Chris@0
|
123 if (0 === $i || preg_match('/^(?P<token>\s*[0-9A-Za-z!#\$%\&\'\*\+\-\.^_`\|~]+)=/', $part)) {
|
Chris@0
|
124 $cookies[] = ltrim($part);
|
Chris@0
|
125 } else {
|
Chris@17
|
126 $cookies[\count($cookies) - 1] .= ','.$part;
|
Chris@0
|
127 }
|
Chris@0
|
128 }
|
Chris@0
|
129 }
|
Chris@0
|
130
|
Chris@0
|
131 foreach ($cookies as $cookie) {
|
Chris@0
|
132 try {
|
Chris@0
|
133 $this->set(Cookie::fromString($cookie, $uri));
|
Chris@0
|
134 } catch (\InvalidArgumentException $e) {
|
Chris@0
|
135 // invalid cookies are just ignored
|
Chris@0
|
136 }
|
Chris@0
|
137 }
|
Chris@0
|
138 }
|
Chris@0
|
139
|
Chris@0
|
140 /**
|
Chris@0
|
141 * Updates the cookie jar from a Response object.
|
Chris@0
|
142 *
|
Chris@0
|
143 * @param Response $response A Response object
|
Chris@0
|
144 * @param string $uri The base URL
|
Chris@0
|
145 */
|
Chris@0
|
146 public function updateFromResponse(Response $response, $uri = null)
|
Chris@0
|
147 {
|
Chris@0
|
148 $this->updateFromSetCookie($response->getHeader('Set-Cookie', false), $uri);
|
Chris@0
|
149 }
|
Chris@0
|
150
|
Chris@0
|
151 /**
|
Chris@0
|
152 * Returns not yet expired cookies.
|
Chris@0
|
153 *
|
Chris@0
|
154 * @return Cookie[] An array of cookies
|
Chris@0
|
155 */
|
Chris@0
|
156 public function all()
|
Chris@0
|
157 {
|
Chris@0
|
158 $this->flushExpiredCookies();
|
Chris@0
|
159
|
Chris@17
|
160 $flattenedCookies = [];
|
Chris@0
|
161 foreach ($this->cookieJar as $path) {
|
Chris@0
|
162 foreach ($path as $cookies) {
|
Chris@0
|
163 foreach ($cookies as $cookie) {
|
Chris@0
|
164 $flattenedCookies[] = $cookie;
|
Chris@0
|
165 }
|
Chris@0
|
166 }
|
Chris@0
|
167 }
|
Chris@0
|
168
|
Chris@0
|
169 return $flattenedCookies;
|
Chris@0
|
170 }
|
Chris@0
|
171
|
Chris@0
|
172 /**
|
Chris@0
|
173 * Returns not yet expired cookie values for the given URI.
|
Chris@0
|
174 *
|
Chris@0
|
175 * @param string $uri A URI
|
Chris@0
|
176 * @param bool $returnsRawValue Returns raw value or urldecoded value
|
Chris@0
|
177 *
|
Chris@0
|
178 * @return array An array of cookie values
|
Chris@0
|
179 */
|
Chris@0
|
180 public function allValues($uri, $returnsRawValue = false)
|
Chris@0
|
181 {
|
Chris@0
|
182 $this->flushExpiredCookies();
|
Chris@0
|
183
|
Chris@17
|
184 $parts = array_replace(['path' => '/'], parse_url($uri));
|
Chris@17
|
185 $cookies = [];
|
Chris@0
|
186 foreach ($this->cookieJar as $domain => $pathCookies) {
|
Chris@0
|
187 if ($domain) {
|
Chris@0
|
188 $domain = '.'.ltrim($domain, '.');
|
Chris@17
|
189 if ($domain != substr('.'.$parts['host'], -\strlen($domain))) {
|
Chris@0
|
190 continue;
|
Chris@0
|
191 }
|
Chris@0
|
192 }
|
Chris@0
|
193
|
Chris@0
|
194 foreach ($pathCookies as $path => $namedCookies) {
|
Chris@17
|
195 if ($path != substr($parts['path'], 0, \strlen($path))) {
|
Chris@0
|
196 continue;
|
Chris@0
|
197 }
|
Chris@0
|
198
|
Chris@0
|
199 foreach ($namedCookies as $cookie) {
|
Chris@0
|
200 if ($cookie->isSecure() && 'https' != $parts['scheme']) {
|
Chris@0
|
201 continue;
|
Chris@0
|
202 }
|
Chris@0
|
203
|
Chris@0
|
204 $cookies[$cookie->getName()] = $returnsRawValue ? $cookie->getRawValue() : $cookie->getValue();
|
Chris@0
|
205 }
|
Chris@0
|
206 }
|
Chris@0
|
207 }
|
Chris@0
|
208
|
Chris@0
|
209 return $cookies;
|
Chris@0
|
210 }
|
Chris@0
|
211
|
Chris@0
|
212 /**
|
Chris@0
|
213 * Returns not yet expired raw cookie values for the given URI.
|
Chris@0
|
214 *
|
Chris@0
|
215 * @param string $uri A URI
|
Chris@0
|
216 *
|
Chris@0
|
217 * @return array An array of cookie values
|
Chris@0
|
218 */
|
Chris@0
|
219 public function allRawValues($uri)
|
Chris@0
|
220 {
|
Chris@0
|
221 return $this->allValues($uri, true);
|
Chris@0
|
222 }
|
Chris@0
|
223
|
Chris@0
|
224 /**
|
Chris@0
|
225 * Removes all expired cookies.
|
Chris@0
|
226 */
|
Chris@0
|
227 public function flushExpiredCookies()
|
Chris@0
|
228 {
|
Chris@0
|
229 foreach ($this->cookieJar as $domain => $pathCookies) {
|
Chris@0
|
230 foreach ($pathCookies as $path => $namedCookies) {
|
Chris@0
|
231 foreach ($namedCookies as $name => $cookie) {
|
Chris@0
|
232 if ($cookie->isExpired()) {
|
Chris@0
|
233 unset($this->cookieJar[$domain][$path][$name]);
|
Chris@0
|
234 }
|
Chris@0
|
235 }
|
Chris@0
|
236 }
|
Chris@0
|
237 }
|
Chris@0
|
238 }
|
Chris@0
|
239 }
|