Response.php
5.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<?php
/**
* @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)
* @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;
use function gettype;
use function is_float;
use function is_numeric;
use function is_scalar;
use function sprintf;
/**
* 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;
const MIN_STATUS_CODE_VALUE = 100;
const MAX_STATUS_CODE_VALUE = 599;
/**
* Map of standard HTTP status code/reason phrases
*
* @var array
*/
private $phrases = [
// INFORMATIONAL CODES
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing',
103 => 'Early Hints',
// SUCCESS CODES
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status',
208 => 'Already Reported',
226 => 'IM Used',
// REDIRECTION CODES
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
306 => 'Switch Proxy', // Deprecated to 306 => '(Unused)'
307 => 'Temporary Redirect',
308 => 'Permanent Redirect',
// 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',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Payload Too Large',
414 => 'URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Range Not Satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot',
421 => 'Misdirected Request',
422 => 'Unprocessable Entity',
423 => 'Locked',
424 => 'Failed Dependency',
425 => 'Too Early',
426 => 'Upgrade Required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
431 => 'Request Header Fields Too Large',
444 => 'Connection Closed Without Response',
451 => 'Unavailable For Legal Reasons',
// SERVER ERROR
499 => 'Client Closed Request',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported',
506 => 'Variant Also Negotiates',
507 => 'Insufficient Storage',
508 => 'Loop Detected',
510 => 'Not Extended',
511 => 'Network Authentication Required',
599 => 'Network Connect Timeout Error',
];
/**
* @var string
*/
private $reasonPhrase;
/**
* @var int
*/
private $statusCode;
/**
* @param string|resource|StreamInterface $body Stream identifier and/or actual stream resource
* @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 = [])
{
$this->setStatusCode($status);
$this->stream = $this->getStream($body, 'wb+');
$this->setHeaders($headers);
}
/**
* {@inheritdoc}
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* {@inheritdoc}
*/
public function getReasonPhrase()
{
return $this->reasonPhrase;
}
/**
* {@inheritdoc}
*/
public function withStatus($code, $reasonPhrase = '')
{
$new = clone $this;
$new->setStatusCode($code, $reasonPhrase);
return $new;
}
/**
* Set a valid status code.
*
* @param int $code
* @param string $reasonPhrase
* @throws InvalidArgumentException on an invalid status code.
*/
private function setStatusCode($code, $reasonPhrase = '')
{
if (! is_numeric($code)
|| is_float($code)
|| $code < static::MIN_STATUS_CODE_VALUE
|| $code > static::MAX_STATUS_CODE_VALUE
) {
throw new InvalidArgumentException(sprintf(
'Invalid status code "%s"; must be an integer between %d and %d, inclusive',
is_scalar($code) ? $code : gettype($code),
static::MIN_STATUS_CODE_VALUE,
static::MAX_STATUS_CODE_VALUE
));
}
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;
}
}