File indexing completed on 2024-05-12 06:02:41
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Http 0017 * @subpackage CookieJar 0018 * @version $Id$ 0019 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0020 * @license http://framework.zend.com/license/new-bsd New BSD License 0021 */ 0022 0023 /** 0024 * @see Zend_Uri 0025 */ 0026 // require_once "Zend/Uri.php"; 0027 /** 0028 * @see Zend_Http_Cookie 0029 */ 0030 // require_once "Zend/Http/Cookie.php"; 0031 /** 0032 * @see Zend_Http_Response 0033 */ 0034 // require_once "Zend/Http/Response.php"; 0035 0036 /** 0037 * A Zend_Http_CookieJar object is designed to contain and maintain HTTP cookies, and should 0038 * be used along with Zend_Http_Client in order to manage cookies across HTTP requests and 0039 * responses. 0040 * 0041 * The class contains an array of Zend_Http_Cookie objects. Cookies can be added to the jar 0042 * automatically from a request or manually. Then, the jar can find and return the cookies 0043 * needed for a specific HTTP request. 0044 * 0045 * A special parameter can be passed to all methods of this class that return cookies: Cookies 0046 * can be returned either in their native form (as Zend_Http_Cookie objects) or as strings - 0047 * the later is suitable for sending as the value of the "Cookie" header in an HTTP request. 0048 * You can also choose, when returning more than one cookie, whether to get an array of strings 0049 * (by passing Zend_Http_CookieJar::COOKIE_STRING_ARRAY) or one unified string for all cookies 0050 * (by passing Zend_Http_CookieJar::COOKIE_STRING_CONCAT). 0051 * 0052 * @link http://wp.netscape.com/newsref/std/cookie_spec.html for some specs. 0053 * 0054 * @category Zend 0055 * @package Zend_Http 0056 * @subpackage CookieJar 0057 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0058 * @license http://framework.zend.com/license/new-bsd New BSD License 0059 */ 0060 class Zend_Http_CookieJar implements Countable, IteratorAggregate 0061 { 0062 /** 0063 * Return cookie(s) as a Zend_Http_Cookie object 0064 * 0065 */ 0066 const COOKIE_OBJECT = 0; 0067 0068 /** 0069 * Return cookie(s) as a string (suitable for sending in an HTTP request) 0070 * 0071 */ 0072 const COOKIE_STRING_ARRAY = 1; 0073 0074 /** 0075 * Return all cookies as one long string (suitable for sending in an HTTP request) 0076 * 0077 */ 0078 const COOKIE_STRING_CONCAT = 2; 0079 0080 /** 0081 * Return all cookies as one long string (strict mode) 0082 * - Single space after the semi-colon separating each cookie 0083 * - Remove trailing semi-colon, if any 0084 */ 0085 const COOKIE_STRING_CONCAT_STRICT = 3; 0086 0087 /** 0088 * Array storing cookies 0089 * 0090 * Cookies are stored according to domain and path: 0091 * $cookies 0092 * + www.mydomain.com 0093 * + / 0094 * - cookie1 0095 * - cookie2 0096 * + /somepath 0097 * - othercookie 0098 * + www.otherdomain.net 0099 * + / 0100 * - alsocookie 0101 * 0102 * @var array 0103 */ 0104 protected $cookies = array(); 0105 0106 /** 0107 * The Zend_Http_Cookie array 0108 * 0109 * @var array 0110 */ 0111 protected $_rawCookies = array(); 0112 0113 /** 0114 * Construct a new CookieJar object 0115 * 0116 */ 0117 public function __construct() 0118 { } 0119 0120 /** 0121 * Add a cookie to the jar. Cookie should be passed either as a Zend_Http_Cookie object 0122 * or as a string - in which case an object is created from the string. 0123 * 0124 * @param Zend_Http_Cookie|string $cookie 0125 * @param Zend_Uri_Http|string $ref_uri Optional reference URI (for domain, path, secure) 0126 * @param boolean $encodeValue 0127 */ 0128 public function addCookie($cookie, $ref_uri = null, $encodeValue = true) 0129 { 0130 if (is_string($cookie)) { 0131 $cookie = Zend_Http_Cookie::fromString($cookie, $ref_uri, $encodeValue); 0132 } 0133 0134 if ($cookie instanceof Zend_Http_Cookie) { 0135 $domain = $cookie->getDomain(); 0136 $path = $cookie->getPath(); 0137 if (! isset($this->cookies[$domain])) $this->cookies[$domain] = array(); 0138 if (! isset($this->cookies[$domain][$path])) $this->cookies[$domain][$path] = array(); 0139 $this->cookies[$domain][$path][$cookie->getName()] = $cookie; 0140 $this->_rawCookies[] = $cookie; 0141 } else { 0142 // require_once 'Zend/Http/Exception.php'; 0143 throw new Zend_Http_Exception('Supplient argument is not a valid cookie string or object'); 0144 } 0145 } 0146 0147 /** 0148 * Parse an HTTP response, adding all the cookies set in that response 0149 * to the cookie jar. 0150 * 0151 * @param Zend_Http_Response $response 0152 * @param Zend_Uri_Http|string $ref_uri Requested URI 0153 * @param boolean $encodeValue 0154 */ 0155 public function addCookiesFromResponse($response, $ref_uri, $encodeValue = true) 0156 { 0157 if (! $response instanceof Zend_Http_Response) { 0158 // require_once 'Zend/Http/Exception.php'; 0159 throw new Zend_Http_Exception('$response is expected to be a Response object, ' . 0160 gettype($response) . ' was passed'); 0161 } 0162 0163 $cookie_hdrs = $response->getHeader('Set-Cookie'); 0164 0165 if (is_array($cookie_hdrs)) { 0166 foreach ($cookie_hdrs as $cookie) { 0167 $this->addCookie($cookie, $ref_uri, $encodeValue); 0168 } 0169 } elseif (is_string($cookie_hdrs)) { 0170 $this->addCookie($cookie_hdrs, $ref_uri, $encodeValue); 0171 } 0172 } 0173 0174 /** 0175 * Get all cookies in the cookie jar as an array 0176 * 0177 * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings 0178 * @return array|string 0179 */ 0180 public function getAllCookies($ret_as = self::COOKIE_OBJECT) 0181 { 0182 $cookies = $this->_flattenCookiesArray($this->cookies, $ret_as); 0183 if($ret_as == self::COOKIE_STRING_CONCAT_STRICT) { 0184 $cookies = rtrim(trim($cookies), ';'); 0185 } 0186 return $cookies; 0187 } 0188 0189 /** 0190 * Return an array of all cookies matching a specific request according to the request URI, 0191 * whether session cookies should be sent or not, and the time to consider as "now" when 0192 * checking cookie expiry time. 0193 * 0194 * @param string|Zend_Uri_Http $uri URI to check against (secure, domain, path) 0195 * @param boolean $matchSessionCookies Whether to send session cookies 0196 * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings 0197 * @param int $now Override the current time when checking for expiry time 0198 * @return array|string 0199 */ 0200 public function getMatchingCookies($uri, $matchSessionCookies = true, 0201 $ret_as = self::COOKIE_OBJECT, $now = null) 0202 { 0203 if (is_string($uri)) $uri = Zend_Uri::factory($uri); 0204 if (! $uri instanceof Zend_Uri_Http) { 0205 // require_once 'Zend/Http/Exception.php'; 0206 throw new Zend_Http_Exception("Invalid URI string or object passed"); 0207 } 0208 0209 // First, reduce the array of cookies to only those matching domain and path 0210 $cookies = $this->_matchDomain($uri->getHost()); 0211 $cookies = $this->_matchPath($cookies, $uri->getPath()); 0212 $cookies = $this->_flattenCookiesArray($cookies, self::COOKIE_OBJECT); 0213 0214 // Next, run Cookie->match on all cookies to check secure, time and session mathcing 0215 $ret = array(); 0216 foreach ($cookies as $cookie) 0217 if ($cookie->match($uri, $matchSessionCookies, $now)) 0218 $ret[] = $cookie; 0219 0220 // Now, use self::_flattenCookiesArray again - only to convert to the return format ;) 0221 $ret = $this->_flattenCookiesArray($ret, $ret_as); 0222 if($ret_as == self::COOKIE_STRING_CONCAT_STRICT) { 0223 $ret = rtrim(trim($ret), ';'); 0224 } 0225 0226 return $ret; 0227 } 0228 0229 /** 0230 * Get a specific cookie according to a URI and name 0231 * 0232 * @param Zend_Uri_Http|string $uri The uri (domain and path) to match 0233 * @param string $cookie_name The cookie's name 0234 * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings 0235 * @return Zend_Http_Cookie|string 0236 */ 0237 public function getCookie($uri, $cookie_name, $ret_as = self::COOKIE_OBJECT) 0238 { 0239 if (is_string($uri)) { 0240 $uri = Zend_Uri::factory($uri); 0241 } 0242 0243 if (! $uri instanceof Zend_Uri_Http) { 0244 // require_once 'Zend/Http/Exception.php'; 0245 throw new Zend_Http_Exception('Invalid URI specified'); 0246 } 0247 0248 // Get correct cookie path 0249 $path = $uri->getPath(); 0250 $path = substr($path, 0, strrpos($path, '/')); 0251 if (! $path) $path = '/'; 0252 0253 if (isset($this->cookies[$uri->getHost()][$path][$cookie_name])) { 0254 $cookie = $this->cookies[$uri->getHost()][$path][$cookie_name]; 0255 0256 switch ($ret_as) { 0257 case self::COOKIE_OBJECT: 0258 return $cookie; 0259 break; 0260 0261 case self::COOKIE_STRING_CONCAT_STRICT: 0262 return rtrim(trim($cookie->__toString()), ';'); 0263 break; 0264 0265 case self::COOKIE_STRING_ARRAY: 0266 case self::COOKIE_STRING_CONCAT: 0267 return $cookie->__toString(); 0268 break; 0269 0270 default: 0271 // require_once 'Zend/Http/Exception.php'; 0272 throw new Zend_Http_Exception("Invalid value passed for \$ret_as: {$ret_as}"); 0273 break; 0274 } 0275 } else { 0276 return false; 0277 } 0278 } 0279 0280 /** 0281 * Helper function to recursivly flatten an array. Shoud be used when exporting the 0282 * cookies array (or parts of it) 0283 * 0284 * @param Zend_Http_Cookie|array $ptr 0285 * @param int $ret_as What value to return 0286 * @return array|string 0287 */ 0288 protected function _flattenCookiesArray($ptr, $ret_as = self::COOKIE_OBJECT) { 0289 if (is_array($ptr)) { 0290 $ret = ($ret_as == self::COOKIE_STRING_CONCAT || $ret_as == self::COOKIE_STRING_CONCAT_STRICT) ? '' : array(); 0291 foreach ($ptr as $item) { 0292 if ($ret_as == self::COOKIE_STRING_CONCAT_STRICT) { 0293 $postfix_combine = (!is_array($item) ? ' ' : ''); 0294 $ret .= $this->_flattenCookiesArray($item, $ret_as) . $postfix_combine; 0295 } elseif ($ret_as == self::COOKIE_STRING_CONCAT) { 0296 $ret .= $this->_flattenCookiesArray($item, $ret_as); 0297 } else { 0298 $ret = array_merge($ret, $this->_flattenCookiesArray($item, $ret_as)); 0299 } 0300 } 0301 return $ret; 0302 } elseif ($ptr instanceof Zend_Http_Cookie) { 0303 switch ($ret_as) { 0304 case self::COOKIE_STRING_ARRAY: 0305 return array($ptr->__toString()); 0306 break; 0307 0308 case self::COOKIE_STRING_CONCAT_STRICT: 0309 // break intentionally omitted 0310 0311 case self::COOKIE_STRING_CONCAT: 0312 return $ptr->__toString(); 0313 break; 0314 0315 case self::COOKIE_OBJECT: 0316 default: 0317 return array($ptr); 0318 break; 0319 } 0320 } 0321 0322 return null; 0323 } 0324 0325 /** 0326 * Return a subset of the cookies array matching a specific domain 0327 * 0328 * @param string $domain 0329 * @return array 0330 */ 0331 protected function _matchDomain($domain) 0332 { 0333 $ret = array(); 0334 0335 foreach (array_keys($this->cookies) as $cdom) { 0336 if (Zend_Http_Cookie::matchCookieDomain($cdom, $domain)) { 0337 $ret[$cdom] = $this->cookies[$cdom]; 0338 } 0339 } 0340 0341 return $ret; 0342 } 0343 0344 /** 0345 * Return a subset of a domain-matching cookies that also match a specified path 0346 * 0347 * @param array $dom_array 0348 * @param string $path 0349 * @return array 0350 */ 0351 protected function _matchPath($domains, $path) 0352 { 0353 $ret = array(); 0354 0355 foreach ($domains as $dom => $paths_array) { 0356 foreach (array_keys($paths_array) as $cpath) { 0357 if (Zend_Http_Cookie::matchCookiePath($cpath, $path)) { 0358 if (! isset($ret[$dom])) { 0359 $ret[$dom] = array(); 0360 } 0361 0362 $ret[$dom][$cpath] = $paths_array[$cpath]; 0363 } 0364 } 0365 } 0366 0367 return $ret; 0368 } 0369 0370 /** 0371 * Create a new CookieJar object and automatically load into it all the 0372 * cookies set in an Http_Response object. If $uri is set, it will be 0373 * considered as the requested URI for setting default domain and path 0374 * of the cookie. 0375 * 0376 * @param Zend_Http_Response $response HTTP Response object 0377 * @param Zend_Uri_Http|string $uri The requested URI 0378 * @return Zend_Http_CookieJar 0379 * @todo Add the $uri functionality. 0380 */ 0381 public static function fromResponse(Zend_Http_Response $response, $ref_uri) 0382 { 0383 $jar = new self(); 0384 $jar->addCookiesFromResponse($response, $ref_uri); 0385 return $jar; 0386 } 0387 0388 /** 0389 * Required by Countable interface 0390 * 0391 * @return int 0392 */ 0393 public function count() 0394 { 0395 return count($this->_rawCookies); 0396 } 0397 0398 /** 0399 * Required by IteratorAggregate interface 0400 * 0401 * @return ArrayIterator 0402 */ 0403 public function getIterator() 0404 { 0405 return new ArrayIterator($this->_rawCookies); 0406 } 0407 0408 /** 0409 * Tells if the jar is empty of any cookie 0410 * 0411 * @return bool 0412 */ 0413 public function isEmpty() 0414 { 0415 return count($this) == 0; 0416 } 0417 0418 /** 0419 * Empties the cookieJar of any cookie 0420 * 0421 * @return Zend_Http_CookieJar 0422 */ 0423 public function reset() 0424 { 0425 $this->cookies = $this->_rawCookies = array(); 0426 return $this; 0427 } 0428 }