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