ILIAS  release_7 Revision v7.30-3-g800a261c036
CookieJar.php
Go to the documentation of this file.
1<?php
2
42{
43 private $_cookies;
44
53 public function __construct(array &$storageArray)
54 {
55 $this->_cookies = &$storageArray;
56 }
57
69 public function storeCookies($request_url, $response_headers)
70 {
71 $urlParts = parse_url($request_url);
72 $defaultDomain = $urlParts['host'];
73
74 $cookies = $this->parseCookieHeaders($response_headers, $defaultDomain);
75
76 // var_dump($cookies);
77 foreach ($cookies as $cookie) {
78 // Enforce the same-origin policy by verifying that the cookie
79 // would match the url that is setting it
80 if (!$this->cookieMatchesTarget($cookie, $urlParts)) {
81 continue;
82 }
83
84 // store the cookie
85 $this->storeCookie($cookie);
86
87 phpCAS::trace($cookie['name'] . ' -> ' . $cookie['value']);
88 }
89 }
90
101 public function getCookies($request_url)
102 {
103 if (!count($this->_cookies)) {
104 return array();
105 }
106
107 // If our request URL can't be parsed, no cookies apply.
108 $target = parse_url($request_url);
109 if ($target === false) {
110 return array();
111 }
112
113 $this->expireCookies();
114
115 $matching_cookies = array();
116 foreach ($this->_cookies as $key => $cookie) {
117 if ($this->cookieMatchesTarget($cookie, $target)) {
118 $matching_cookies[$cookie['name']] = $cookie['value'];
119 }
120 }
121 return $matching_cookies;
122 }
123
124
135 protected function parseCookieHeaders($header, $defaultDomain)
136 {
138 $cookies = array();
139 foreach ($header as $line) {
140 if (preg_match('/^Set-Cookie2?: /i', $line)) {
141 $cookies[] = $this->parseCookieHeader($line, $defaultDomain);
142 }
143 }
144
145 phpCAS::traceEnd($cookies);
146 return $cookies;
147 }
148
160 protected function parseCookieHeader($line, $defaultDomain)
161 {
162 if (!$defaultDomain) {
164 '$defaultDomain was not provided.'
165 );
166 }
167
168 // Set our default values
169 $cookie = array(
170 'domain' => $defaultDomain,
171 'path' => '/',
172 'secure' => false,
173 );
174
175 $line = preg_replace('/^Set-Cookie2?: /i', '', trim($line));
176
177 // trim any trailing semicolons.
178 $line = trim($line, ';');
179
180 phpCAS::trace("Cookie Line: $line");
181
182 // This implementation makes the assumption that semicolons will not
183 // be present in quoted attribute values. While attribute values that
184 // contain semicolons are allowed by RFC2965, they are hopefully rare
185 // enough to ignore for our purposes. Most browsers make the same
186 // assumption.
187 $attributeStrings = explode(';', $line);
188
189 foreach ($attributeStrings as $attributeString) {
190 // split on the first equals sign and use the rest as value
191 $attributeParts = explode('=', $attributeString, 2);
192
193 $attributeName = trim($attributeParts[0]);
194 $attributeNameLC = strtolower($attributeName);
195
196 if (isset($attributeParts[1])) {
197 $attributeValue = trim($attributeParts[1]);
198 // Values may be quoted strings.
199 if (strpos($attributeValue, '"') === 0) {
200 $attributeValue = trim($attributeValue, '"');
201 // unescape any escaped quotes:
202 $attributeValue = str_replace('\"', '"', $attributeValue);
203 }
204 } else {
205 $attributeValue = null;
206 }
207
208 switch ($attributeNameLC) {
209 case 'expires':
210 $cookie['expires'] = strtotime($attributeValue);
211 break;
212 case 'max-age':
213 $cookie['max-age'] = (int) $attributeValue;
214 // Set an expiry time based on the max-age
215 if ($cookie['max-age']) {
216 $cookie['expires'] = time() + $cookie['max-age'];
217 } else {
218 // If max-age is zero, then the cookie should be removed
219 // imediately so set an expiry before now.
220 $cookie['expires'] = time() - 1;
221 }
222 break;
223 case 'secure':
224 $cookie['secure'] = true;
225 break;
226 case 'domain':
227 case 'path':
228 case 'port':
229 case 'version':
230 case 'comment':
231 case 'commenturl':
232 case 'discard':
233 case 'httponly':
234 $cookie[$attributeNameLC] = $attributeValue;
235 break;
236 default:
237 $cookie['name'] = $attributeName;
238 $cookie['value'] = $attributeValue;
239 }
240 }
241
242 return $cookie;
243 }
244
254 protected function storeCookie($cookie)
255 {
256 // Discard any old versions of this cookie.
257 $this->discardCookie($cookie);
258 $this->_cookies[] = $cookie;
259 }
260
270 protected function discardCookie($cookie)
271 {
272 if (!isset($cookie['domain'])
273 || !isset($cookie['path'])
274 || !isset($cookie['path'])
275 ) {
276 throw new CAS_InvalidArgumentException('Invalid Cookie array passed.');
277 }
278
279 foreach ($this->_cookies as $key => $old_cookie) {
280 if ($cookie['domain'] == $old_cookie['domain']
281 && $cookie['path'] == $old_cookie['path']
282 && $cookie['name'] == $old_cookie['name']
283 ) {
284 unset($this->_cookies[$key]);
285 }
286 }
287 }
288
296 protected function expireCookies()
297 {
298 foreach ($this->_cookies as $key => $cookie) {
299 if (isset($cookie['expires']) && $cookie['expires'] < time()) {
300 unset($this->_cookies[$key]);
301 }
302 }
303 }
304
315 protected function cookieMatchesTarget($cookie, $target)
316 {
317 if (!is_array($target)) {
319 '$target must be an array of URL attributes as generated by parse_url().'
320 );
321 }
322 if (!isset($target['host'])) {
324 '$target must be an array of URL attributes as generated by parse_url().'
325 );
326 }
327
328 // Verify that the scheme matches
329 if ($cookie['secure'] && $target['scheme'] != 'https') {
330 return false;
331 }
332
333 // Verify that the host matches
334 // Match domain and mulit-host cookies
335 if (strpos($cookie['domain'], '.') === 0) {
336 // .host.domain.edu cookies are valid for host.domain.edu
337 if (substr($cookie['domain'], 1) == $target['host']) {
338 // continue with other checks
339 } else {
340 // non-exact host-name matches.
341 // check that the target host a.b.c.edu is within .b.c.edu
342 $pos = strripos($target['host'], $cookie['domain']);
343 if (!$pos) {
344 return false;
345 }
346 // verify that the cookie domain is the last part of the host.
347 if ($pos + strlen($cookie['domain']) != strlen($target['host'])) {
348 return false;
349 }
350 // verify that the host name does not contain interior dots as per
351 // RFC 2965 section 3.3.2 Rejecting Cookies
352 // http://www.ietf.org/rfc/rfc2965.txt
353 $hostname = substr($target['host'], 0, $pos);
354 if (strpos($hostname, '.') !== false) {
355 return false;
356 }
357 }
358 } else {
359 // If the cookie host doesn't begin with '.',
360 // the host must case-insensitive match exactly
361 if (strcasecmp($target['host'], $cookie['domain']) !== 0) {
362 return false;
363 }
364 }
365
366 // Verify that the port matches
367 if (isset($cookie['ports'])
368 && !in_array($target['port'], $cookie['ports'])
369 ) {
370 return false;
371 }
372
373 // Verify that the path matches
374 if (strpos($target['path'], $cookie['path']) !== 0) {
375 return false;
376 }
377
378 return true;
379 }
380}
This class provides access to service cookies and handles parsing of response headers to pull out coo...
Definition: CookieJar.php:42
parseCookieHeader($line, $defaultDomain)
Parse a single cookie header line.
Definition: CookieJar.php:160
storeCookies($request_url, $response_headers)
Store cookies for a web service request.
Definition: CookieJar.php:69
cookieMatchesTarget($cookie, $target)
Answer true if cookie is applicable to a target.
Definition: CookieJar.php:315
expireCookies()
Go through our stored cookies and remove any that are expired.
Definition: CookieJar.php:296
discardCookie($cookie)
Discard an existing cookie.
Definition: CookieJar.php:270
__construct(array &$storageArray)
Create a new cookie jar by passing it a reference to an array in which it should store cookies.
Definition: CookieJar.php:53
storeCookie($cookie)
Add, update, or remove a cookie.
Definition: CookieJar.php:254
getCookies($request_url)
Retrieve cookies applicable for a web service request.
Definition: CookieJar.php:101
parseCookieHeaders($header, $defaultDomain)
Parse Cookies without PECL From the comments in http://php.net/manual/en/function....
Definition: CookieJar.php:135
An exception for terminatinating execution or to throw for unit testing.
Exception that denotes invalid arguments were passed.
static trace($str)
This method is used to log something in debug mode.
Definition: CAS.php:599
static traceEnd($res='')
This method is used to indicate the end of the execution of a function in debug mode.
Definition: CAS.php:658
static traceBegin()
This method is used to indicate the start of the execution of a function in debug mode.
Definition: CAS.php:611