File indexing completed on 2025-01-19 05:21:14
0001 <?php 0002 0003 /** 0004 * Zend Framework 0005 * 0006 * LICENSE 0007 * 0008 * This source file is subject to the new BSD license that is bundled 0009 * with this package in the file LICENSE.txt. 0010 * It is also available through the world-wide-web at this URL: 0011 * http://framework.zend.com/license/new-bsd 0012 * If you did not receive a copy of the license and are unable to 0013 * obtain it through the world-wide-web, please send an email 0014 * to license@zend.com so we can send you a copy immediately. 0015 * 0016 * @category Zend 0017 * @package Zend_Http 0018 * @subpackage Cookie 0019 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0020 * @version $Id$ 0021 * @license http://framework.zend.com/license/new-bsd New BSD License 0022 */ 0023 0024 /** 0025 * @see Zend_Uri_Http 0026 */ 0027 // require_once 'Zend/Uri/Http.php'; 0028 0029 0030 /** 0031 * Zend_Http_Cookie is a class describing an HTTP cookie and all it's parameters. 0032 * 0033 * Zend_Http_Cookie is a class describing an HTTP cookie and all it's parameters. The 0034 * class also enables validating whether the cookie should be sent to the server in 0035 * a specified scenario according to the request URI, the expiry time and whether 0036 * session cookies should be used or not. Generally speaking cookies should be 0037 * contained in a Cookiejar object, or instantiated manually and added to an HTTP 0038 * request. 0039 * 0040 * See http://wp.netscape.com/newsref/std/cookie_spec.html for some specs. 0041 * 0042 * @category Zend 0043 * @package Zend_Http 0044 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0045 * @license http://framework.zend.com/license/new-bsd New BSD License 0046 */ 0047 class Zend_Http_Cookie 0048 { 0049 /** 0050 * Cookie name 0051 * 0052 * @var string 0053 */ 0054 protected $name; 0055 0056 /** 0057 * Cookie value 0058 * 0059 * @var string 0060 */ 0061 protected $value; 0062 0063 /** 0064 * Cookie expiry date 0065 * 0066 * @var int 0067 */ 0068 protected $expires; 0069 0070 /** 0071 * Cookie domain 0072 * 0073 * @var string 0074 */ 0075 protected $domain; 0076 0077 /** 0078 * Cookie path 0079 * 0080 * @var string 0081 */ 0082 protected $path; 0083 0084 /** 0085 * Whether the cookie is secure or not 0086 * 0087 * @var boolean 0088 */ 0089 protected $secure; 0090 0091 /** 0092 * Whether the cookie value has been encoded/decoded 0093 * 0094 * @var boolean 0095 */ 0096 protected $encodeValue; 0097 0098 /** 0099 * Cookie object constructor 0100 * 0101 * @todo Add validation of each one of the parameters (legal domain, etc.) 0102 * 0103 * @param string $name 0104 * @param string $value 0105 * @param string $domain 0106 * @param int $expires 0107 * @param string $path 0108 * @param bool $secure 0109 */ 0110 public function __construct($name, $value, $domain, $expires = null, $path = null, $secure = false) 0111 { 0112 if (preg_match("/[=,; \t\r\n\013\014]/", $name)) { 0113 // require_once 'Zend/Http/Exception.php'; 0114 throw new Zend_Http_Exception("Cookie name cannot contain these characters: =,; \\t\\r\\n\\013\\014 ({$name})"); 0115 } 0116 0117 if (! $this->name = (string) $name) { 0118 // require_once 'Zend/Http/Exception.php'; 0119 throw new Zend_Http_Exception('Cookies must have a name'); 0120 } 0121 0122 if (! $this->domain = (string) $domain) { 0123 // require_once 'Zend/Http/Exception.php'; 0124 throw new Zend_Http_Exception('Cookies must have a domain'); 0125 } 0126 0127 $this->value = (string) $value; 0128 $this->expires = ($expires === null ? null : (int) $expires); 0129 $this->path = ($path ? $path : '/'); 0130 $this->secure = $secure; 0131 } 0132 0133 /** 0134 * Get Cookie name 0135 * 0136 * @return string 0137 */ 0138 public function getName() 0139 { 0140 return $this->name; 0141 } 0142 0143 /** 0144 * Get cookie value 0145 * 0146 * @return string 0147 */ 0148 public function getValue() 0149 { 0150 return $this->value; 0151 } 0152 0153 /** 0154 * Get cookie domain 0155 * 0156 * @return string 0157 */ 0158 public function getDomain() 0159 { 0160 return $this->domain; 0161 } 0162 0163 /** 0164 * Get the cookie path 0165 * 0166 * @return string 0167 */ 0168 public function getPath() 0169 { 0170 return $this->path; 0171 } 0172 0173 /** 0174 * Get the expiry time of the cookie, or null if no expiry time is set 0175 * 0176 * @return int|null 0177 */ 0178 public function getExpiryTime() 0179 { 0180 return $this->expires; 0181 } 0182 0183 /** 0184 * Check whether the cookie should only be sent over secure connections 0185 * 0186 * @return boolean 0187 */ 0188 public function isSecure() 0189 { 0190 return $this->secure; 0191 } 0192 0193 /** 0194 * Check whether the cookie has expired 0195 * 0196 * Always returns false if the cookie is a session cookie (has no expiry time) 0197 * 0198 * @param int $now Timestamp to consider as "now" 0199 * @return boolean 0200 */ 0201 public function isExpired($now = null) 0202 { 0203 if ($now === null) $now = time(); 0204 if (is_int($this->expires) && $this->expires < $now) { 0205 return true; 0206 } else { 0207 return false; 0208 } 0209 } 0210 0211 /** 0212 * Check whether the cookie is a session cookie (has no expiry time set) 0213 * 0214 * @return boolean 0215 */ 0216 public function isSessionCookie() 0217 { 0218 return ($this->expires === null); 0219 } 0220 0221 /** 0222 * Checks whether the cookie should be sent or not in a specific scenario 0223 * 0224 * @param string|Zend_Uri_Http $uri URI to check against (secure, domain, path) 0225 * @param boolean $matchSessionCookies Whether to send session cookies 0226 * @param int $now Override the current time when checking for expiry time 0227 * @return boolean 0228 */ 0229 public function match($uri, $matchSessionCookies = true, $now = null) 0230 { 0231 if (is_string ($uri)) { 0232 $uri = Zend_Uri_Http::factory($uri); 0233 } 0234 0235 // Make sure we have a valid Zend_Uri_Http object 0236 if (! ($uri->valid() && ($uri->getScheme() == 'http' || $uri->getScheme() =='https'))) { 0237 // require_once 'Zend/Http/Exception.php'; 0238 throw new Zend_Http_Exception('Passed URI is not a valid HTTP or HTTPS URI'); 0239 } 0240 0241 // Check that the cookie is secure (if required) and not expired 0242 if ($this->secure && $uri->getScheme() != 'https') return false; 0243 if ($this->isExpired($now)) return false; 0244 if ($this->isSessionCookie() && ! $matchSessionCookies) return false; 0245 0246 // Check if the domain matches 0247 if (! self::matchCookieDomain($this->getDomain(), $uri->getHost())) { 0248 return false; 0249 } 0250 0251 // Check that path matches using prefix match 0252 if (! self::matchCookiePath($this->getPath(), $uri->getPath())) { 0253 return false; 0254 } 0255 0256 // If we didn't die until now, return true. 0257 return true; 0258 } 0259 0260 /** 0261 * Get the cookie as a string, suitable for sending as a "Cookie" header in an 0262 * HTTP request 0263 * 0264 * @return string 0265 */ 0266 public function __toString() 0267 { 0268 if ($this->encodeValue) { 0269 return $this->name . '=' . urlencode($this->value) . ';'; 0270 } 0271 return $this->name . '=' . $this->value . ';'; 0272 } 0273 0274 /** 0275 * Generate a new Cookie object from a cookie string 0276 * (for example the value of the Set-Cookie HTTP header) 0277 * 0278 * @param string $cookieStr 0279 * @param Zend_Uri_Http|string $refUri Reference URI for default values (domain, path) 0280 * @param boolean $encodeValue Whether or not the cookie's value should be 0281 * passed through urlencode/urldecode 0282 * @return Zend_Http_Cookie A new Zend_Http_Cookie object or false on failure. 0283 */ 0284 public static function fromString($cookieStr, $refUri = null, $encodeValue = true) 0285 { 0286 // Set default values 0287 if (is_string($refUri)) { 0288 $refUri = Zend_Uri_Http::factory($refUri); 0289 } 0290 0291 $name = ''; 0292 $value = ''; 0293 $domain = ''; 0294 $path = ''; 0295 $expires = null; 0296 $secure = false; 0297 $parts = explode(';', $cookieStr); 0298 0299 // If first part does not include '=', fail 0300 if (strpos($parts[0], '=') === false) return false; 0301 0302 // Get the name and value of the cookie 0303 list($name, $value) = explode('=', trim(array_shift($parts)), 2); 0304 $name = trim($name); 0305 if ($encodeValue) { 0306 $value = urldecode(trim($value)); 0307 } 0308 0309 // Set default domain and path 0310 if ($refUri instanceof Zend_Uri_Http) { 0311 $domain = $refUri->getHost(); 0312 $path = $refUri->getPath(); 0313 $path = substr($path, 0, strrpos($path, '/')); 0314 } 0315 0316 // Set other cookie parameters 0317 foreach ($parts as $part) { 0318 $part = trim($part); 0319 if (strtolower($part) == 'secure') { 0320 $secure = true; 0321 continue; 0322 } 0323 0324 $keyValue = explode('=', $part, 2); 0325 if (count($keyValue) == 2) { 0326 list($k, $v) = $keyValue; 0327 switch (strtolower($k)) { 0328 case 'expires': 0329 if(($expires = strtotime($v)) === false) { 0330 /** 0331 * The expiration is past Tue, 19 Jan 2038 03:14:07 UTC 0332 * the maximum for 32-bit signed integer. Zend_Date 0333 * can get around that limit. 0334 * 0335 * @see Zend_Date 0336 */ 0337 // require_once 'Zend/Date.php'; 0338 0339 $expireDate = new Zend_Date($v); 0340 $expires = $expireDate->getTimestamp(); 0341 } 0342 break; 0343 0344 case 'path': 0345 $path = $v; 0346 break; 0347 0348 case 'domain': 0349 $domain = $v; 0350 break; 0351 0352 default: 0353 break; 0354 } 0355 } 0356 } 0357 0358 if ($name !== '') { 0359 $ret = new self($name, $value, $domain, $expires, $path, $secure); 0360 $ret->encodeValue = ($encodeValue) ? true : false; 0361 return $ret; 0362 } else { 0363 return false; 0364 } 0365 } 0366 0367 /** 0368 * Check if a cookie's domain matches a host name. 0369 * 0370 * Used by Zend_Http_Cookie and Zend_Http_CookieJar for cookie matching 0371 * 0372 * @param string $cookieDomain 0373 * @param string $host 0374 * 0375 * @return boolean 0376 */ 0377 public static function matchCookieDomain($cookieDomain, $host) 0378 { 0379 if (! $cookieDomain) { 0380 // require_once 'Zend/Http/Exception.php'; 0381 throw new Zend_Http_Exception("\$cookieDomain is expected to be a cookie domain"); 0382 } 0383 0384 if (! $host) { 0385 // require_once 'Zend/Http/Exception.php'; 0386 throw new Zend_Http_Exception("\$host is expected to be a host name"); 0387 } 0388 0389 $cookieDomain = strtolower($cookieDomain); 0390 $host = strtolower($host); 0391 0392 if ($cookieDomain[0] == '.') { 0393 $cookieDomain = substr($cookieDomain, 1); 0394 } 0395 0396 // Check for either exact match or suffix match 0397 return ($cookieDomain == $host || 0398 preg_match('/\.' . preg_quote($cookieDomain) . '$/', $host)); 0399 } 0400 0401 /** 0402 * Check if a cookie's path matches a URL path 0403 * 0404 * Used by Zend_Http_Cookie and Zend_Http_CookieJar for cookie matching 0405 * 0406 * @param string $cookiePath 0407 * @param string $path 0408 * @return boolean 0409 */ 0410 public static function matchCookiePath($cookiePath, $path) 0411 { 0412 if (! $cookiePath) { 0413 // require_once 'Zend/Http/Exception.php'; 0414 throw new Zend_Http_Exception("\$cookiePath is expected to be a cookie path"); 0415 } 0416 0417 if (! $path) { 0418 // require_once 'Zend/Http/Exception.php'; 0419 throw new Zend_Http_Exception("\$path is expected to be a host name"); 0420 } 0421 0422 return (strpos($path, $cookiePath) === 0); 0423 } 0424 }