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