web/lib/Zend/Http/Cookie.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * Zend Framework
       
     5  *
       
     6  * LICENSE
       
     7  *
       
     8  * This source file is subject to the new BSD license that is bundled
       
     9  * with this package in the file LICENSE.txt.
       
    10  * It is also available through the world-wide-web at this URL:
       
    11  * http://framework.zend.com/license/new-bsd
       
    12  * If you did not receive a copy of the license and are unable to
       
    13  * obtain it through the world-wide-web, please send an email
       
    14  * to license@zend.com so we can send you a copy immediately.
       
    15  *
       
    16  * @category   Zend
       
    17  * @package    Zend_Http
       
    18  * @subpackage Cookie
       
    19  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    20  * @version    $Id: Cookie.php 23443 2010-11-24 11:53:13Z shahar $
       
    21  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    22  */
       
    23 
       
    24 /**
       
    25  * @see Zend_Uri_Http
       
    26  */
       
    27 require_once 'Zend/Uri/Http.php';
       
    28 
       
    29 
       
    30 /**
       
    31  * Zend_Http_Cookie is a class describing an HTTP cookie and all it's parameters.
       
    32  *
       
    33  * Zend_Http_Cookie is a class describing an HTTP cookie and all it's parameters. The
       
    34  * class also enables validating whether the cookie should be sent to the server in
       
    35  * a specified scenario according to the request URI, the expiry time and whether
       
    36  * session cookies should be used or not. Generally speaking cookies should be
       
    37  * contained in a Cookiejar object, or instantiated manually and added to an HTTP
       
    38  * request.
       
    39  *
       
    40  * See http://wp.netscape.com/newsref/std/cookie_spec.html for some specs.
       
    41  *
       
    42  * @category   Zend
       
    43  * @package    Zend_Http
       
    44  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    45  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    46  */
       
    47 class Zend_Http_Cookie
       
    48 {
       
    49     /**
       
    50      * Cookie name
       
    51      *
       
    52      * @var string
       
    53      */
       
    54     protected $name;
       
    55 
       
    56     /**
       
    57      * Cookie value
       
    58      *
       
    59      * @var string
       
    60      */
       
    61     protected $value;
       
    62 
       
    63     /**
       
    64      * Cookie expiry date
       
    65      *
       
    66      * @var int
       
    67      */
       
    68     protected $expires;
       
    69 
       
    70     /**
       
    71      * Cookie domain
       
    72      *
       
    73      * @var string
       
    74      */
       
    75     protected $domain;
       
    76 
       
    77     /**
       
    78      * Cookie path
       
    79      *
       
    80      * @var string
       
    81      */
       
    82     protected $path;
       
    83 
       
    84     /**
       
    85      * Whether the cookie is secure or not
       
    86      *
       
    87      * @var boolean
       
    88      */
       
    89     protected $secure;
       
    90 
       
    91     /**
       
    92      * Whether the cookie value has been encoded/decoded
       
    93      *
       
    94      * @var boolean
       
    95      */
       
    96     protected $encodeValue;
       
    97 
       
    98     /**
       
    99      * Cookie object constructor
       
   100      *
       
   101      * @todo Add validation of each one of the parameters (legal domain, etc.)
       
   102      *
       
   103      * @param string $name
       
   104      * @param string $value
       
   105      * @param string $domain
       
   106      * @param int $expires
       
   107      * @param string $path
       
   108      * @param bool $secure
       
   109      */
       
   110     public function __construct($name, $value, $domain, $expires = null, $path = null, $secure = false)
       
   111     {
       
   112         if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
       
   113             require_once 'Zend/Http/Exception.php';
       
   114             throw new Zend_Http_Exception("Cookie name cannot contain these characters: =,; \\t\\r\\n\\013\\014 ({$name})");
       
   115         }
       
   116 
       
   117         if (! $this->name = (string) $name) {
       
   118             require_once 'Zend/Http/Exception.php';
       
   119             throw new Zend_Http_Exception('Cookies must have a name');
       
   120         }
       
   121 
       
   122         if (! $this->domain = (string) $domain) {
       
   123             require_once 'Zend/Http/Exception.php';
       
   124             throw new Zend_Http_Exception('Cookies must have a domain');
       
   125         }
       
   126 
       
   127         $this->value = (string) $value;
       
   128         $this->expires = ($expires === null ? null : (int) $expires);
       
   129         $this->path = ($path ? $path : '/');
       
   130         $this->secure = $secure;
       
   131     }
       
   132 
       
   133     /**
       
   134      * Get Cookie name
       
   135      *
       
   136      * @return string
       
   137      */
       
   138     public function getName()
       
   139     {
       
   140         return $this->name;
       
   141     }
       
   142 
       
   143     /**
       
   144      * Get cookie value
       
   145      *
       
   146      * @return string
       
   147      */
       
   148     public function getValue()
       
   149     {
       
   150         return $this->value;
       
   151     }
       
   152 
       
   153     /**
       
   154      * Get cookie domain
       
   155      *
       
   156      * @return string
       
   157      */
       
   158     public function getDomain()
       
   159     {
       
   160         return $this->domain;
       
   161     }
       
   162 
       
   163     /**
       
   164      * Get the cookie path
       
   165      *
       
   166      * @return string
       
   167      */
       
   168     public function getPath()
       
   169     {
       
   170         return $this->path;
       
   171     }
       
   172 
       
   173     /**
       
   174      * Get the expiry time of the cookie, or null if no expiry time is set
       
   175      *
       
   176      * @return int|null
       
   177      */
       
   178     public function getExpiryTime()
       
   179     {
       
   180         return $this->expires;
       
   181     }
       
   182 
       
   183     /**
       
   184      * Check whether the cookie should only be sent over secure connections
       
   185      *
       
   186      * @return boolean
       
   187      */
       
   188     public function isSecure()
       
   189     {
       
   190         return $this->secure;
       
   191     }
       
   192 
       
   193     /**
       
   194      * Check whether the cookie has expired
       
   195      *
       
   196      * Always returns false if the cookie is a session cookie (has no expiry time)
       
   197      *
       
   198      * @param int $now Timestamp to consider as "now"
       
   199      * @return boolean
       
   200      */
       
   201     public function isExpired($now = null)
       
   202     {
       
   203         if ($now === null) $now = time();
       
   204         if (is_int($this->expires) && $this->expires < $now) {
       
   205             return true;
       
   206         } else {
       
   207             return false;
       
   208         }
       
   209     }
       
   210 
       
   211     /**
       
   212      * Check whether the cookie is a session cookie (has no expiry time set)
       
   213      *
       
   214      * @return boolean
       
   215      */
       
   216     public function isSessionCookie()
       
   217     {
       
   218         return ($this->expires === null);
       
   219     }
       
   220 
       
   221     /**
       
   222      * Checks whether the cookie should be sent or not in a specific scenario
       
   223      *
       
   224      * @param string|Zend_Uri_Http $uri URI to check against (secure, domain, path)
       
   225      * @param boolean $matchSessionCookies Whether to send session cookies
       
   226      * @param int $now Override the current time when checking for expiry time
       
   227      * @return boolean
       
   228      */
       
   229     public function match($uri, $matchSessionCookies = true, $now = null)
       
   230     {
       
   231         if (is_string ($uri)) {
       
   232             $uri = Zend_Uri_Http::factory($uri);
       
   233         }
       
   234 
       
   235         // Make sure we have a valid Zend_Uri_Http object
       
   236         if (! ($uri->valid() && ($uri->getScheme() == 'http' || $uri->getScheme() =='https'))) {
       
   237             require_once 'Zend/Http/Exception.php';
       
   238             throw new Zend_Http_Exception('Passed URI is not a valid HTTP or HTTPS URI');
       
   239         }
       
   240 
       
   241         // Check that the cookie is secure (if required) and not expired
       
   242         if ($this->secure && $uri->getScheme() != 'https') return false;
       
   243         if ($this->isExpired($now)) return false;
       
   244         if ($this->isSessionCookie() && ! $matchSessionCookies) return false;
       
   245 
       
   246         // Check if the domain matches
       
   247         if (! self::matchCookieDomain($this->getDomain(), $uri->getHost())) {
       
   248             return false;
       
   249         }
       
   250 
       
   251         // Check that path matches using prefix match
       
   252         if (! self::matchCookiePath($this->getPath(), $uri->getPath())) {
       
   253             return false;
       
   254         }
       
   255 
       
   256         // If we didn't die until now, return true.
       
   257         return true;
       
   258     }
       
   259 
       
   260     /**
       
   261      * Get the cookie as a string, suitable for sending as a "Cookie" header in an
       
   262      * HTTP request
       
   263      *
       
   264      * @return string
       
   265      */
       
   266     public function __toString()
       
   267     {
       
   268         if ($this->encodeValue) {
       
   269             return $this->name . '=' . urlencode($this->value) . ';';
       
   270         }
       
   271         return $this->name . '=' . $this->value . ';';
       
   272     }
       
   273 
       
   274     /**
       
   275      * Generate a new Cookie object from a cookie string
       
   276      * (for example the value of the Set-Cookie HTTP header)
       
   277      *
       
   278      * @param string $cookieStr
       
   279      * @param Zend_Uri_Http|string $refUri Reference URI for default values (domain, path)
       
   280      * @param boolean $encodeValue Whether or not the cookie's value should be
       
   281      *                             passed through urlencode/urldecode
       
   282      * @return Zend_Http_Cookie A new Zend_Http_Cookie object or false on failure.
       
   283      */
       
   284     public static function fromString($cookieStr, $refUri = null, $encodeValue = true)
       
   285     {
       
   286         // Set default values
       
   287         if (is_string($refUri)) {
       
   288             $refUri = Zend_Uri_Http::factory($refUri);
       
   289         }
       
   290 
       
   291         $name    = '';
       
   292         $value   = '';
       
   293         $domain  = '';
       
   294         $path    = '';
       
   295         $expires = null;
       
   296         $secure  = false;
       
   297         $parts   = explode(';', $cookieStr);
       
   298 
       
   299         // If first part does not include '=', fail
       
   300         if (strpos($parts[0], '=') === false) return false;
       
   301 
       
   302         // Get the name and value of the cookie
       
   303         list($name, $value) = explode('=', trim(array_shift($parts)), 2);
       
   304         $name  = trim($name);
       
   305         if ($encodeValue) {
       
   306             $value = urldecode(trim($value));
       
   307         }
       
   308 
       
   309         // Set default domain and path
       
   310         if ($refUri instanceof Zend_Uri_Http) {
       
   311             $domain = $refUri->getHost();
       
   312             $path = $refUri->getPath();
       
   313             $path = substr($path, 0, strrpos($path, '/'));
       
   314         }
       
   315 
       
   316         // Set other cookie parameters
       
   317         foreach ($parts as $part) {
       
   318             $part = trim($part);
       
   319             if (strtolower($part) == 'secure') {
       
   320                 $secure = true;
       
   321                 continue;
       
   322             }
       
   323 
       
   324             $keyValue = explode('=', $part, 2);
       
   325             if (count($keyValue) == 2) {
       
   326                 list($k, $v) = $keyValue;
       
   327                 switch (strtolower($k))    {
       
   328                     case 'expires':
       
   329                         if(($expires = strtotime($v)) === false) {
       
   330                             /**
       
   331                              * The expiration is past Tue, 19 Jan 2038 03:14:07 UTC
       
   332                              * the maximum for 32-bit signed integer. Zend_Date
       
   333                              * can get around that limit.
       
   334                              *
       
   335                              * @see Zend_Date
       
   336                              */
       
   337                             require_once 'Zend/Date.php';
       
   338 
       
   339                             $expireDate = new Zend_Date($v);
       
   340                             $expires = $expireDate->getTimestamp();
       
   341                         }
       
   342                         break;
       
   343 
       
   344                     case 'path':
       
   345                         $path = $v;
       
   346                         break;
       
   347 
       
   348                     case 'domain':
       
   349                         $domain = $v;
       
   350                         break;
       
   351 
       
   352                     default:
       
   353                         break;
       
   354                 }
       
   355             }
       
   356         }
       
   357 
       
   358         if ($name !== '') {
       
   359             $ret = new self($name, $value, $domain, $expires, $path, $secure);
       
   360             $ret->encodeValue = ($encodeValue) ? true : false;
       
   361             return $ret;
       
   362         } else {
       
   363             return false;
       
   364         }
       
   365     }
       
   366 
       
   367     /**
       
   368      * Check if a cookie's domain matches a host name.
       
   369      *
       
   370      * Used by Zend_Http_Cookie and Zend_Http_CookieJar for cookie matching
       
   371      *
       
   372      * @param  string $cookieDomain
       
   373      * @param  string $host
       
   374      *
       
   375      * @return boolean
       
   376      */
       
   377     public static function matchCookieDomain($cookieDomain, $host)
       
   378     {
       
   379         if (! $cookieDomain) {
       
   380             require_once 'Zend/Http/Exception.php';
       
   381             throw new Zend_Http_Exception("\$cookieDomain is expected to be a cookie domain");
       
   382         }
       
   383 
       
   384         if (! $host) {
       
   385             require_once 'Zend/Http/Exception.php';
       
   386             throw new Zend_Http_Exception("\$host is expected to be a host name");
       
   387         }
       
   388 
       
   389         $cookieDomain = strtolower($cookieDomain);
       
   390         $host = strtolower($host);
       
   391 
       
   392         if ($cookieDomain[0] == '.') {
       
   393             $cookieDomain = substr($cookieDomain, 1);
       
   394         }
       
   395 
       
   396         // Check for either exact match or suffix match
       
   397         return ($cookieDomain == $host ||
       
   398                 preg_match('/\.' . preg_quote($cookieDomain) . '$/', $host));
       
   399     }
       
   400 
       
   401     /**
       
   402      * Check if a cookie's path matches a URL path
       
   403      *
       
   404      * Used by Zend_Http_Cookie and Zend_Http_CookieJar for cookie matching
       
   405      *
       
   406      * @param  string $cookiePath
       
   407      * @param  string $path
       
   408      * @return boolean
       
   409      */
       
   410     public static function matchCookiePath($cookiePath, $path)
       
   411     {
       
   412         if (! $cookiePath) {
       
   413             require_once 'Zend/Http/Exception.php';
       
   414             throw new Zend_Http_Exception("\$cookiePath is expected to be a cookie path");
       
   415         }
       
   416 
       
   417         if (! $path) {
       
   418             require_once 'Zend/Http/Exception.php';
       
   419             throw new Zend_Http_Exception("\$path is expected to be a host name");
       
   420         }
       
   421 
       
   422         return (strpos($path, $cookiePath) === 0);
       
   423     }
       
   424 }