127 101 =>
'Switching Protocols',
132 203 =>
'Non-Authoritative Information',
134 205 =>
'Reset Content',
135 206 =>
'Partial Content',
136 207 =>
'Multi-Status',
137 208 =>
'Already Reported',
139 300 =>
'Multiple Choices',
140 301 =>
'Moved Permanently',
143 304 =>
'Not Modified',
145 307 =>
'Temporary Redirect',
146 308 =>
'Permanent Redirect',
147 400 =>
'Bad Request',
148 401 =>
'Unauthorized',
149 402 =>
'Payment Required',
152 405 =>
'Method Not Allowed',
153 406 =>
'Not Acceptable',
154 407 =>
'Proxy Authentication Required',
155 408 =>
'Request Timeout',
158 411 =>
'Length Required',
159 412 =>
'Precondition Failed',
160 413 =>
'Payload Too Large',
161 414 =>
'URI Too Long',
162 415 =>
'Unsupported Media Type',
163 416 =>
'Range Not Satisfiable',
164 417 =>
'Expectation Failed',
165 418 =>
'I\'m a teapot',
166 421 =>
'Misdirected Request',
167 422 =>
'Unprocessable Entity',
169 424 =>
'Failed Dependency',
170 425 =>
'Reserved for WebDAV advanced collections expired proposal',
171 426 =>
'Upgrade Required',
172 428 =>
'Precondition Required',
173 429 =>
'Too Many Requests',
174 431 =>
'Request Header Fields Too Large',
175 451 =>
'Unavailable For Legal Reasons',
176 500 =>
'Internal Server Error',
177 501 =>
'Not Implemented',
178 502 =>
'Bad Gateway',
179 503 =>
'Service Unavailable',
180 504 =>
'Gateway Timeout',
181 505 =>
'HTTP Version Not Supported',
182 506 =>
'Variant Also Negotiates',
183 507 =>
'Insufficient Storage',
184 508 =>
'Loop Detected',
185 510 =>
'Not Extended',
186 511 =>
'Network Authentication Required',
206 if (!$this->headers->has(
'Date')) {
207 $this->
setDate(\DateTime::createFromFormat(
'U', time()));
244 sprintf(
'HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText).
"\r\n".
245 $this->headers.
"\r\n".
278 if (!
$headers->has(
'Content-Type')) {
279 $format = $request->getRequestFormat();
280 if (
null !== $format && $mimeType = $request->getMimeType($format)) {
281 $headers->set(
'Content-Type', $mimeType);
287 if (!
$headers->has(
'Content-Type')) {
289 } elseif (0 === stripos(
$headers->get(
'Content-Type'),
'text/') &&
false === stripos(
$headers->get(
'Content-Type'),
'charset')) {
295 if (
$headers->has(
'Transfer-Encoding')) {
299 if ($request->isMethod(
'HEAD')) {
301 $length =
$headers->get(
'Content-Length');
304 $headers->set(
'Content-Length', $length);
310 if (
'HTTP/1.0' != $request->server->get(
'SERVER_PROTOCOL')) {
315 if (
'1.0' == $this->
getProtocolVersion() &&
false !== strpos($this->headers->get(
'Cache-Control'),
'no-cache')) {
316 $this->headers->set(
'pragma',
'no-cache');
317 $this->headers->set(
'expires', -1);
333 if (headers_sent()) {
338 if (!$this->headers->has(
'Date')) {
339 $this->
setDate(\DateTime::createFromFormat(
'U', time()));
343 foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
344 foreach ($values as $value) {
345 header($name.
': '.$value,
false, $this->statusCode);
350 header(sprintf(
'HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText),
true, $this->statusCode);
353 foreach ($this->headers->getCookies() as $cookie) {
354 if ($cookie->isRaw()) {
355 setrawcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
357 setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
381 public function send()
386 if (function_exists(
'fastcgi_finish_request')) {
387 fastcgi_finish_request();
388 } elseif (
'cli' !== PHP_SAPI) {
389 static::closeOutputBuffers(0,
true);
409 throw new \UnexpectedValueException(sprintf(
'The Response content must be a string or object implementing __toString(), "%s" given.', gettype(
$content)));
472 $this->statusCode = $code = (int) $code;
474 throw new \InvalidArgumentException(sprintf(
'The HTTP status code "%s" is not valid.', $code));
477 if (
null === $text) {
478 $this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] :
'unknown status';
483 if (
false === $text) {
484 $this->statusText =
'';
489 $this->statusText = $text;
549 if (!in_array($this->statusCode, array(200, 203, 300, 301, 302, 404, 410))) {
553 if ($this->headers->hasCacheControlDirective(
'no-store') || $this->headers->getCacheControlDirective(
'private')) {
573 return $this->
getTtl() > 0;
586 return $this->headers->has(
'Last-Modified') || $this->headers->has(
'ETag');
600 $this->headers->removeCacheControlDirective(
'public');
601 $this->headers->addCacheControlDirective(
'private');
617 $this->headers->addCacheControlDirective(
'public');
618 $this->headers->removeCacheControlDirective(
'private');
637 return $this->headers->hasCacheControlDirective(
'must-revalidate') || $this->headers->hasCacheControlDirective(
'proxy-revalidate');
656 if (!$this->headers->has(
'Date')) {
657 $this->
setDate(\DateTime::createFromFormat(
'U', time()));
660 return $this->headers->getDate(
'Date');
672 public function setDate(\DateTime $date)
674 $date->setTimezone(
new \DateTimeZone(
'UTC'));
675 $this->headers->set(
'Date', $date->format(
'D, d M Y H:i:s').
' GMT');
689 if (
null !== $age = $this->headers->get(
'Age')) {
693 return max(time() - $this->
getDate()->format(
'U'), 0);
704 $this->headers->set(
'Age', $this->
getMaxAge());
720 return $this->headers->getDate(
'Expires');
721 }
catch (\RuntimeException $e) {
723 return \DateTime::createFromFormat(DATE_RFC2822,
'Sat, 01 Jan 00 00:00:00 +0000');
738 public function setExpires(\DateTime $date =
null)
740 if (
null === $date) {
741 $this->headers->remove(
'Expires');
744 $date->setTimezone(
new \DateTimeZone(
'UTC'));
745 $this->headers->set(
'Expires', $date->format(
'D, d M Y H:i:s').
' GMT');
764 if ($this->headers->hasCacheControlDirective(
's-maxage')) {
765 return (
int) $this->headers->getCacheControlDirective(
's-maxage');
768 if ($this->headers->hasCacheControlDirective(
'max-age')) {
769 return (
int) $this->headers->getCacheControlDirective(
'max-age');
790 $this->headers->addCacheControlDirective(
'max-age', $value);
809 $this->headers->addCacheControlDirective(
's-maxage', $value);
828 if (
null !== $maxAge = $this->
getMaxAge()) {
829 return $maxAge - $this->
getAge();
880 return $this->headers->getDate(
'Last-Modified');
896 if (
null === $date) {
897 $this->headers->remove(
'Last-Modified');
900 $date->setTimezone(
new \DateTimeZone(
'UTC'));
901 $this->headers->set(
'Last-Modified', $date->format(
'D, d M Y H:i:s').
' GMT');
916 return $this->headers->get(
'ETag');
929 public function setEtag($etag =
null, $weak =
false)
931 if (
null === $etag) {
932 $this->headers->remove(
'Etag');
934 if (0 !== strpos($etag,
'"')) {
935 $etag =
'"'.$etag.
'"';
938 $this->headers->set(
'ETag', (
true === $weak ?
'W/' :
'').$etag);
957 public function setCache(array $options)
959 if ($diff = array_diff(array_keys($options), array(
'etag',
'last_modified',
'max_age',
's_maxage',
'private',
'public'))) {
960 throw new \InvalidArgumentException(sprintf(
'Response does not support the following options: "%s".', implode(
'", "', array_values($diff))));
963 if (isset($options[
'etag'])) {
964 $this->
setEtag($options[
'etag']);
967 if (isset($options[
'last_modified'])) {
971 if (isset($options[
'max_age'])) {
975 if (isset($options[
's_maxage'])) {
979 if (isset($options[
'public'])) {
980 if ($options[
'public']) {
987 if (isset($options[
'private'])) {
988 if ($options[
'private']) {
1016 foreach (array(
'Allow',
'Content-Encoding',
'Content-Language',
'Content-Length',
'Content-MD5',
'Content-Type',
'Last-Modified') as $header) {
1017 $this->headers->remove($header);
1032 return null !== $this->headers->get(
'Vary');
1044 if (!$vary = $this->headers->get(
'Vary',
null,
false)) {
1049 foreach ($vary as $item) {
1050 $ret = array_merge($ret, preg_split(
'/[\s,]+/', $item));
1068 $this->headers->set(
'Vary',
$headers, $replace);
1088 if (!$request->isMethodCacheable()) {
1092 $notModified =
false;
1093 $lastModified = $this->headers->get(
'Last-Modified');
1094 $modifiedSince = $request->headers->get(
'If-Modified-Since');
1096 if ($etags = $request->getETags()) {
1097 $notModified = in_array($this->
getEtag(), $etags) || in_array(
'*', $etags);
1100 if ($modifiedSince && $lastModified) {
1101 $notModified = strtotime($modifiedSince) >= strtotime($lastModified) && (!$etags || $notModified);
1108 return $notModified;
1122 return $this->statusCode < 100 || $this->statusCode >= 600;
1134 return $this->statusCode >= 100 && $this->statusCode < 200;
1146 return $this->statusCode >= 200 && $this->statusCode < 300;
1158 return $this->statusCode >= 300 && $this->statusCode < 400;
1170 return $this->statusCode >= 400 && $this->statusCode < 500;
1182 return $this->statusCode >= 500 && $this->statusCode < 600;
1192 public function isOk()
1232 return in_array($this->statusCode, array(201, 301, 302, 303, 307, 308)) && (
null === $location ?: $location == $this->headers->get(
'Location'));
1244 return in_array($this->statusCode, array(204, 304));
1259 $status = ob_get_status(
true);
1260 $level = count($status);
1262 $flags = defined(
'PHP_OUTPUT_HANDLER_REMOVABLE') ? PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? PHP_OUTPUT_HANDLER_FLUSHABLE : PHP_OUTPUT_HANDLER_CLEANABLE) : -1;
1264 while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s[
'del']) ? !isset($s[
'flags']) || $flags === ($s[
'flags'] & $flags) : $s[
'del'])) {
1282 if (
false !== stripos($this->headers->get(
'Content-Disposition'),
'attachment') && preg_match(
'/MSIE (.*?);/i', $request->server->get(
'HTTP_USER_AGENT'), $match) == 1 &&
true === $request->isSecure()) {
1283 if ((
int) preg_replace(
'/(MSIE )(.*?);/',
'$2', $match[0]) < 9) {
1284 $this->headers->remove(
'Cache-Control');