Requests_Cookie

Cookie storage object.

Defined (1)

The class is defined in the following location(s).

/wp-includes/Requests/Cookie.php  
  1. class Requests_Cookie { 
  2. /** 
  3. * Cookie name. 
  4. * @var string 
  5. */ 
  6. public $name; 
  7.  
  8. /** 
  9. * Cookie value. 
  10. * @var string 
  11. */ 
  12. public $value; 
  13.  
  14. /** 
  15. * Cookie attributes 
  16. * Valid keys are (currently) path, domain, expires, max-age, secure and 
  17. * httponly. 
  18. * @var Requests_Utility_CaseInsensitiveDictionary|array Array-like object 
  19. */ 
  20. public $attributes = array(); 
  21.  
  22. /** 
  23. * Cookie flags 
  24. * Valid keys are (currently) creation, last-access, persistent and 
  25. * host-only. 
  26. * @var array 
  27. */ 
  28. public $flags = array(); 
  29.  
  30. /** 
  31. * Reference time for relative calculations 
  32. * This is used in place of `time()` when calculating Max-Age expiration and 
  33. * checking time validity. 
  34. * @var int 
  35. */ 
  36. public $reference_time = 0; 
  37.  
  38. /** 
  39. * Create a new cookie object 
  40. * @param string $name 
  41. * @param string $value 
  42. * @param array|Requests_Utility_CaseInsensitiveDictionary $attributes Associative array of attribute data 
  43. */ 
  44. public function __construct($name, $value, $attributes = array(), $flags = array(), $reference_time = null) { 
  45. $this->name = $name; 
  46. $this->value = $value; 
  47. $this->attributes = $attributes; 
  48. $default_flags = array( 
  49. 'creation' => time(),  
  50. 'last-access' => time(),  
  51. 'persistent' => false,  
  52. 'host-only' => true,  
  53. ); 
  54. $this->flags = array_merge($default_flags, $flags); 
  55.  
  56. $this->reference_time = time(); 
  57. if ($reference_time !== null) { 
  58. $this->reference_time = $reference_time; 
  59.  
  60. $this->normalize(); 
  61.  
  62. /** 
  63. * Check if a cookie is expired. 
  64. * Checks the age against $this->reference_time to determine if the cookie 
  65. * is expired. 
  66. * @return boolean True if expired, false if time is valid. 
  67. */ 
  68. public function is_expired() { 
  69. // RFC6265, s. 4.1.2.2: 
  70. // If a cookie has both the Max-Age and the Expires attribute, the Max- 
  71. // Age attribute has precedence and controls the expiration date of the 
  72. // cookie. 
  73. if (isset($this->attributes['max-age'])) { 
  74. $max_age = $this->attributes['max-age']; 
  75. return $max_age < $this->reference_time; 
  76.  
  77. if (isset($this->attributes['expires'])) { 
  78. $expires = $this->attributes['expires']; 
  79. return $expires < $this->reference_time; 
  80.  
  81. return false; 
  82.  
  83. /** 
  84. * Check if a cookie is valid for a given URI 
  85. * @param Requests_IRI $uri URI to check 
  86. * @return boolean Whether the cookie is valid for the given URI 
  87. */ 
  88. public function uri_matches(Requests_IRI $uri) { 
  89. if (!$this->domain_matches($uri->host)) { 
  90. return false; 
  91.  
  92. if (!$this->path_matches($uri->path)) { 
  93. return false; 
  94.  
  95. return empty($this->attributes['secure']) || $uri->scheme === 'https'; 
  96.  
  97. /** 
  98. * Check if a cookie is valid for a given domain 
  99. * @param string $string Domain to check 
  100. * @return boolean Whether the cookie is valid for the given domain 
  101. */ 
  102. public function domain_matches($string) { 
  103. if (!isset($this->attributes['domain'])) { 
  104. // Cookies created manually; cookies created by Requests will set 
  105. // the domain to the requested domain 
  106. return true; 
  107.  
  108. $domain_string = $this->attributes['domain']; 
  109. if ($domain_string === $string) { 
  110. // The domain string and the string are identical. 
  111. return true; 
  112.  
  113. // If the cookie is marked as host-only and we don't have an exact 
  114. // match, reject the cookie 
  115. if ($this->flags['host-only'] === true) { 
  116. return false; 
  117.  
  118. if (strlen($string) <= strlen($domain_string)) { 
  119. // For obvious reasons, the string cannot be a suffix if the domain 
  120. // is shorter than the domain string 
  121. return false; 
  122.  
  123. if (substr($string, -1 * strlen($domain_string)) !== $domain_string) { 
  124. // The domain string should be a suffix of the string. 
  125. return false; 
  126.  
  127. $prefix = substr($string, 0, strlen($string) - strlen($domain_string)); 
  128. if (substr($prefix, -1) !== '.') { 
  129. // The last character of the string that is not included in the 
  130. // domain string should be a %x2E (".") character. 
  131. return false; 
  132.  
  133. // The string should be a host name (i.e., not an IP address). 
  134. return !preg_match('#^(.+\.)\d{1, 3}\.\d{1, 3}\.\d{1, 3}\.\d{1, 3}$#', $string); 
  135.  
  136. /** 
  137. * Check if a cookie is valid for a given path 
  138. * From the path-match check in RFC 6265 section 5.1.4 
  139. * @param string $request_path Path to check 
  140. * @return boolean Whether the cookie is valid for the given path 
  141. */ 
  142. public function path_matches($request_path) { 
  143. if (empty($request_path)) { 
  144. // Normalize empty path to root 
  145. $request_path = '/'; 
  146.  
  147. if (!isset($this->attributes['path'])) { 
  148. // Cookies created manually; cookies created by Requests will set 
  149. // the path to the requested path 
  150. return true; 
  151.  
  152. $cookie_path = $this->attributes['path']; 
  153.  
  154. if ($cookie_path === $request_path) { 
  155. // The cookie-path and the request-path are identical. 
  156. return true; 
  157.  
  158. if (strlen($request_path) > strlen($cookie_path) && substr($request_path, 0, strlen($cookie_path)) === $cookie_path) { 
  159. if (substr($cookie_path, -1) === '/') { 
  160. // The cookie-path is a prefix of the request-path, and the last 
  161. // character of the cookie-path is %x2F ("/"). 
  162. return true; 
  163.  
  164. if (substr($request_path, strlen($cookie_path), 1) === '/') { 
  165. // The cookie-path is a prefix of the request-path, and the 
  166. // first character of the request-path that is not included in 
  167. // the cookie-path is a %x2F ("/") character. 
  168. return true; 
  169.  
  170. return false; 
  171.  
  172. /** 
  173. * Normalize cookie and attributes 
  174. * @return boolean Whether the cookie was successfully normalized 
  175. */ 
  176. public function normalize() { 
  177. foreach ($this->attributes as $key => $value) { 
  178. $orig_value = $value; 
  179. $value = $this->normalize_attribute($key, $value); 
  180. if ($value === null) { 
  181. unset($this->attributes[$key]); 
  182. continue; 
  183.  
  184. if ($value !== $orig_value) { 
  185. $this->attributes[$key] = $value; 
  186.  
  187. return true; 
  188.  
  189. /** 
  190. * Parse an individual cookie attribute 
  191. * Handles parsing individual attributes from the cookie values. 
  192. * @param string $name Attribute name 
  193. * @param string|boolean $value Attribute value (string value, or true if empty/flag) 
  194. * @return mixed Value if available, or null if the attribute value is invalid (and should be skipped) 
  195. */ 
  196. protected function normalize_attribute($name, $value) { 
  197. switch (strtolower($name)) { 
  198. case 'expires': 
  199. // Expiration parsing, as per RFC 6265 section 5.2.1 
  200. if (is_int($value)) { 
  201. return $value; 
  202.  
  203. $expiry_time = strtotime($value); 
  204. if ($expiry_time === false) { 
  205. return null; 
  206.  
  207. return $expiry_time; 
  208.  
  209. case 'max-age': 
  210. // Expiration parsing, as per RFC 6265 section 5.2.2 
  211. if (is_int($value)) { 
  212. return $value; 
  213.  
  214. // Check that we have a valid age 
  215. if (!preg_match('/^-?\d+$/', $value)) { 
  216. return null; 
  217.  
  218. $delta_seconds = (int) $value; 
  219. if ($delta_seconds <= 0) { 
  220. $expiry_time = 0; 
  221. else { 
  222. $expiry_time = $this->reference_time + $delta_seconds; 
  223.  
  224. return $expiry_time; 
  225.  
  226. case 'domain': 
  227. // Domain normalization, as per RFC 6265 section 5.2.3 
  228. if ($value[0] === '.') { 
  229. $value = substr($value, 1); 
  230.  
  231. return $value; 
  232.  
  233. default: 
  234. return $value; 
  235.  
  236. /** 
  237. * Format a cookie for a Cookie header 
  238. * This is used when sending cookies to a server. 
  239. * @return string Cookie formatted for Cookie header 
  240. */ 
  241. public function format_for_header() { 
  242. return sprintf('%s=%s', $this->name, $this->value); 
  243.  
  244. /** 
  245. * Format a cookie for a Cookie header 
  246. * @codeCoverageIgnore 
  247. * @deprecated Use {@see Requests_Cookie::format_for_header} 
  248. * @return string 
  249. */ 
  250. public function formatForHeader() { 
  251. return $this->format_for_header(); 
  252.  
  253. /** 
  254. * Format a cookie for a Set-Cookie header 
  255. * This is used when sending cookies to clients. This isn't really 
  256. * applicable to client-side usage, but might be handy for debugging. 
  257. * @return string Cookie formatted for Set-Cookie header 
  258. */ 
  259. public function format_for_set_cookie() { 
  260. $header_value = $this->format_for_header(); 
  261. if (!empty($this->attributes)) { 
  262. $parts = array(); 
  263. foreach ($this->attributes as $key => $value) { 
  264. // Ignore non-associative attributes 
  265. if (is_numeric($key)) { 
  266. $parts[] = $value; 
  267. else { 
  268. $parts[] = sprintf('%s=%s', $key, $value); 
  269.  
  270. $header_value .= '; ' . implode('; ', $parts); 
  271. return $header_value; 
  272.  
  273. /** 
  274. * Format a cookie for a Set-Cookie header 
  275. * @codeCoverageIgnore 
  276. * @deprecated Use {@see Requests_Cookie::format_for_set_cookie} 
  277. * @return string 
  278. */ 
  279. public function formatForSetCookie() { 
  280. return $this->format_for_set_cookie(); 
  281.  
  282. /** 
  283. * Get the cookie value 
  284. * Attributes and other data can be accessed via methods. 
  285. */ 
  286. public function __toString() { 
  287. return $this->value; 
  288.  
  289. /** 
  290. * Parse a cookie string into a cookie object 
  291. * Based on Mozilla's parsing code in Firefox and related projects, which 
  292. * is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265 
  293. * specifies some of this handling, but not in a thorough manner. 
  294. * @param string Cookie header value (from a Set-Cookie header) 
  295. * @return Requests_Cookie Parsed cookie object 
  296. */ 
  297. public static function parse($string, $name = '', $reference_time = null) { 
  298. $parts = explode(';', $string); 
  299. $kvparts = array_shift($parts); 
  300.  
  301. if (!empty($name)) { 
  302. $value = $string; 
  303. elseif (strpos($kvparts, '=') === false) { 
  304. // Some sites might only have a value without the equals separator. 
  305. // Deviate from RFC 6265 and pretend it was actually a blank name 
  306. // (`=foo`) 
  307. // 
  308. // https://bugzilla.mozilla.org/show_bug.cgi?id=169091 
  309. $name = ''; 
  310. $value = $kvparts; 
  311. else { 
  312. list($name, $value) = explode('=', $kvparts, 2); 
  313. $name = trim($name); 
  314. $value = trim($value); 
  315.  
  316. // Attribute key are handled case-insensitively 
  317. $attributes = new Requests_Utility_CaseInsensitiveDictionary(); 
  318.  
  319. if (!empty($parts)) { 
  320. foreach ($parts as $part) { 
  321. if (strpos($part, '=') === false) { 
  322. $part_key = $part; 
  323. $part_value = true; 
  324. else { 
  325. list($part_key, $part_value) = explode('=', $part, 2); 
  326. $part_value = trim($part_value); 
  327.  
  328. $part_key = trim($part_key); 
  329. $attributes[$part_key] = $part_value; 
  330.  
  331. return new Requests_Cookie($name, $value, $attributes, array(), $reference_time); 
  332.  
  333. /** 
  334. * Parse all Set-Cookie headers from request headers 
  335. * @param Requests_Response_Headers $headers Headers to parse from 
  336. * @param Requests_IRI|null $origin URI for comparing cookie origins 
  337. * @param int|null $time Reference time for expiration calculation 
  338. * @return array 
  339. */ 
  340. public static function parse_from_headers(Requests_Response_Headers $headers, Requests_IRI $origin = null, $time = null) { 
  341. $cookie_headers = $headers->getValues('Set-Cookie'); 
  342. if (empty($cookie_headers)) { 
  343. return array(); 
  344.  
  345. $cookies = array(); 
  346. foreach ($cookie_headers as $header) { 
  347. $parsed = self::parse($header, '', $time); 
  348.  
  349. // Default domain/path attributes 
  350. if (empty($parsed->attributes['domain']) && !empty($origin)) { 
  351. $parsed->attributes['domain'] = $origin->host; 
  352. $parsed->flags['host-only'] = true; 
  353. else { 
  354. $parsed->flags['host-only'] = false; 
  355.  
  356. $path_is_valid = (!empty($parsed->attributes['path']) && $parsed->attributes['path'][0] === '/'); 
  357. if (!$path_is_valid && !empty($origin)) { 
  358. $path = $origin->path; 
  359.  
  360. // Default path normalization as per RFC 6265 section 5.1.4 
  361. if (substr($path, 0, 1) !== '/') { 
  362. // If the uri-path is empty or if the first character of 
  363. // the uri-path is not a %x2F ("/") character, output 
  364. // %x2F ("/") and skip the remaining steps. 
  365. $path = '/'; 
  366. elseif (substr_count($path, '/') === 1) { 
  367. // If the uri-path contains no more than one %x2F ("/") 
  368. // character, output %x2F ("/") and skip the remaining 
  369. // step. 
  370. $path = '/'; 
  371. else { 
  372. // Output the characters of the uri-path from the first 
  373. // character up to, but not including, the right-most 
  374. // %x2F ("/"). 
  375. $path = substr($path, 0, strrpos($path, '/')); 
  376. $parsed->attributes['path'] = $path; 
  377.  
  378. // Reject invalid cookie domains 
  379. if (!empty($origin) && !$parsed->domain_matches($origin->host)) { 
  380. continue; 
  381.  
  382. $cookies[$parsed->name] = $parsed; 
  383.  
  384. return $cookies; 
  385.  
  386. /** 
  387. * Parse all Set-Cookie headers from request headers 
  388. * @codeCoverageIgnore 
  389. * @deprecated Use {@see Requests_Cookie::parse_from_headers} 
  390. * @return string 
  391. */ 
  392. public static function parseFromHeaders(Requests_Response_Headers $headers) { 
  393. return self::parse_from_headers($headers);