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