File indexing completed on 2024-05-12 06:02:41

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 }