ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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 }
parseCookieHeader($line, $defaultDomain)
Parse a single cookie header line.
Definition: CookieJar.php:160
cookieMatchesTarget($cookie, $target)
Answer true if cookie is applicable to a target.
Definition: CookieJar.php:315
static traceEnd($res='')
This method is used to indicate the end of the execution of a function in debug mode.
Definition: CAS.php:658
__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
static trace($str)
This method is used to log something in debug mode.
Definition: CAS.php:599
parseCookieHeaders($header, $defaultDomain)
Parse Cookies without PECL From the comments in http://php.net/manual/en/function.http-parse-cookie.php.
Definition: CookieJar.php:135
Exception that denotes invalid arguments were passed.
storeCookie($cookie)
Add, update, or remove a cookie.
Definition: CookieJar.php:254
expireCookies()
Go through our stored cookies and remove any that are expired.
Definition: CookieJar.php:296
getCookies($request_url)
Retrieve cookies applicable for a web service request.
Definition: CookieJar.php:101
storeCookies($request_url, $response_headers)
Store cookies for a web service request.
Definition: CookieJar.php:69
static traceBegin()
This method is used to indicate the start of the execution of a function in debug mode...
Definition: CAS.php:611
$target
Definition: test.php:19
$key
Definition: croninfo.php:18
discardCookie($cookie)
Discard an existing cookie.
Definition: CookieJar.php:270
This class provides access to service cookies and handles parsing of response headers to pull out coo...
Definition: CookieJar.php:41