web/lib/Zend/Http/CookieJar.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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 CookieJar
       
    18  * @version    $Id: CookieJar.php 23443 2010-11-24 11:53:13Z shahar $
       
    19  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    20  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    21  */
       
    22 
       
    23 /**
       
    24  * @see Zend_Uri
       
    25  */
       
    26 require_once "Zend/Uri.php";
       
    27 /**
       
    28  * @see Zend_Http_Cookie
       
    29  */
       
    30 require_once "Zend/Http/Cookie.php";
       
    31 /**
       
    32  * @see Zend_Http_Response
       
    33  */
       
    34 require_once "Zend/Http/Response.php";
       
    35 
       
    36 /**
       
    37  * A Zend_Http_CookieJar object is designed to contain and maintain HTTP cookies, and should
       
    38  * be used along with Zend_Http_Client in order to manage cookies across HTTP requests and
       
    39  * responses.
       
    40  *
       
    41  * The class contains an array of Zend_Http_Cookie objects. Cookies can be added to the jar
       
    42  * automatically from a request or manually. Then, the jar can find and return the cookies
       
    43  * needed for a specific HTTP request.
       
    44  *
       
    45  * A special parameter can be passed to all methods of this class that return cookies: Cookies
       
    46  * can be returned either in their native form (as Zend_Http_Cookie objects) or as strings -
       
    47  * the later is suitable for sending as the value of the "Cookie" header in an HTTP request.
       
    48  * You can also choose, when returning more than one cookie, whether to get an array of strings
       
    49  * (by passing Zend_Http_CookieJar::COOKIE_STRING_ARRAY) or one unified string for all cookies
       
    50  * (by passing Zend_Http_CookieJar::COOKIE_STRING_CONCAT).
       
    51  *
       
    52  * @link       http://wp.netscape.com/newsref/std/cookie_spec.html for some specs.
       
    53  *
       
    54  * @category   Zend
       
    55  * @package    Zend_Http
       
    56  * @subpackage CookieJar
       
    57  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    58  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    59  */
       
    60 class Zend_Http_CookieJar implements Countable, IteratorAggregate
       
    61 {
       
    62     /**
       
    63      * Return cookie(s) as a Zend_Http_Cookie object
       
    64      *
       
    65      */
       
    66     const COOKIE_OBJECT = 0;
       
    67 
       
    68     /**
       
    69      * Return cookie(s) as a string (suitable for sending in an HTTP request)
       
    70      *
       
    71      */
       
    72     const COOKIE_STRING_ARRAY = 1;
       
    73 
       
    74     /**
       
    75      * Return all cookies as one long string (suitable for sending in an HTTP request)
       
    76      *
       
    77      */
       
    78     const COOKIE_STRING_CONCAT = 2;
       
    79 
       
    80     /**
       
    81      * Array storing cookies
       
    82      *
       
    83      * Cookies are stored according to domain and path:
       
    84      * $cookies
       
    85      *  + www.mydomain.com
       
    86      *    + /
       
    87      *      - cookie1
       
    88      *      - cookie2
       
    89      *    + /somepath
       
    90      *      - othercookie
       
    91      *  + www.otherdomain.net
       
    92      *    + /
       
    93      *      - alsocookie
       
    94      *
       
    95      * @var array
       
    96      */
       
    97     protected $cookies = array();
       
    98 
       
    99     /**
       
   100      * The Zend_Http_Cookie array
       
   101      *
       
   102      * @var array
       
   103      */
       
   104     protected $_rawCookies = array();
       
   105 
       
   106     /**
       
   107      * Construct a new CookieJar object
       
   108      *
       
   109      */
       
   110     public function __construct()
       
   111     { }
       
   112 
       
   113     /**
       
   114      * Add a cookie to the jar. Cookie should be passed either as a Zend_Http_Cookie object
       
   115      * or as a string - in which case an object is created from the string.
       
   116      *
       
   117      * @param Zend_Http_Cookie|string $cookie
       
   118      * @param Zend_Uri_Http|string    $ref_uri Optional reference URI (for domain, path, secure)
       
   119      * @param boolean $encodeValue
       
   120      */
       
   121     public function addCookie($cookie, $ref_uri = null, $encodeValue = true)
       
   122     {
       
   123         if (is_string($cookie)) {
       
   124             $cookie = Zend_Http_Cookie::fromString($cookie, $ref_uri, $encodeValue);
       
   125         }
       
   126 
       
   127         if ($cookie instanceof Zend_Http_Cookie) {
       
   128             $domain = $cookie->getDomain();
       
   129             $path = $cookie->getPath();
       
   130             if (! isset($this->cookies[$domain])) $this->cookies[$domain] = array();
       
   131             if (! isset($this->cookies[$domain][$path])) $this->cookies[$domain][$path] = array();
       
   132             $this->cookies[$domain][$path][$cookie->getName()] = $cookie;
       
   133             $this->_rawCookies[] = $cookie;
       
   134         } else {
       
   135             require_once 'Zend/Http/Exception.php';
       
   136             throw new Zend_Http_Exception('Supplient argument is not a valid cookie string or object');
       
   137         }
       
   138     }
       
   139 
       
   140     /**
       
   141      * Parse an HTTP response, adding all the cookies set in that response
       
   142      * to the cookie jar.
       
   143      *
       
   144      * @param Zend_Http_Response $response
       
   145      * @param Zend_Uri_Http|string $ref_uri Requested URI
       
   146      * @param boolean $encodeValue
       
   147      */
       
   148     public function addCookiesFromResponse($response, $ref_uri, $encodeValue = true)
       
   149     {
       
   150         if (! $response instanceof Zend_Http_Response) {
       
   151             require_once 'Zend/Http/Exception.php';
       
   152             throw new Zend_Http_Exception('$response is expected to be a Response object, ' .
       
   153                 gettype($response) . ' was passed');
       
   154         }
       
   155 
       
   156         $cookie_hdrs = $response->getHeader('Set-Cookie');
       
   157 
       
   158         if (is_array($cookie_hdrs)) {
       
   159             foreach ($cookie_hdrs as $cookie) {
       
   160                 $this->addCookie($cookie, $ref_uri, $encodeValue);
       
   161             }
       
   162         } elseif (is_string($cookie_hdrs)) {
       
   163             $this->addCookie($cookie_hdrs, $ref_uri, $encodeValue);
       
   164         }
       
   165     }
       
   166 
       
   167     /**
       
   168      * Get all cookies in the cookie jar as an array
       
   169      *
       
   170      * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings
       
   171      * @return array|string
       
   172      */
       
   173     public function getAllCookies($ret_as = self::COOKIE_OBJECT)
       
   174     {
       
   175         $cookies = $this->_flattenCookiesArray($this->cookies, $ret_as);
       
   176         return $cookies;
       
   177     }
       
   178 
       
   179     /**
       
   180      * Return an array of all cookies matching a specific request according to the request URI,
       
   181      * whether session cookies should be sent or not, and the time to consider as "now" when
       
   182      * checking cookie expiry time.
       
   183      *
       
   184      * @param string|Zend_Uri_Http $uri URI to check against (secure, domain, path)
       
   185      * @param boolean $matchSessionCookies Whether to send session cookies
       
   186      * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings
       
   187      * @param int $now Override the current time when checking for expiry time
       
   188      * @return array|string
       
   189      */
       
   190     public function getMatchingCookies($uri, $matchSessionCookies = true,
       
   191         $ret_as = self::COOKIE_OBJECT, $now = null)
       
   192     {
       
   193         if (is_string($uri)) $uri = Zend_Uri::factory($uri);
       
   194         if (! $uri instanceof Zend_Uri_Http) {
       
   195             require_once 'Zend/Http/Exception.php';
       
   196             throw new Zend_Http_Exception("Invalid URI string or object passed");
       
   197         }
       
   198 
       
   199         // First, reduce the array of cookies to only those matching domain and path
       
   200         $cookies = $this->_matchDomain($uri->getHost());
       
   201         $cookies = $this->_matchPath($cookies, $uri->getPath());
       
   202         $cookies = $this->_flattenCookiesArray($cookies, self::COOKIE_OBJECT);
       
   203 
       
   204         // Next, run Cookie->match on all cookies to check secure, time and session mathcing
       
   205         $ret = array();
       
   206         foreach ($cookies as $cookie)
       
   207             if ($cookie->match($uri, $matchSessionCookies, $now))
       
   208                 $ret[] = $cookie;
       
   209 
       
   210         // Now, use self::_flattenCookiesArray again - only to convert to the return format ;)
       
   211         $ret = $this->_flattenCookiesArray($ret, $ret_as);
       
   212 
       
   213         return $ret;
       
   214     }
       
   215 
       
   216     /**
       
   217      * Get a specific cookie according to a URI and name
       
   218      *
       
   219      * @param Zend_Uri_Http|string $uri The uri (domain and path) to match
       
   220      * @param string $cookie_name The cookie's name
       
   221      * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings
       
   222      * @return Zend_Http_Cookie|string
       
   223      */
       
   224     public function getCookie($uri, $cookie_name, $ret_as = self::COOKIE_OBJECT)
       
   225     {
       
   226         if (is_string($uri)) {
       
   227             $uri = Zend_Uri::factory($uri);
       
   228         }
       
   229 
       
   230         if (! $uri instanceof Zend_Uri_Http) {
       
   231             require_once 'Zend/Http/Exception.php';
       
   232             throw new Zend_Http_Exception('Invalid URI specified');
       
   233         }
       
   234 
       
   235         // Get correct cookie path
       
   236         $path = $uri->getPath();
       
   237         $path = substr($path, 0, strrpos($path, '/'));
       
   238         if (! $path) $path = '/';
       
   239 
       
   240         if (isset($this->cookies[$uri->getHost()][$path][$cookie_name])) {
       
   241             $cookie = $this->cookies[$uri->getHost()][$path][$cookie_name];
       
   242 
       
   243             switch ($ret_as) {
       
   244                 case self::COOKIE_OBJECT:
       
   245                     return $cookie;
       
   246                     break;
       
   247 
       
   248                 case self::COOKIE_STRING_ARRAY:
       
   249                 case self::COOKIE_STRING_CONCAT:
       
   250                     return $cookie->__toString();
       
   251                     break;
       
   252 
       
   253                 default:
       
   254                     require_once 'Zend/Http/Exception.php';
       
   255                     throw new Zend_Http_Exception("Invalid value passed for \$ret_as: {$ret_as}");
       
   256                     break;
       
   257             }
       
   258         } else {
       
   259             return false;
       
   260         }
       
   261     }
       
   262 
       
   263     /**
       
   264      * Helper function to recursivly flatten an array. Shoud be used when exporting the
       
   265      * cookies array (or parts of it)
       
   266      *
       
   267      * @param Zend_Http_Cookie|array $ptr
       
   268      * @param int $ret_as What value to return
       
   269      * @return array|string
       
   270      */
       
   271     protected function _flattenCookiesArray($ptr, $ret_as = self::COOKIE_OBJECT) {
       
   272         if (is_array($ptr)) {
       
   273             $ret = ($ret_as == self::COOKIE_STRING_CONCAT ? '' : array());
       
   274             foreach ($ptr as $item) {
       
   275                 if ($ret_as == self::COOKIE_STRING_CONCAT) {
       
   276                     $ret .= $this->_flattenCookiesArray($item, $ret_as);
       
   277                 } else {
       
   278                     $ret = array_merge($ret, $this->_flattenCookiesArray($item, $ret_as));
       
   279                 }
       
   280             }
       
   281             return $ret;
       
   282         } elseif ($ptr instanceof Zend_Http_Cookie) {
       
   283             switch ($ret_as) {
       
   284                 case self::COOKIE_STRING_ARRAY:
       
   285                     return array($ptr->__toString());
       
   286                     break;
       
   287 
       
   288                 case self::COOKIE_STRING_CONCAT:
       
   289                     return $ptr->__toString();
       
   290                     break;
       
   291 
       
   292                 case self::COOKIE_OBJECT:
       
   293                 default:
       
   294                     return array($ptr);
       
   295                     break;
       
   296             }
       
   297         }
       
   298 
       
   299         return null;
       
   300     }
       
   301 
       
   302     /**
       
   303      * Return a subset of the cookies array matching a specific domain
       
   304      *
       
   305      * @param string $domain
       
   306      * @return array
       
   307      */
       
   308     protected function _matchDomain($domain)
       
   309     {
       
   310         $ret = array();
       
   311 
       
   312         foreach (array_keys($this->cookies) as $cdom) {
       
   313             if (Zend_Http_Cookie::matchCookieDomain($cdom, $domain)) {
       
   314                 $ret[$cdom] = $this->cookies[$cdom];
       
   315             }
       
   316         }
       
   317 
       
   318         return $ret;
       
   319     }
       
   320 
       
   321     /**
       
   322      * Return a subset of a domain-matching cookies that also match a specified path
       
   323      *
       
   324      * @param array $dom_array
       
   325      * @param string $path
       
   326      * @return array
       
   327      */
       
   328     protected function _matchPath($domains, $path)
       
   329     {
       
   330         $ret = array();
       
   331 
       
   332         foreach ($domains as $dom => $paths_array) {
       
   333             foreach (array_keys($paths_array) as $cpath) {
       
   334                 if (Zend_Http_Cookie::matchCookiePath($cpath, $path)) {
       
   335                     if (! isset($ret[$dom])) {
       
   336                         $ret[$dom] = array();
       
   337                     }
       
   338 
       
   339                     $ret[$dom][$cpath] = $paths_array[$cpath];
       
   340                 }
       
   341             }
       
   342         }
       
   343 
       
   344         return $ret;
       
   345     }
       
   346 
       
   347     /**
       
   348      * Create a new CookieJar object and automatically load into it all the
       
   349      * cookies set in an Http_Response object. If $uri is set, it will be
       
   350      * considered as the requested URI for setting default domain and path
       
   351      * of the cookie.
       
   352      *
       
   353      * @param Zend_Http_Response $response HTTP Response object
       
   354      * @param Zend_Uri_Http|string $uri The requested URI
       
   355      * @return Zend_Http_CookieJar
       
   356      * @todo Add the $uri functionality.
       
   357      */
       
   358     public static function fromResponse(Zend_Http_Response $response, $ref_uri)
       
   359     {
       
   360         $jar = new self();
       
   361         $jar->addCookiesFromResponse($response, $ref_uri);
       
   362         return $jar;
       
   363     }
       
   364 
       
   365     /**
       
   366      * Required by Countable interface
       
   367      *
       
   368      * @return int
       
   369      */
       
   370     public function count()
       
   371     {
       
   372         return count($this->_rawCookies);
       
   373     }
       
   374 
       
   375     /**
       
   376      * Required by IteratorAggregate interface
       
   377      *
       
   378      * @return ArrayIterator
       
   379      */
       
   380     public function getIterator()
       
   381     {
       
   382         return new ArrayIterator($this->_rawCookies);
       
   383     }
       
   384 
       
   385     /**
       
   386      * Tells if the jar is empty of any cookie
       
   387      *
       
   388      * @return bool
       
   389      */
       
   390     public function isEmpty()
       
   391     {
       
   392         return count($this) == 0;
       
   393     }
       
   394 
       
   395     /**
       
   396      * Empties the cookieJar of any cookie
       
   397      *
       
   398      * @return Zend_Http_CookieJar
       
   399      */
       
   400     public function reset()
       
   401     {
       
   402         $this->cookies = $this->_rawCookies = array();
       
   403         return $this;
       
   404     }
       
   405 }