2
0

Cookie.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Http
  17. * @subpackage Cookie
  18. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com/)
  19. * @version $Id$
  20. * @license http://framework.zend.com/license/new-bsd New BSD License
  21. */
  22. require_once 'Zend/Uri/Http.php';
  23. /**
  24. * Zend_Http_Cookie is a class describing an HTTP cookie and all it's parameters.
  25. *
  26. * Zend_Http_Cookie is a class describing an HTTP cookie and all it's parameters. The
  27. * class also enables validating whether the cookie should be sent to the server in
  28. * a specified scenario according to the request URI, the expiry time and whether
  29. * session cookies should be used or not. Generally speaking cookies should be
  30. * contained in a Cookiejar object, or instantiated manually and added to an HTTP
  31. * request.
  32. *
  33. * See http://wp.netscape.com/newsref/std/cookie_spec.html for some specs.
  34. *
  35. * @category Zend
  36. * @package Zend_Http
  37. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com/)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. */
  40. class Zend_Http_Cookie
  41. {
  42. /**
  43. * Cookie name
  44. *
  45. * @var string
  46. */
  47. protected $name;
  48. /**
  49. * Cookie value
  50. *
  51. * @var string
  52. */
  53. protected $value;
  54. /**
  55. * Cookie expiry date
  56. *
  57. * @var int
  58. */
  59. protected $expires;
  60. /**
  61. * Cookie domain
  62. *
  63. * @var string
  64. */
  65. protected $domain;
  66. /**
  67. * Cookie path
  68. *
  69. * @var string
  70. */
  71. protected $path;
  72. /**
  73. * Whether the cookie is secure or not
  74. *
  75. * @var boolean
  76. */
  77. protected $secure;
  78. /**
  79. * Cookie object constructor
  80. *
  81. * @todo Add validation of each one of the parameters (legal domain, etc.)
  82. *
  83. * @param string $name
  84. * @param string $value
  85. * @param string $domain
  86. * @param int $expires
  87. * @param string $path
  88. * @param bool $secure
  89. */
  90. public function __construct($name, $value, $domain, $expires = null, $path = null, $secure = false)
  91. {
  92. if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
  93. require_once 'Zend/Http/Exception.php';
  94. throw new Zend_Http_Exception("Cookie name cannot contain these characters: =,; \\t\\r\\n\\013\\014 ({$name})");
  95. }
  96. if (! $this->name = (string) $name) {
  97. require_once 'Zend/Http/Exception.php';
  98. throw new Zend_Http_Exception('Cookies must have a name');
  99. }
  100. if (! $this->domain = (string) $domain) {
  101. require_once 'Zend/Http/Exception.php';
  102. throw new Zend_Http_Exception('Cookies must have a domain');
  103. }
  104. $this->value = (string) $value;
  105. $this->expires = ($expires === null ? null : (int) $expires);
  106. $this->path = ($path ? $path : '/');
  107. $this->secure = $secure;
  108. }
  109. /**
  110. * Get Cookie name
  111. *
  112. * @return string
  113. */
  114. public function getName()
  115. {
  116. return $this->name;
  117. }
  118. /**
  119. * Get cookie value
  120. *
  121. * @return string
  122. */
  123. public function getValue()
  124. {
  125. return $this->value;
  126. }
  127. /**
  128. * Get cookie domain
  129. *
  130. * @return string
  131. */
  132. public function getDomain()
  133. {
  134. return $this->domain;
  135. }
  136. /**
  137. * Get the cookie path
  138. *
  139. * @return string
  140. */
  141. public function getPath()
  142. {
  143. return $this->path;
  144. }
  145. /**
  146. * Get the expiry time of the cookie, or null if no expiry time is set
  147. *
  148. * @return int|null
  149. */
  150. public function getExpiryTime()
  151. {
  152. return $this->expires;
  153. }
  154. /**
  155. * Check whether the cookie should only be sent over secure connections
  156. *
  157. * @return boolean
  158. */
  159. public function isSecure()
  160. {
  161. return $this->secure;
  162. }
  163. /**
  164. * Check whether the cookie has expired
  165. *
  166. * Always returns false if the cookie is a session cookie (has no expiry time)
  167. *
  168. * @param int $now Timestamp to consider as "now"
  169. * @return boolean
  170. */
  171. public function isExpired($now = null)
  172. {
  173. if ($now === null) $now = time();
  174. if (is_int($this->expires) && $this->expires < $now) {
  175. return true;
  176. } else {
  177. return false;
  178. }
  179. }
  180. /**
  181. * Check whether the cookie is a session cookie (has no expiry time set)
  182. *
  183. * @return boolean
  184. */
  185. public function isSessionCookie()
  186. {
  187. return ($this->expires === null);
  188. }
  189. /**
  190. * Checks whether the cookie should be sent or not in a specific scenario
  191. *
  192. * @param string|Zend_Uri_Http $uri URI to check against (secure, domain, path)
  193. * @param boolean $matchSessionCookies Whether to send session cookies
  194. * @param int $now Override the current time when checking for expiry time
  195. * @return boolean
  196. */
  197. public function match($uri, $matchSessionCookies = true, $now = null)
  198. {
  199. if (is_string ($uri)) {
  200. $uri = Zend_Uri_Http::factory($uri);
  201. }
  202. // Make sure we have a valid Zend_Uri_Http object
  203. if (! ($uri->valid() && ($uri->getScheme() == 'http' || $uri->getScheme() =='https'))) {
  204. require_once 'Zend/Http/Exception.php';
  205. throw new Zend_Http_Exception('Passed URI is not a valid HTTP or HTTPS URI');
  206. }
  207. // Check that the cookie is secure (if required) and not expired
  208. if ($this->secure && $uri->getScheme() != 'https') return false;
  209. if ($this->isExpired($now)) return false;
  210. if ($this->isSessionCookie() && ! $matchSessionCookies) return false;
  211. // Validate domain and path
  212. // Domain is validated using tail match, while path is validated using head match
  213. $domain_preg = preg_quote($this->getDomain(), "/");
  214. if (! preg_match("/{$domain_preg}$/", $uri->getHost())) return false;
  215. $path_preg = preg_quote($this->getPath(), "/");
  216. if (! preg_match("/^{$path_preg}/", $uri->getPath())) return false;
  217. // If we didn't die until now, return true.
  218. return true;
  219. }
  220. /**
  221. * Get the cookie as a string, suitable for sending as a "Cookie" header in an
  222. * HTTP request
  223. *
  224. * @return string
  225. */
  226. public function __toString()
  227. {
  228. return $this->name . '=' . urlencode($this->value) . ';';
  229. }
  230. /**
  231. * Generate a new Cookie object from a cookie string
  232. * (for example the value of the Set-Cookie HTTP header)
  233. *
  234. * @param string $cookieStr
  235. * @param Zend_Uri_Http|string $ref_uri Reference URI for default values (domain, path)
  236. * @return Zend_Http_Cookie A new Zend_Http_Cookie object or false on failure.
  237. */
  238. public static function fromString($cookieStr, $ref_uri = null)
  239. {
  240. // Set default values
  241. if (is_string($ref_uri)) {
  242. $ref_uri = Zend_Uri_Http::factory($ref_uri);
  243. }
  244. $name = '';
  245. $value = '';
  246. $domain = '';
  247. $path = '';
  248. $expires = null;
  249. $secure = false;
  250. $parts = explode(';', $cookieStr);
  251. // If first part does not include '=', fail
  252. if (strpos($parts[0], '=') === false) return false;
  253. // Get the name and value of the cookie
  254. list($name, $value) = explode('=', trim(array_shift($parts)), 2);
  255. $name = trim($name);
  256. $value = urldecode(trim($value));
  257. // Set default domain and path
  258. if ($ref_uri instanceof Zend_Uri_Http) {
  259. $domain = $ref_uri->getHost();
  260. $path = $ref_uri->getPath();
  261. $path = substr($path, 0, strrpos($path, '/'));
  262. }
  263. // Set other cookie parameters
  264. foreach ($parts as $part) {
  265. $part = trim($part);
  266. if (strtolower($part) == 'secure') {
  267. $secure = true;
  268. continue;
  269. }
  270. $keyValue = explode('=', $part, 2);
  271. if (count($keyValue) == 2) {
  272. list($k, $v) = $keyValue;
  273. switch (strtolower($k)) {
  274. case 'expires':
  275. if(($expires = strtotime($v)) === false) {
  276. /**
  277. * The expiration is past Tue, 19 Jan 2038 03:14:07 UTC
  278. * the maximum for 32-bit signed integer. Zend_Date
  279. * can get around that limit.
  280. *
  281. * @see Zend_Date
  282. */
  283. require_once 'Zend/Date.php';
  284. $expireDate = new Zend_Date($v);
  285. $expires = $expireDate->getTimestamp();
  286. }
  287. break;
  288. case 'path':
  289. $path = $v;
  290. break;
  291. case 'domain':
  292. $domain = $v;
  293. break;
  294. default:
  295. break;
  296. }
  297. }
  298. }
  299. if ($name !== '') {
  300. return new self($name, $value, $domain, $expires, $path, $secure);
  301. } else {
  302. return false;
  303. }
  304. }
  305. }