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 Header 19 * @version $Id$ 20 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 21 * @license http://framework.zend.com/license/new-bsd New BSD License 22 */ 23 24/** 25 * @see Zend_Http_Header_Exception_InvalidArgumentException 26 */ 27require_once "Zend/Http/Header/Exception/InvalidArgumentException.php"; 28 29/** 30 * @see Zend_Http_Header_Exception_RuntimeException 31 */ 32require_once "Zend/Http/Header/Exception/RuntimeException.php"; 33 34/** 35 * @see Zend_Http_Header_HeaderValue 36 */ 37require_once "Zend/Http/Header/HeaderValue.php"; 38 39/** 40 * Zend_Http_Client is an implementation of an HTTP client in PHP. The client 41 * supports basic features like sending different HTTP requests and handling 42 * redirections, as well as more advanced features like proxy settings, HTTP 43 * authentication and cookie persistence (using a Zend_Http_CookieJar object) 44 * 45 * @todo Implement proxy settings 46 * @category Zend 47 * @package Zend_Http 48 * @subpackage Header 49 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 50 * @license http://framework.zend.com/license/new-bsd New BSD License 51 */ 52class Zend_Http_Header_SetCookie 53{ 54 55 /** 56 * Cookie name 57 * 58 * @var string 59 */ 60 protected $name = null; 61 62 /** 63 * Cookie value 64 * 65 * @var string 66 */ 67 protected $value = null; 68 69 /** 70 * Version 71 * 72 * @var integer 73 */ 74 protected $version = null; 75 76 /** 77 * Max Age 78 * 79 * @var integer 80 */ 81 protected $maxAge = null; 82 83 /** 84 * Cookie expiry date 85 * 86 * @var int 87 */ 88 protected $expires = null; 89 90 /** 91 * Cookie domain 92 * 93 * @var string 94 */ 95 protected $domain = null; 96 97 /** 98 * Cookie path 99 * 100 * @var string 101 */ 102 protected $path = null; 103 104 /** 105 * Whether the cookie is secure or not 106 * 107 * @var boolean 108 */ 109 protected $secure = null; 110 111 /** 112 * @var true 113 */ 114 protected $httponly = null; 115 116 /** 117 * Generate a new Cookie object from a cookie string 118 * (for example the value of the Set-Cookie HTTP header) 119 * 120 * @static 121 * @throws Zend_Http_Header_Exception_InvalidArgumentException 122 * @param $headerLine 123 * @param bool $bypassHeaderFieldName 124 * @return array|SetCookie 125 */ 126 public static function fromString($headerLine, $bypassHeaderFieldName = false) 127 { 128 list($name, $value) = explode(': ', $headerLine, 2); 129 130 // check to ensure proper header type for this factory 131 if (strtolower($name) !== 'set-cookie') { 132 throw new Zend_Http_Header_Exception_InvalidArgumentException('Invalid header line for Set-Cookie string: "' . $name . '"'); 133 } 134 135 $multipleHeaders = preg_split('#(?<!Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s*#', $value); 136 $headers = array(); 137 foreach ($multipleHeaders as $headerLine) { 138 $header = new self(); 139 $keyValuePairs = preg_split('#;\s*#', $headerLine); 140 foreach ($keyValuePairs as $keyValue) { 141 if (strpos($keyValue, '=')) { 142 list($headerKey, $headerValue) = preg_split('#=\s*#', $keyValue, 2); 143 } else { 144 $headerKey = $keyValue; 145 $headerValue = null; 146 } 147 148 // First K=V pair is always the cookie name and value 149 if ($header->getName() === NULL) { 150 $header->setName($headerKey); 151 $header->setValue($headerValue); 152 continue; 153 } 154 155 // Process the remanining elements 156 switch (str_replace(array('-', '_'), '', strtolower($headerKey))) { 157 case 'expires' : $header->setExpires($headerValue); break; 158 case 'domain' : $header->setDomain($headerValue); break; 159 case 'path' : $header->setPath($headerValue); break; 160 case 'secure' : $header->setSecure(true); break; 161 case 'httponly': $header->setHttponly(true); break; 162 case 'version' : $header->setVersion((int) $headerValue); break; 163 case 'maxage' : $header->setMaxAge((int) $headerValue); break; 164 default: 165 // Intentionally omitted 166 } 167 } 168 $headers[] = $header; 169 } 170 return count($headers) == 1 ? array_pop($headers) : $headers; 171 } 172 173 /** 174 * Cookie object constructor 175 * 176 * @todo Add validation of each one of the parameters (legal domain, etc.) 177 * 178 * @param string $name 179 * @param string $value 180 * @param int $expires 181 * @param string $path 182 * @param string $domain 183 * @param bool $secure 184 * @param bool $httponly 185 * @param string $maxAge 186 * @param int $version 187 * @return SetCookie 188 */ 189 public function __construct($name = null, $value = null, $expires = null, $path = null, $domain = null, $secure = false, $httponly = false, $maxAge = null, $version = null) 190 { 191 $this->type = 'Cookie'; 192 193 if ($name) { 194 $this->setName($name); 195 } 196 197 if ($value) { 198 $this->setValue($value); // in parent 199 } 200 201 if ($version) { 202 $this->setVersion($version); 203 } 204 205 if ($maxAge) { 206 $this->setMaxAge($maxAge); 207 } 208 209 if ($domain) { 210 $this->setDomain($domain); 211 } 212 213 if ($expires) { 214 $this->setExpires($expires); 215 } 216 217 if ($path) { 218 $this->setPath($path); 219 } 220 221 if ($secure) { 222 $this->setSecure($secure); 223 } 224 225 if ($httponly) { 226 $this->setHttponly($httponly); 227 } 228 } 229 230 /** 231 * @return string 'Set-Cookie' 232 */ 233 public function getFieldName() 234 { 235 return 'Set-Cookie'; 236 } 237 238 /** 239 * @throws Zend_Http_Header_Exception_RuntimeException 240 * @return string 241 */ 242 public function getFieldValue() 243 { 244 if ($this->getName() == '') { 245 throw new Zend_Http_Header_Exception_RuntimeException('A cookie name is required to generate a field value for this cookie'); 246 } 247 248 $value = $this->getValue(); 249 if (strpos($value,'"')!==false) { 250 $value = '"'.urlencode(str_replace('"', '', $value)).'"'; 251 } else { 252 $value = urlencode($value); 253 } 254 $fieldValue = $this->getName() . '=' . $value; 255 256 $version = $this->getVersion(); 257 if ($version!==null) { 258 $fieldValue .= '; Version=' . $version; 259 } 260 261 $maxAge = $this->getMaxAge(); 262 if ($maxAge!==null) { 263 $fieldValue .= '; Max-Age=' . $maxAge; 264 } 265 266 $expires = $this->getExpires(); 267 if ($expires) { 268 $fieldValue .= '; Expires=' . $expires; 269 } 270 271 $domain = $this->getDomain(); 272 if ($domain) { 273 $fieldValue .= '; Domain=' . $domain; 274 } 275 276 $path = $this->getPath(); 277 if ($path) { 278 $fieldValue .= '; Path=' . $path; 279 } 280 281 if ($this->isSecure()) { 282 $fieldValue .= '; Secure'; 283 } 284 285 if ($this->isHttponly()) { 286 $fieldValue .= '; HttpOnly'; 287 } 288 289 return $fieldValue; 290 } 291 292 /** 293 * @param string $name 294 * @return SetCookie 295 */ 296 public function setName($name) 297 { 298 if (preg_match("/[=,; \t\r\n\013\014]/", $name)) { 299 throw new Zend_Http_Header_Exception_InvalidArgumentException("Cookie name cannot contain these characters: =,; \\t\\r\\n\\013\\014 ({$name})"); 300 } 301 302 $this->name = $name; 303 return $this; 304 } 305 306 /** 307 * @return string 308 */ 309 public function getName() 310 { 311 return $this->name; 312 } 313 314 /** 315 * @param string $value 316 */ 317 public function setValue($value) 318 { 319 Zend_Http_Header_HeaderValue::assertValid($value); 320 $this->value = $value; 321 return $this; 322 } 323 324 /** 325 * @return string 326 */ 327 public function getValue() 328 { 329 return $this->value; 330 } 331 332 /** 333 * Set version 334 * 335 * @param integer $version 336 */ 337 public function setVersion($version) 338 { 339 if (!is_int($version)) { 340 throw new Zend_Http_Header_Exception_InvalidArgumentException('Invalid Version number specified'); 341 } 342 $this->version = $version; 343 } 344 345 /** 346 * Get version 347 * 348 * @return integer 349 */ 350 public function getVersion() 351 { 352 return $this->version; 353 } 354 355 /** 356 * Set Max-Age 357 * 358 * @param integer $maxAge 359 */ 360 public function setMaxAge($maxAge) 361 { 362 if (!is_int($maxAge) || ($maxAge<0)) { 363 throw new Zend_Http_Header_Exception_InvalidArgumentException('Invalid Max-Age number specified'); 364 } 365 $this->maxAge = $maxAge; 366 } 367 368 /** 369 * Get Max-Age 370 * 371 * @return integer 372 */ 373 public function getMaxAge() 374 { 375 return $this->maxAge; 376 } 377 378 /** 379 * @param int $expires 380 * @return SetCookie 381 */ 382 public function setExpires($expires) 383 { 384 if (!empty($expires)) { 385 if (is_string($expires)) { 386 $expires = strtotime($expires); 387 } elseif (!is_int($expires)) { 388 throw new Zend_Http_Header_Exception_InvalidArgumentException('Invalid expires time specified'); 389 } 390 $this->expires = (int) $expires; 391 } 392 return $this; 393 } 394 395 /** 396 * @return int 397 */ 398 public function getExpires($inSeconds = false) 399 { 400 if ($this->expires == null) { 401 return; 402 } 403 if ($inSeconds) { 404 return $this->expires; 405 } 406 return gmdate('D, d-M-Y H:i:s', $this->expires) . ' GMT'; 407 } 408 409 /** 410 * @param string $domain 411 */ 412 public function setDomain($domain) 413 { 414 Zend_Http_Header_HeaderValue::assertValid($domain); 415 $this->domain = $domain; 416 return $this; 417 } 418 419 /** 420 * @return string 421 */ 422 public function getDomain() 423 { 424 return $this->domain; 425 } 426 427 /** 428 * @param string $path 429 */ 430 public function setPath($path) 431 { 432 Zend_Http_Header_HeaderValue::assertValid($path); 433 $this->path = $path; 434 return $this; 435 } 436 437 /** 438 * @return string 439 */ 440 public function getPath() 441 { 442 return $this->path; 443 } 444 445 /** 446 * @param boolean $secure 447 */ 448 public function setSecure($secure) 449 { 450 $this->secure = $secure; 451 return $this; 452 } 453 454 /** 455 * @return boolean 456 */ 457 public function isSecure() 458 { 459 return $this->secure; 460 } 461 462 /** 463 * @param bool $httponly 464 */ 465 public function setHttponly($httponly) 466 { 467 $this->httponly = $httponly; 468 return $this; 469 } 470 471 /** 472 * @return bool 473 */ 474 public function isHttponly() 475 { 476 return $this->httponly; 477 } 478 479 /** 480 * Check whether the cookie has expired 481 * 482 * Always returns false if the cookie is a session cookie (has no expiry time) 483 * 484 * @param int $now Timestamp to consider as "now" 485 * @return boolean 486 */ 487 public function isExpired($now = null) 488 { 489 if ($now === null) { 490 $now = time(); 491 } 492 493 if (is_int($this->expires) && $this->expires < $now) { 494 return true; 495 } else { 496 return false; 497 } 498 } 499 500 /** 501 * Check whether the cookie is a session cookie (has no expiry time set) 502 * 503 * @return boolean 504 */ 505 public function isSessionCookie() 506 { 507 return ($this->expires === null); 508 } 509 510 public function isValidForRequest($requestDomain, $path, $isSecure = false) 511 { 512 if ($this->getDomain() && (strrpos($requestDomain, $this->getDomain()) !== false)) { 513 return false; 514 } 515 516 if ($this->getPath() && (strpos($path, $this->getPath()) !== 0)) { 517 return false; 518 } 519 520 if ($this->secure && $this->isSecure()!==$isSecure) { 521 return false; 522 } 523 524 return true; 525 526 } 527 528 public function toString() 529 { 530 return $this->getFieldName() . ': ' . $this->getFieldValue(); 531 } 532 533 public function __toString() 534 { 535 return $this->toString(); 536 } 537 538 public function toStringMultipleHeaders(array $headers) 539 { 540 $headerLine = $this->toString(); 541 /* @var $header SetCookie */ 542 foreach ($headers as $header) { 543 if (!$header instanceof Zend_Http_Header_SetCookie) { 544 throw new Zend_Http_Header_Exception_RuntimeException( 545 'The SetCookie multiple header implementation can only accept an array of SetCookie headers' 546 ); 547 } 548 $headerLine .= ', ' . $header->getFieldValue(); 549 } 550 return $headerLine; 551 } 552 553 554} 555