[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 namespace Symfony\Component\HttpFoundation; 13 14 /** 15 * Response represents an HTTP response. 16 * 17 * @author Fabien Potencier <fabien@symfony.com> 18 */ 19 class Response 20 { 21 /** 22 * @var \Symfony\Component\HttpFoundation\ResponseHeaderBag 23 */ 24 public $headers; 25 26 /** 27 * @var string 28 */ 29 protected $content; 30 31 /** 32 * @var string 33 */ 34 protected $version; 35 36 /** 37 * @var int 38 */ 39 protected $statusCode; 40 41 /** 42 * @var string 43 */ 44 protected $statusText; 45 46 /** 47 * @var string 48 */ 49 protected $charset; 50 51 /** 52 * Status codes translation table. 53 * 54 * The list of codes is complete according to the 55 * {@link http://www.iana.org/assignments/http-status-codes/ Hypertext Transfer Protocol (HTTP) Status Code Registry} 56 * (last updated 2016-03-01). 57 * 58 * Unless otherwise noted, the status code is defined in RFC2616. 59 * 60 * @var array 61 */ 62 public static $statusTexts = array( 63 100 => 'Continue', 64 101 => 'Switching Protocols', 65 102 => 'Processing', // RFC2518 66 200 => 'OK', 67 201 => 'Created', 68 202 => 'Accepted', 69 203 => 'Non-Authoritative Information', 70 204 => 'No Content', 71 205 => 'Reset Content', 72 206 => 'Partial Content', 73 207 => 'Multi-Status', // RFC4918 74 208 => 'Already Reported', // RFC5842 75 226 => 'IM Used', // RFC3229 76 300 => 'Multiple Choices', 77 301 => 'Moved Permanently', 78 302 => 'Found', 79 303 => 'See Other', 80 304 => 'Not Modified', 81 305 => 'Use Proxy', 82 306 => 'Reserved', 83 307 => 'Temporary Redirect', 84 308 => 'Permanent Redirect', // RFC7238 85 400 => 'Bad Request', 86 401 => 'Unauthorized', 87 402 => 'Payment Required', 88 403 => 'Forbidden', 89 404 => 'Not Found', 90 405 => 'Method Not Allowed', 91 406 => 'Not Acceptable', 92 407 => 'Proxy Authentication Required', 93 408 => 'Request Timeout', 94 409 => 'Conflict', 95 410 => 'Gone', 96 411 => 'Length Required', 97 412 => 'Precondition Failed', 98 413 => 'Request Entity Too Large', 99 414 => 'Request-URI Too Long', 100 415 => 'Unsupported Media Type', 101 416 => 'Requested Range Not Satisfiable', 102 417 => 'Expectation Failed', 103 418 => 'I\'m a teapot', // RFC2324 104 421 => 'Misdirected Request', // RFC7540 105 422 => 'Unprocessable Entity', // RFC4918 106 423 => 'Locked', // RFC4918 107 424 => 'Failed Dependency', // RFC4918 108 425 => 'Reserved for WebDAV advanced collections expired proposal', // RFC2817 109 426 => 'Upgrade Required', // RFC2817 110 428 => 'Precondition Required', // RFC6585 111 429 => 'Too Many Requests', // RFC6585 112 431 => 'Request Header Fields Too Large', // RFC6585 113 451 => 'Unavailable For Legal Reasons', // RFC7725 114 500 => 'Internal Server Error', 115 501 => 'Not Implemented', 116 502 => 'Bad Gateway', 117 503 => 'Service Unavailable', 118 504 => 'Gateway Timeout', 119 505 => 'HTTP Version Not Supported', 120 506 => 'Variant Also Negotiates (Experimental)', // RFC2295 121 507 => 'Insufficient Storage', // RFC4918 122 508 => 'Loop Detected', // RFC5842 123 510 => 'Not Extended', // RFC2774 124 511 => 'Network Authentication Required', // RFC6585 125 ); 126 127 /** 128 * Constructor. 129 * 130 * @param string $content The response content 131 * @param int $status The response status code 132 * @param array $headers An array of response headers 133 * 134 * @throws \InvalidArgumentException When the HTTP status code is not valid 135 */ 136 public function __construct($content = '', $status = 200, $headers = array()) 137 { 138 $this->headers = new ResponseHeaderBag($headers); 139 $this->setContent($content); 140 $this->setStatusCode($status); 141 $this->setProtocolVersion('1.0'); 142 if (!$this->headers->has('Date')) { 143 $this->setDate(\DateTime::createFromFormat('U', time(), new \DateTimeZone('UTC'))); 144 } 145 } 146 147 /** 148 * Factory method for chainability. 149 * 150 * Example: 151 * 152 * return Response::create($body, 200) 153 * ->setSharedMaxAge(300); 154 * 155 * @param string $content The response content 156 * @param int $status The response status code 157 * @param array $headers An array of response headers 158 * 159 * @return Response 160 */ 161 public static function create($content = '', $status = 200, $headers = array()) 162 { 163 return new static($content, $status, $headers); 164 } 165 166 /** 167 * Returns the Response as an HTTP string. 168 * 169 * The string representation of the Response is the same as the 170 * one that will be sent to the client only if the prepare() method 171 * has been called before. 172 * 173 * @return string The Response as an HTTP string 174 * 175 * @see prepare() 176 */ 177 public function __toString() 178 { 179 return 180 sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". 181 $this->headers."\r\n". 182 $this->getContent(); 183 } 184 185 /** 186 * Clones the current Response instance. 187 */ 188 public function __clone() 189 { 190 $this->headers = clone $this->headers; 191 } 192 193 /** 194 * Prepares the Response before it is sent to the client. 195 * 196 * This method tweaks the Response to ensure that it is 197 * compliant with RFC 2616. Most of the changes are based on 198 * the Request that is "associated" with this Response. 199 * 200 * @param Request $request A Request instance 201 * 202 * @return Response The current response. 203 */ 204 public function prepare(Request $request) 205 { 206 $headers = $this->headers; 207 208 if ($this->isInformational() || $this->isEmpty()) { 209 $this->setContent(null); 210 $headers->remove('Content-Type'); 211 $headers->remove('Content-Length'); 212 } else { 213 // Content-type based on the Request 214 if (!$headers->has('Content-Type')) { 215 $format = $request->getRequestFormat(); 216 if (null !== $format && $mimeType = $request->getMimeType($format)) { 217 $headers->set('Content-Type', $mimeType); 218 } 219 } 220 221 // Fix Content-Type 222 $charset = $this->charset ?: 'UTF-8'; 223 if (!$headers->has('Content-Type')) { 224 $headers->set('Content-Type', 'text/html; charset='.$charset); 225 } elseif (0 === stripos($headers->get('Content-Type'), 'text/') && false === stripos($headers->get('Content-Type'), 'charset')) { 226 // add the charset 227 $headers->set('Content-Type', $headers->get('Content-Type').'; charset='.$charset); 228 } 229 230 // Fix Content-Length 231 if ($headers->has('Transfer-Encoding')) { 232 $headers->remove('Content-Length'); 233 } 234 235 if ($request->isMethod('HEAD')) { 236 // cf. RFC2616 14.13 237 $length = $headers->get('Content-Length'); 238 $this->setContent(null); 239 if ($length) { 240 $headers->set('Content-Length', $length); 241 } 242 } 243 } 244 245 // Fix protocol 246 if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) { 247 $this->setProtocolVersion('1.1'); 248 } 249 250 // Check if we need to send extra expire info headers 251 if ('1.0' == $this->getProtocolVersion() && 'no-cache' == $this->headers->get('Cache-Control')) { 252 $this->headers->set('pragma', 'no-cache'); 253 $this->headers->set('expires', -1); 254 } 255 256 $this->ensureIEOverSSLCompatibility($request); 257 258 return $this; 259 } 260 261 /** 262 * Sends HTTP headers. 263 * 264 * @return Response 265 */ 266 public function sendHeaders() 267 { 268 // headers have already been sent by the developer 269 if (headers_sent()) { 270 return $this; 271 } 272 273 // headers 274 foreach ($this->headers->allPreserveCase() as $name => $values) { 275 foreach ($values as $value) { 276 header($name.': '.$value, false); 277 } 278 } 279 280 // status 281 header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode); 282 283 // cookies 284 foreach ($this->headers->getCookies() as $cookie) { 285 setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly()); 286 } 287 288 return $this; 289 } 290 291 /** 292 * Sends content for the current web response. 293 * 294 * @return Response 295 */ 296 public function sendContent() 297 { 298 echo $this->content; 299 300 return $this; 301 } 302 303 /** 304 * Sends HTTP headers and content. 305 * 306 * @return Response 307 */ 308 public function send() 309 { 310 $this->sendHeaders(); 311 $this->sendContent(); 312 313 if (function_exists('fastcgi_finish_request')) { 314 fastcgi_finish_request(); 315 } elseif ('cli' !== PHP_SAPI) { 316 // ob_get_level() never returns 0 on some Windows configurations, so if 317 // the level is the same two times in a row, the loop should be stopped. 318 $previous = null; 319 $obStatus = ob_get_status(1); 320 while (($level = ob_get_level()) > 0 && $level !== $previous) { 321 $previous = $level; 322 if ($obStatus[$level - 1]) { 323 if (PHP_VERSION_ID >= 50400) { 324 if (isset($obStatus[$level - 1]['flags']) && ($obStatus[$level - 1]['flags'] & PHP_OUTPUT_HANDLER_REMOVABLE)) { 325 ob_end_flush(); 326 } 327 } else { 328 if (isset($obStatus[$level - 1]['del']) && $obStatus[$level - 1]['del']) { 329 ob_end_flush(); 330 } 331 } 332 } 333 } 334 flush(); 335 } 336 337 return $this; 338 } 339 340 /** 341 * Sets the response content. 342 * 343 * Valid types are strings, numbers, and objects that implement a __toString() method. 344 * 345 * @param mixed $content 346 * 347 * @return Response 348 * 349 * @throws \UnexpectedValueException 350 */ 351 public function setContent($content) 352 { 353 if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable(array($content, '__toString'))) { 354 throw new \UnexpectedValueException(sprintf('The Response content must be a string or object implementing __toString(), "%s" given.', gettype($content))); 355 } 356 357 $this->content = (string) $content; 358 359 return $this; 360 } 361 362 /** 363 * Gets the current response content. 364 * 365 * @return string Content 366 */ 367 public function getContent() 368 { 369 return $this->content; 370 } 371 372 /** 373 * Sets the HTTP protocol version (1.0 or 1.1). 374 * 375 * @param string $version The HTTP protocol version 376 * 377 * @return Response 378 */ 379 public function setProtocolVersion($version) 380 { 381 $this->version = $version; 382 383 return $this; 384 } 385 386 /** 387 * Gets the HTTP protocol version. 388 * 389 * @return string The HTTP protocol version 390 */ 391 public function getProtocolVersion() 392 { 393 return $this->version; 394 } 395 396 /** 397 * Sets the response status code. 398 * 399 * @param int $code HTTP status code 400 * @param mixed $text HTTP status text 401 * 402 * If the status text is null it will be automatically populated for the known 403 * status codes and left empty otherwise. 404 * 405 * @return Response 406 * 407 * @throws \InvalidArgumentException When the HTTP status code is not valid 408 */ 409 public function setStatusCode($code, $text = null) 410 { 411 $this->statusCode = $code = (int) $code; 412 if ($this->isInvalid()) { 413 throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code)); 414 } 415 416 if (null === $text) { 417 $this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : 'unknown status'; 418 419 return $this; 420 } 421 422 if (false === $text) { 423 $this->statusText = ''; 424 425 return $this; 426 } 427 428 $this->statusText = $text; 429 430 return $this; 431 } 432 433 /** 434 * Retrieves the status code for the current web response. 435 * 436 * @return int Status code 437 */ 438 public function getStatusCode() 439 { 440 return $this->statusCode; 441 } 442 443 /** 444 * Sets the response charset. 445 * 446 * @param string $charset Character set 447 * 448 * @return Response 449 */ 450 public function setCharset($charset) 451 { 452 $this->charset = $charset; 453 454 return $this; 455 } 456 457 /** 458 * Retrieves the response charset. 459 * 460 * @return string Character set 461 */ 462 public function getCharset() 463 { 464 return $this->charset; 465 } 466 467 /** 468 * Returns true if the response is worth caching under any circumstance. 469 * 470 * Responses marked "private" with an explicit Cache-Control directive are 471 * considered uncacheable. 472 * 473 * Responses with neither a freshness lifetime (Expires, max-age) nor cache 474 * validator (Last-Modified, ETag) are considered uncacheable. 475 * 476 * @return bool true if the response is worth caching, false otherwise 477 */ 478 public function isCacheable() 479 { 480 if (!in_array($this->statusCode, array(200, 203, 300, 301, 302, 404, 410))) { 481 return false; 482 } 483 484 if ($this->headers->hasCacheControlDirective('no-store') || $this->headers->getCacheControlDirective('private')) { 485 return false; 486 } 487 488 return $this->isValidateable() || $this->isFresh(); 489 } 490 491 /** 492 * Returns true if the response is "fresh". 493 * 494 * Fresh responses may be served from cache without any interaction with the 495 * origin. A response is considered fresh when it includes a Cache-Control/max-age 496 * indicator or Expires header and the calculated age is less than the freshness lifetime. 497 * 498 * @return bool true if the response is fresh, false otherwise 499 */ 500 public function isFresh() 501 { 502 return $this->getTtl() > 0; 503 } 504 505 /** 506 * Returns true if the response includes headers that can be used to validate 507 * the response with the origin server using a conditional GET request. 508 * 509 * @return bool true if the response is validateable, false otherwise 510 */ 511 public function isValidateable() 512 { 513 return $this->headers->has('Last-Modified') || $this->headers->has('ETag'); 514 } 515 516 /** 517 * Marks the response as "private". 518 * 519 * It makes the response ineligible for serving other clients. 520 * 521 * @return Response 522 */ 523 public function setPrivate() 524 { 525 $this->headers->removeCacheControlDirective('public'); 526 $this->headers->addCacheControlDirective('private'); 527 528 return $this; 529 } 530 531 /** 532 * Marks the response as "public". 533 * 534 * It makes the response eligible for serving other clients. 535 * 536 * @return Response 537 */ 538 public function setPublic() 539 { 540 $this->headers->addCacheControlDirective('public'); 541 $this->headers->removeCacheControlDirective('private'); 542 543 return $this; 544 } 545 546 /** 547 * Returns true if the response must be revalidated by caches. 548 * 549 * This method indicates that the response must not be served stale by a 550 * cache in any circumstance without first revalidating with the origin. 551 * When present, the TTL of the response should not be overridden to be 552 * greater than the value provided by the origin. 553 * 554 * @return bool true if the response must be revalidated by a cache, false otherwise 555 */ 556 public function mustRevalidate() 557 { 558 return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->hasCacheControlDirective('proxy-revalidate'); 559 } 560 561 /** 562 * Returns the Date header as a DateTime instance. 563 * 564 * @return \DateTime A \DateTime instance 565 * 566 * @throws \RuntimeException When the header is not parseable 567 */ 568 public function getDate() 569 { 570 return $this->headers->getDate('Date', new \DateTime()); 571 } 572 573 /** 574 * Sets the Date header. 575 * 576 * @param \DateTime $date A \DateTime instance 577 * 578 * @return Response 579 */ 580 public function setDate(\DateTime $date) 581 { 582 $date->setTimezone(new \DateTimeZone('UTC')); 583 $this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT'); 584 585 return $this; 586 } 587 588 /** 589 * Returns the age of the response. 590 * 591 * @return int The age of the response in seconds 592 */ 593 public function getAge() 594 { 595 if (null !== $age = $this->headers->get('Age')) { 596 return (int) $age; 597 } 598 599 return max(time() - $this->getDate()->format('U'), 0); 600 } 601 602 /** 603 * Marks the response stale by setting the Age header to be equal to the maximum age of the response. 604 * 605 * @return Response 606 */ 607 public function expire() 608 { 609 if ($this->isFresh()) { 610 $this->headers->set('Age', $this->getMaxAge()); 611 } 612 613 return $this; 614 } 615 616 /** 617 * Returns the value of the Expires header as a DateTime instance. 618 * 619 * @return \DateTime|null A DateTime instance or null if the header does not exist 620 */ 621 public function getExpires() 622 { 623 try { 624 return $this->headers->getDate('Expires'); 625 } catch (\RuntimeException $e) { 626 // according to RFC 2616 invalid date formats (e.g. "0" and "-1") must be treated as in the past 627 return \DateTime::createFromFormat(DATE_RFC2822, 'Sat, 01 Jan 00 00:00:00 +0000'); 628 } 629 } 630 631 /** 632 * Sets the Expires HTTP header with a DateTime instance. 633 * 634 * Passing null as value will remove the header. 635 * 636 * @param \DateTime|null $date A \DateTime instance or null to remove the header 637 * 638 * @return Response 639 */ 640 public function setExpires(\DateTime $date = null) 641 { 642 if (null === $date) { 643 $this->headers->remove('Expires'); 644 } else { 645 $date = clone $date; 646 $date->setTimezone(new \DateTimeZone('UTC')); 647 $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT'); 648 } 649 650 return $this; 651 } 652 653 /** 654 * Returns the number of seconds after the time specified in the response's Date 655 * header when the response should no longer be considered fresh. 656 * 657 * First, it checks for a s-maxage directive, then a max-age directive, and then it falls 658 * back on an expires header. It returns null when no maximum age can be established. 659 * 660 * @return int|null Number of seconds 661 */ 662 public function getMaxAge() 663 { 664 if ($this->headers->hasCacheControlDirective('s-maxage')) { 665 return (int) $this->headers->getCacheControlDirective('s-maxage'); 666 } 667 668 if ($this->headers->hasCacheControlDirective('max-age')) { 669 return (int) $this->headers->getCacheControlDirective('max-age'); 670 } 671 672 if (null !== $this->getExpires()) { 673 return $this->getExpires()->format('U') - $this->getDate()->format('U'); 674 } 675 } 676 677 /** 678 * Sets the number of seconds after which the response should no longer be considered fresh. 679 * 680 * This methods sets the Cache-Control max-age directive. 681 * 682 * @param int $value Number of seconds 683 * 684 * @return Response 685 */ 686 public function setMaxAge($value) 687 { 688 $this->headers->addCacheControlDirective('max-age', $value); 689 690 return $this; 691 } 692 693 /** 694 * Sets the number of seconds after which the response should no longer be considered fresh by shared caches. 695 * 696 * This methods sets the Cache-Control s-maxage directive. 697 * 698 * @param int $value Number of seconds 699 * 700 * @return Response 701 */ 702 public function setSharedMaxAge($value) 703 { 704 $this->setPublic(); 705 $this->headers->addCacheControlDirective('s-maxage', $value); 706 707 return $this; 708 } 709 710 /** 711 * Returns the response's time-to-live in seconds. 712 * 713 * It returns null when no freshness information is present in the response. 714 * 715 * When the responses TTL is <= 0, the response may not be served from cache without first 716 * revalidating with the origin. 717 * 718 * @return int|null The TTL in seconds 719 */ 720 public function getTtl() 721 { 722 if (null !== $maxAge = $this->getMaxAge()) { 723 return $maxAge - $this->getAge(); 724 } 725 } 726 727 /** 728 * Sets the response's time-to-live for shared caches. 729 * 730 * This method adjusts the Cache-Control/s-maxage directive. 731 * 732 * @param int $seconds Number of seconds 733 * 734 * @return Response 735 */ 736 public function setTtl($seconds) 737 { 738 $this->setSharedMaxAge($this->getAge() + $seconds); 739 740 return $this; 741 } 742 743 /** 744 * Sets the response's time-to-live for private/client caches. 745 * 746 * This method adjusts the Cache-Control/max-age directive. 747 * 748 * @param int $seconds Number of seconds 749 * 750 * @return Response 751 */ 752 public function setClientTtl($seconds) 753 { 754 $this->setMaxAge($this->getAge() + $seconds); 755 756 return $this; 757 } 758 759 /** 760 * Returns the Last-Modified HTTP header as a DateTime instance. 761 * 762 * @return \DateTime|null A DateTime instance or null if the header does not exist 763 * 764 * @throws \RuntimeException When the HTTP header is not parseable 765 */ 766 public function getLastModified() 767 { 768 return $this->headers->getDate('Last-Modified'); 769 } 770 771 /** 772 * Sets the Last-Modified HTTP header with a DateTime instance. 773 * 774 * Passing null as value will remove the header. 775 * 776 * @param \DateTime|null $date A \DateTime instance or null to remove the header 777 * 778 * @return Response 779 */ 780 public function setLastModified(\DateTime $date = null) 781 { 782 if (null === $date) { 783 $this->headers->remove('Last-Modified'); 784 } else { 785 $date = clone $date; 786 $date->setTimezone(new \DateTimeZone('UTC')); 787 $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT'); 788 } 789 790 return $this; 791 } 792 793 /** 794 * Returns the literal value of the ETag HTTP header. 795 * 796 * @return string|null The ETag HTTP header or null if it does not exist 797 */ 798 public function getEtag() 799 { 800 return $this->headers->get('ETag'); 801 } 802 803 /** 804 * Sets the ETag value. 805 * 806 * @param string|null $etag The ETag unique identifier or null to remove the header 807 * @param bool $weak Whether you want a weak ETag or not 808 * 809 * @return Response 810 */ 811 public function setEtag($etag = null, $weak = false) 812 { 813 if (null === $etag) { 814 $this->headers->remove('Etag'); 815 } else { 816 if (0 !== strpos($etag, '"')) { 817 $etag = '"'.$etag.'"'; 818 } 819 820 $this->headers->set('ETag', (true === $weak ? 'W/' : '').$etag); 821 } 822 823 return $this; 824 } 825 826 /** 827 * Sets the response's cache headers (validation and/or expiration). 828 * 829 * Available options are: etag, last_modified, max_age, s_maxage, private, and public. 830 * 831 * @param array $options An array of cache options 832 * 833 * @return Response 834 * 835 * @throws \InvalidArgumentException 836 */ 837 public function setCache(array $options) 838 { 839 if ($diff = array_diff(array_keys($options), array('etag', 'last_modified', 'max_age', 's_maxage', 'private', 'public'))) { 840 throw new \InvalidArgumentException(sprintf('Response does not support the following options: "%s".', implode('", "', array_values($diff)))); 841 } 842 843 if (isset($options['etag'])) { 844 $this->setEtag($options['etag']); 845 } 846 847 if (isset($options['last_modified'])) { 848 $this->setLastModified($options['last_modified']); 849 } 850 851 if (isset($options['max_age'])) { 852 $this->setMaxAge($options['max_age']); 853 } 854 855 if (isset($options['s_maxage'])) { 856 $this->setSharedMaxAge($options['s_maxage']); 857 } 858 859 if (isset($options['public'])) { 860 if ($options['public']) { 861 $this->setPublic(); 862 } else { 863 $this->setPrivate(); 864 } 865 } 866 867 if (isset($options['private'])) { 868 if ($options['private']) { 869 $this->setPrivate(); 870 } else { 871 $this->setPublic(); 872 } 873 } 874 875 return $this; 876 } 877 878 /** 879 * Modifies the response so that it conforms to the rules defined for a 304 status code. 880 * 881 * This sets the status, removes the body, and discards any headers 882 * that MUST NOT be included in 304 responses. 883 * 884 * @return Response 885 * 886 * @see http://tools.ietf.org/html/rfc2616#section-10.3.5 887 */ 888 public function setNotModified() 889 { 890 $this->setStatusCode(304); 891 $this->setContent(null); 892 893 // remove headers that MUST NOT be included with 304 Not Modified responses 894 foreach (array('Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-MD5', 'Content-Type', 'Last-Modified') as $header) { 895 $this->headers->remove($header); 896 } 897 898 return $this; 899 } 900 901 /** 902 * Returns true if the response includes a Vary header. 903 * 904 * @return bool true if the response includes a Vary header, false otherwise 905 */ 906 public function hasVary() 907 { 908 return null !== $this->headers->get('Vary'); 909 } 910 911 /** 912 * Returns an array of header names given in the Vary header. 913 * 914 * @return array An array of Vary names 915 */ 916 public function getVary() 917 { 918 if (!$vary = $this->headers->get('Vary', null, false)) { 919 return array(); 920 } 921 922 $ret = array(); 923 foreach ($vary as $item) { 924 $ret = array_merge($ret, preg_split('/[\s,]+/', $item)); 925 } 926 927 return $ret; 928 } 929 930 /** 931 * Sets the Vary header. 932 * 933 * @param string|array $headers 934 * @param bool $replace Whether to replace the actual value or not (true by default) 935 * 936 * @return Response 937 */ 938 public function setVary($headers, $replace = true) 939 { 940 $this->headers->set('Vary', $headers, $replace); 941 942 return $this; 943 } 944 945 /** 946 * Determines if the Response validators (ETag, Last-Modified) match 947 * a conditional value specified in the Request. 948 * 949 * If the Response is not modified, it sets the status code to 304 and 950 * removes the actual content by calling the setNotModified() method. 951 * 952 * @param Request $request A Request instance 953 * 954 * @return bool true if the Response validators match the Request, false otherwise 955 */ 956 public function isNotModified(Request $request) 957 { 958 if (!$request->isMethodSafe()) { 959 return false; 960 } 961 962 $notModified = false; 963 $lastModified = $this->headers->get('Last-Modified'); 964 $modifiedSince = $request->headers->get('If-Modified-Since'); 965 966 if ($etags = $request->getETags()) { 967 $notModified = in_array($this->getEtag(), $etags) || in_array('*', $etags); 968 } 969 970 if ($modifiedSince && $lastModified) { 971 $notModified = strtotime($modifiedSince) >= strtotime($lastModified) && (!$etags || $notModified); 972 } 973 974 if ($notModified) { 975 $this->setNotModified(); 976 } 977 978 return $notModified; 979 } 980 981 /** 982 * Is response invalid? 983 * 984 * @return bool 985 * 986 * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 987 */ 988 public function isInvalid() 989 { 990 return $this->statusCode < 100 || $this->statusCode >= 600; 991 } 992 993 /** 994 * Is response informative? 995 * 996 * @return bool 997 */ 998 public function isInformational() 999 { 1000 return $this->statusCode >= 100 && $this->statusCode < 200; 1001 } 1002 1003 /** 1004 * Is response successful? 1005 * 1006 * @return bool 1007 */ 1008 public function isSuccessful() 1009 { 1010 return $this->statusCode >= 200 && $this->statusCode < 300; 1011 } 1012 1013 /** 1014 * Is the response a redirect? 1015 * 1016 * @return bool 1017 */ 1018 public function isRedirection() 1019 { 1020 return $this->statusCode >= 300 && $this->statusCode < 400; 1021 } 1022 1023 /** 1024 * Is there a client error? 1025 * 1026 * @return bool 1027 */ 1028 public function isClientError() 1029 { 1030 return $this->statusCode >= 400 && $this->statusCode < 500; 1031 } 1032 1033 /** 1034 * Was there a server side error? 1035 * 1036 * @return bool 1037 */ 1038 public function isServerError() 1039 { 1040 return $this->statusCode >= 500 && $this->statusCode < 600; 1041 } 1042 1043 /** 1044 * Is the response OK? 1045 * 1046 * @return bool 1047 */ 1048 public function isOk() 1049 { 1050 return 200 === $this->statusCode; 1051 } 1052 1053 /** 1054 * Is the response forbidden? 1055 * 1056 * @return bool 1057 */ 1058 public function isForbidden() 1059 { 1060 return 403 === $this->statusCode; 1061 } 1062 1063 /** 1064 * Is the response a not found error? 1065 * 1066 * @return bool 1067 */ 1068 public function isNotFound() 1069 { 1070 return 404 === $this->statusCode; 1071 } 1072 1073 /** 1074 * Is the response a redirect of some form? 1075 * 1076 * @param string $location 1077 * 1078 * @return bool 1079 */ 1080 public function isRedirect($location = null) 1081 { 1082 return in_array($this->statusCode, array(201, 301, 302, 303, 307, 308)) && (null === $location ?: $location == $this->headers->get('Location')); 1083 } 1084 1085 /** 1086 * Is the response empty? 1087 * 1088 * @return bool 1089 */ 1090 public function isEmpty() 1091 { 1092 return in_array($this->statusCode, array(204, 304)); 1093 } 1094 1095 /** 1096 * Check if we need to remove Cache-Control for SSL encrypted downloads when using IE < 9. 1097 * 1098 * @link http://support.microsoft.com/kb/323308 1099 */ 1100 protected function ensureIEOverSSLCompatibility(Request $request) 1101 { 1102 if (false !== stripos($this->headers->get('Content-Disposition'), 'attachment') && preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT'), $match) == 1 && true === $request->isSecure()) { 1103 if ((int) preg_replace('/(MSIE )(.*?);/', '$2', $match[0]) < 9) { 1104 $this->headers->remove('Cache-Control'); 1105 } 1106 } 1107 } 1108 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |