1<?php 2 3namespace Sabre\HTTP; 4 5/** 6 * This class represents a single HTTP response. 7 * 8 * @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/). 9 * @author Evert Pot (http://evertpot.com/) 10 * @license http://sabre.io/license/ Modified BSD License 11 */ 12class Response extends Message implements ResponseInterface { 13 14 /** 15 * This is the list of currently registered HTTP status codes. 16 * 17 * @var array 18 */ 19 static $statusCodes = [ 20 100 => 'Continue', 21 101 => 'Switching Protocols', 22 102 => 'Processing', 23 200 => 'OK', 24 201 => 'Created', 25 202 => 'Accepted', 26 203 => 'Non-Authorative Information', 27 204 => 'No Content', 28 205 => 'Reset Content', 29 206 => 'Partial Content', 30 207 => 'Multi-Status', // RFC 4918 31 208 => 'Already Reported', // RFC 5842 32 226 => 'IM Used', // RFC 3229 33 300 => 'Multiple Choices', 34 301 => 'Moved Permanently', 35 302 => 'Found', 36 303 => 'See Other', 37 304 => 'Not Modified', 38 305 => 'Use Proxy', 39 307 => 'Temporary Redirect', 40 308 => 'Permanent Redirect', 41 400 => 'Bad Request', 42 401 => 'Unauthorized', 43 402 => 'Payment Required', 44 403 => 'Forbidden', 45 404 => 'Not Found', 46 405 => 'Method Not Allowed', 47 406 => 'Not Acceptable', 48 407 => 'Proxy Authentication Required', 49 408 => 'Request Timeout', 50 409 => 'Conflict', 51 410 => 'Gone', 52 411 => 'Length Required', 53 412 => 'Precondition failed', 54 413 => 'Request Entity Too Large', 55 414 => 'Request-URI Too Long', 56 415 => 'Unsupported Media Type', 57 416 => 'Requested Range Not Satisfiable', 58 417 => 'Expectation Failed', 59 418 => 'I\'m a teapot', // RFC 2324 60 421 => 'Misdirected Request', // RFC7540 (HTTP/2) 61 422 => 'Unprocessable Entity', // RFC 4918 62 423 => 'Locked', // RFC 4918 63 424 => 'Failed Dependency', // RFC 4918 64 426 => 'Upgrade Required', 65 428 => 'Precondition Required', // RFC 6585 66 429 => 'Too Many Requests', // RFC 6585 67 431 => 'Request Header Fields Too Large', // RFC 6585 68 451 => 'Unavailable For Legal Reasons', // draft-tbray-http-legally-restricted-status 69 500 => 'Internal Server Error', 70 501 => 'Not Implemented', 71 502 => 'Bad Gateway', 72 503 => 'Service Unavailable', 73 504 => 'Gateway Timeout', 74 505 => 'HTTP Version not supported', 75 506 => 'Variant Also Negotiates', 76 507 => 'Insufficient Storage', // RFC 4918 77 508 => 'Loop Detected', // RFC 5842 78 509 => 'Bandwidth Limit Exceeded', // non-standard 79 510 => 'Not extended', 80 511 => 'Network Authentication Required', // RFC 6585 81 ]; 82 83 /** 84 * HTTP status code 85 * 86 * @var int 87 */ 88 protected $status; 89 90 /** 91 * HTTP status text 92 * 93 * @var string 94 */ 95 protected $statusText; 96 97 /** 98 * Creates the response object 99 * 100 * @param string|int $status 101 * @param array $headers 102 * @param resource $body 103 * @return void 104 */ 105 function __construct($status = null, array $headers = null, $body = null) { 106 107 if (!is_null($status)) $this->setStatus($status); 108 if (!is_null($headers)) $this->setHeaders($headers); 109 if (!is_null($body)) $this->setBody($body); 110 111 } 112 113 114 /** 115 * Returns the current HTTP status code. 116 * 117 * @return int 118 */ 119 function getStatus() { 120 121 return $this->status; 122 123 } 124 125 /** 126 * Returns the human-readable status string. 127 * 128 * In the case of a 200, this may for example be 'OK'. 129 * 130 * @return string 131 */ 132 function getStatusText() { 133 134 return $this->statusText; 135 136 } 137 138 /** 139 * Sets the HTTP status code. 140 * 141 * This can be either the full HTTP status code with human readable string, 142 * for example: "403 I can't let you do that, Dave". 143 * 144 * Or just the code, in which case the appropriate default message will be 145 * added. 146 * 147 * @param string|int $status 148 * @throws \InvalidArgumentExeption 149 * @return void 150 */ 151 function setStatus($status) { 152 153 if (ctype_digit($status) || is_int($status)) { 154 155 $statusCode = $status; 156 $statusText = isset(self::$statusCodes[$status]) ? self::$statusCodes[$status] : 'Unknown'; 157 158 } else { 159 list( 160 $statusCode, 161 $statusText 162 ) = explode(' ', $status, 2); 163 } 164 if ($statusCode < 100 || $statusCode > 999) { 165 throw new \InvalidArgumentException('The HTTP status code must be exactly 3 digits'); 166 } 167 168 $this->status = $statusCode; 169 $this->statusText = $statusText; 170 171 } 172 173 /** 174 * Serializes the response object as a string. 175 * 176 * This is useful for debugging purposes. 177 * 178 * @return string 179 */ 180 function __toString() { 181 182 $str = 'HTTP/' . $this->httpVersion . ' ' . $this->getStatus() . ' ' . $this->getStatusText() . "\r\n"; 183 foreach ($this->getHeaders() as $key => $value) { 184 foreach ($value as $v) { 185 $str .= $key . ": " . $v . "\r\n"; 186 } 187 } 188 $str .= "\r\n"; 189 $str .= $this->getBodyAsString(); 190 return $str; 191 192 } 193 194} 195