2015-08-27 12:03:05 -07:00
< ? php
/**
2018-11-23 12:29:20 +00:00
* @ see https :// github . com / zendframework / zend - diactoros for the canonical source repository
* @ copyright Copyright ( c ) 2015 - 2018 Zend Technologies USA Inc . ( http :// www . zend . com )
2015-08-27 12:03:05 -07:00
* @ license https :// github . com / zendframework / zend - diactoros / blob / master / LICENSE . md New BSD License
*/
namespace Zend\Diactoros ;
use InvalidArgumentException ;
use Psr\Http\Message\ResponseInterface ;
use Psr\Http\Message\StreamInterface ;
2018-11-23 12:29:20 +00:00
use function gettype ;
use function is_float ;
use function is_numeric ;
use function is_scalar ;
use function sprintf ;
2015-08-27 12:03:05 -07:00
/**
* HTTP response encapsulation .
*
* Responses are considered immutable ; all methods that might change state are
* implemented such that they retain the internal state of the current
* message and return a new instance that contains the changed state .
*/
class Response implements ResponseInterface
{
use MessageTrait ;
2017-04-13 15:53:35 +01:00
const MIN_STATUS_CODE_VALUE = 100 ;
const MAX_STATUS_CODE_VALUE = 599 ;
2015-08-27 12:03:05 -07:00
/**
* Map of standard HTTP status code / reason phrases
*
* @ var array
*/
private $phrases = [
// INFORMATIONAL CODES
100 => 'Continue' ,
101 => 'Switching Protocols' ,
102 => 'Processing' ,
2018-11-23 12:29:20 +00:00
103 => 'Early Hints' ,
2015-08-27 12:03:05 -07:00
// SUCCESS CODES
200 => 'OK' ,
201 => 'Created' ,
202 => 'Accepted' ,
203 => 'Non-Authoritative Information' ,
204 => 'No Content' ,
205 => 'Reset Content' ,
206 => 'Partial Content' ,
2017-04-13 15:53:35 +01:00
207 => 'Multi-Status' ,
2015-08-27 12:03:05 -07:00
208 => 'Already Reported' ,
2017-04-13 15:53:35 +01:00
226 => 'IM Used' ,
2015-08-27 12:03:05 -07:00
// REDIRECTION CODES
300 => 'Multiple Choices' ,
301 => 'Moved Permanently' ,
302 => 'Found' ,
303 => 'See Other' ,
304 => 'Not Modified' ,
305 => 'Use Proxy' ,
2017-04-13 15:53:35 +01:00
306 => 'Switch Proxy' , // Deprecated to 306 => '(Unused)'
2015-08-27 12:03:05 -07:00
307 => 'Temporary Redirect' ,
2017-04-13 15:53:35 +01:00
308 => 'Permanent Redirect' ,
2015-08-27 12:03:05 -07:00
// CLIENT ERROR
400 => 'Bad Request' ,
401 => 'Unauthorized' ,
402 => 'Payment Required' ,
403 => 'Forbidden' ,
404 => 'Not Found' ,
405 => 'Method Not Allowed' ,
406 => 'Not Acceptable' ,
407 => 'Proxy Authentication Required' ,
2017-04-13 15:53:35 +01:00
408 => 'Request Timeout' ,
2015-08-27 12:03:05 -07:00
409 => 'Conflict' ,
410 => 'Gone' ,
411 => 'Length Required' ,
412 => 'Precondition Failed' ,
2017-04-13 15:53:35 +01:00
413 => 'Payload Too Large' ,
414 => 'URI Too Long' ,
2015-08-27 12:03:05 -07:00
415 => 'Unsupported Media Type' ,
2017-04-13 15:53:35 +01:00
416 => 'Range Not Satisfiable' ,
2015-08-27 12:03:05 -07:00
417 => 'Expectation Failed' ,
418 => 'I\'m a teapot' ,
2017-04-13 15:53:35 +01:00
421 => 'Misdirected Request' ,
2015-08-27 12:03:05 -07:00
422 => 'Unprocessable Entity' ,
423 => 'Locked' ,
424 => 'Failed Dependency' ,
2018-11-23 12:29:20 +00:00
425 => 'Too Early' ,
2015-08-27 12:03:05 -07:00
426 => 'Upgrade Required' ,
428 => 'Precondition Required' ,
429 => 'Too Many Requests' ,
431 => 'Request Header Fields Too Large' ,
2017-04-13 15:53:35 +01:00
444 => 'Connection Closed Without Response' ,
451 => 'Unavailable For Legal Reasons' ,
2015-08-27 12:03:05 -07:00
// SERVER ERROR
2017-04-13 15:53:35 +01:00
499 => 'Client Closed Request' ,
2015-08-27 12:03:05 -07:00
500 => 'Internal Server Error' ,
501 => 'Not Implemented' ,
502 => 'Bad Gateway' ,
503 => 'Service Unavailable' ,
2017-04-13 15:53:35 +01:00
504 => 'Gateway Timeout' ,
505 => 'HTTP Version Not Supported' ,
2015-08-27 12:03:05 -07:00
506 => 'Variant Also Negotiates' ,
507 => 'Insufficient Storage' ,
508 => 'Loop Detected' ,
2017-04-13 15:53:35 +01:00
510 => 'Not Extended' ,
2015-08-27 12:03:05 -07:00
511 => 'Network Authentication Required' ,
2017-04-13 15:53:35 +01:00
599 => 'Network Connect Timeout Error' ,
2015-08-27 12:03:05 -07:00
];
/**
* @ var string
*/
2018-11-23 12:29:20 +00:00
private $reasonPhrase ;
2015-08-27 12:03:05 -07:00
/**
* @ var int
*/
2017-04-13 15:53:35 +01:00
private $statusCode ;
2015-08-27 12:03:05 -07:00
/**
2017-04-13 15:53:35 +01:00
* @ param string | resource | StreamInterface $body Stream identifier and / or actual stream resource
2015-08-27 12:03:05 -07:00
* @ param int $status Status code for the response , if any .
* @ param array $headers Headers for the response , if any .
* @ throws InvalidArgumentException on any invalid element .
*/
public function __construct ( $body = 'php://memory' , $status = 200 , array $headers = [])
{
2017-04-13 15:53:35 +01:00
$this -> setStatusCode ( $status );
$this -> stream = $this -> getStream ( $body , 'wb+' );
$this -> setHeaders ( $headers );
2015-08-27 12:03:05 -07:00
}
/**
* { @ inheritdoc }
*/
public function getStatusCode ()
{
return $this -> statusCode ;
}
/**
* { @ inheritdoc }
*/
public function getReasonPhrase ()
{
return $this -> reasonPhrase ;
}
/**
* { @ inheritdoc }
*/
public function withStatus ( $code , $reasonPhrase = '' )
{
$new = clone $this ;
2018-11-23 12:29:20 +00:00
$new -> setStatusCode ( $code , $reasonPhrase );
2015-08-27 12:03:05 -07:00
return $new ;
}
/**
2017-04-13 15:53:35 +01:00
* Set a valid status code .
2015-08-27 12:03:05 -07:00
*
2017-04-13 15:53:35 +01:00
* @ param int $code
2018-11-23 12:29:20 +00:00
* @ param string $reasonPhrase
2015-08-27 12:03:05 -07:00
* @ throws InvalidArgumentException on an invalid status code .
*/
2018-11-23 12:29:20 +00:00
private function setStatusCode ( $code , $reasonPhrase = '' )
2015-08-27 12:03:05 -07:00
{
if ( ! is_numeric ( $code )
|| is_float ( $code )
2017-04-13 15:53:35 +01:00
|| $code < static :: MIN_STATUS_CODE_VALUE
|| $code > static :: MAX_STATUS_CODE_VALUE
2015-08-27 12:03:05 -07:00
) {
throw new InvalidArgumentException ( sprintf (
2017-04-13 15:53:35 +01:00
'Invalid status code "%s"; must be an integer between %d and %d, inclusive' ,
2018-11-23 12:29:20 +00:00
is_scalar ( $code ) ? $code : gettype ( $code ),
2017-04-13 15:53:35 +01:00
static :: MIN_STATUS_CODE_VALUE ,
static :: MAX_STATUS_CODE_VALUE
2015-08-27 12:03:05 -07:00
));
}
2018-11-23 12:29:20 +00:00
if ( ! is_string ( $reasonPhrase )) {
throw new InvalidArgumentException ( sprintf (
'Unsupported response reason phrase; must be a string, received %s' ,
is_object ( $reasonPhrase ) ? get_class ( $reasonPhrase ) : gettype ( $reasonPhrase )
));
}
if ( $reasonPhrase === '' && isset ( $this -> phrases [ $code ])) {
$reasonPhrase = $this -> phrases [ $code ];
}
$this -> reasonPhrase = $reasonPhrase ;
$this -> statusCode = ( int ) $code ;
2015-08-27 12:03:05 -07:00
}
}