Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
15 / 15 |
|
100.00% |
9 / 9 |
CRAP | |
100.00% |
1 / 1 |
StatusCode | |
100.00% |
15 / 15 |
|
100.00% |
9 / 9 |
15 | |
100.00% |
1 / 1 |
getCode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getReasonPhrase | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCategory | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
6 | |||
isInformational | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isSuccess | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isRedirection | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isClientError | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isServerError | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isError | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | /** |
6 | * This file is part of php-fast-forward/http-message. |
7 | * |
8 | * This source file is subject to the license bundled |
9 | * with this source code in the file LICENSE. |
10 | * |
11 | * @link https://github.com/php-fast-forward/http-message |
12 | * @copyright Copyright (c) 2025 Felipe Sayão Lobato Abreu <github@mentordosnerds.com> |
13 | * @license https://opensource.org/licenses/MIT MIT License |
14 | */ |
15 | |
16 | namespace FastForward\Http\Message; |
17 | |
18 | /** |
19 | * Enum StatusCode. |
20 | * |
21 | * Defines HTTP status codes in accordance with the IETF RFC 9110 and related specifications. |
22 | * This enum provides a structured representation of common HTTP response codes, grouped by their respective categories: |
23 | * |
24 | * - Informational (1xx) |
25 | * - Successful (2xx) |
26 | * - Redirection (3xx) |
27 | * - Client Errors (4xx) |
28 | * - Server Errors (5xx) |
29 | * |
30 | * All status codes MUST adhere to the official HTTP specification and SHALL be used consistently within HTTP responses. |
31 | * |
32 | * @package FastForward\Http\Message |
33 | */ |
34 | enum StatusCode: int |
35 | { |
36 | // Informational 1xx |
37 | |
38 | /** @var int The server has received the request headers and the client SHOULD proceed to send the request body. */ |
39 | case Continue = 100; |
40 | |
41 | /** @var int The requester has asked the server to switch protocols. */ |
42 | case SwitchingProtocols = 101; |
43 | |
44 | /** @var int The server has received and is processing the request, but no response is available yet. */ |
45 | case Processing = 102; |
46 | |
47 | /** @var int Used to return some response headers before the final HTTP message. */ |
48 | case EarlyHints = 103; |
49 | |
50 | // Successful 2xx |
51 | |
52 | /** @var int The request has succeeded. */ |
53 | case Ok = 200; |
54 | |
55 | /** @var int The request has been fulfilled and has resulted in the creation of a new resource. */ |
56 | case Created = 201; |
57 | |
58 | /** @var int The request has been accepted for processing, but the processing has not been completed. */ |
59 | case Accepted = 202; |
60 | |
61 | /** @var int The request was successful, but the enclosed payload has been modified from that of the origin server. */ |
62 | case NonAuthoritativeInformation = 203; |
63 | |
64 | /** @var int The server successfully processed the request and is not returning any content. */ |
65 | case NoContent = 204; |
66 | |
67 | /** @var int The server successfully processed the request, but is not returning any content, and requests that the requester reset the document view. */ |
68 | case ResetContent = 205; |
69 | |
70 | /** @var int The server is delivering only part of the resource due to a range header sent by the client. */ |
71 | case PartialContent = 206; |
72 | |
73 | /** @var int The message body that follows is an XML message and can contain a number of separate response codes. */ |
74 | case MultiStatus = 207; |
75 | |
76 | /** @var int The members of a DAV binding have already been enumerated in a previous reply to this request, and are not being included again. */ |
77 | case AlreadyReported = 208; |
78 | |
79 | /** @var int The server has fulfilled a request for the resource, and the response is a representation of the result of one or more instance-manipulations. */ |
80 | case ImUsed = 226; |
81 | |
82 | // Redirection 3xx |
83 | |
84 | /** @var int Indicates multiple options for the resource from which the client may choose. */ |
85 | case MultipleChoices = 300; |
86 | |
87 | /** @var int This and all future requests SHOULD be directed to the given URI. */ |
88 | case MovedPermanently = 301; |
89 | |
90 | /** @var int The resource resides temporarily under a different URI. */ |
91 | case Found = 302; |
92 | |
93 | /** @var int The response to the request can be found under another URI using a GET method. */ |
94 | case SeeOther = 303; |
95 | |
96 | /** @var int Indicates the resource has not been modified since the version specified by the request headers. */ |
97 | case NotModified = 304; |
98 | |
99 | /** @var int The requested resource is only available through a proxy, whose address is provided in the response. */ |
100 | case UseProxy = 305; |
101 | |
102 | /** @var int Reserved for future use. */ |
103 | case Reserved = 306; |
104 | |
105 | /** @var int Instructs the client to repeat the request with a different URI. */ |
106 | case TemporaryRedirect = 307; |
107 | |
108 | /** @var int The request and all future requests SHOULD be repeated using another URI. */ |
109 | case PermanentRedirect = 308; |
110 | |
111 | // Client Errors 4xx |
112 | |
113 | /** @var int The server cannot process the request due to a client error. */ |
114 | case BadRequest = 400; |
115 | |
116 | /** @var int Authentication is required and has failed or has not yet been provided. */ |
117 | case Unauthorized = 401; |
118 | |
119 | /** @var int Payment is required to access the requested resource. */ |
120 | case PaymentRequired = 402; |
121 | |
122 | /** @var int The client does not have permission to access the resource. */ |
123 | case Forbidden = 403; |
124 | |
125 | /** @var int The requested resource could not be found. */ |
126 | case NotFound = 404; |
127 | |
128 | /** @var int A request method is not supported for the requested resource. */ |
129 | case MethodNotAllowed = 405; |
130 | |
131 | /** @var int The requested resource is capable of generating only content not acceptable according to the Accept headers. */ |
132 | case NotAcceptable = 406; |
133 | |
134 | /** @var int Proxy authentication is required to access the resource. */ |
135 | case ProxyAuthenticationRequired = 407; |
136 | |
137 | /** @var int The client did not produce a request within the time that the server was prepared to wait. */ |
138 | case RequestTimeout = 408; |
139 | |
140 | /** @var int The request could not be completed due to a conflict with the current state of the resource. */ |
141 | case Conflict = 409; |
142 | |
143 | /** @var int The resource requested is no longer available and will not be available again. */ |
144 | case Gone = 410; |
145 | |
146 | /** @var int The request did not specify the length of its content, which is required by the requested resource. */ |
147 | case LengthRequired = 411; |
148 | |
149 | /** @var int The server does not meet one of the preconditions specified by the requester. */ |
150 | case PreconditionFailed = 412; |
151 | |
152 | /** @var int The request is larger than the server is willing or able to process. */ |
153 | case PayloadTooLarge = 413; |
154 | |
155 | /** @var int The URI provided was too long for the server to process. */ |
156 | case UriTooLong = 414; |
157 | |
158 | /** @var int The server does not support the media format of the requested data. */ |
159 | case UnsupportedMediaType = 415; |
160 | |
161 | /** @var int The client has asked for a portion of the file, but the server cannot supply that portion. */ |
162 | case RangeNotSatisfiable = 416; |
163 | |
164 | /** @var int The server cannot meet the expectations specified in the Expect request header. */ |
165 | case ExpectationFailed = 417; |
166 | |
167 | /** @var int This code is returned by HTCPCP-compliant teapots. */ |
168 | case ImATeapot = 418; |
169 | |
170 | /** @var int The request was directed at a server that is not able to produce a response. */ |
171 | case MisdirectedRequest = 421; |
172 | |
173 | /** @var int The request was well-formed but was unable to be followed due to semantic errors. */ |
174 | case UnprocessableEntity = 422; |
175 | |
176 | /** @var int The resource that is being accessed is locked. */ |
177 | case Locked = 423; |
178 | |
179 | /** @var int The request failed due to failure of a previous request. */ |
180 | case FailedDependency = 424; |
181 | |
182 | /** @var int Indicates the server is unwilling to risk processing a request that might be replayed. */ |
183 | case TooEarly = 425; |
184 | |
185 | /** @var int The client should switch to a different protocol such as TLS/1.0. */ |
186 | case UpgradeRequired = 426; |
187 | |
188 | /** @var int The origin server requires the request to be conditional. */ |
189 | case PreconditionRequired = 428; |
190 | |
191 | /** @var int The user has sent too many requests in a given amount of time. */ |
192 | case TooManyRequests = 429; |
193 | |
194 | /** @var int The server is unwilling to process the request because its header fields are too large. */ |
195 | case RequestHeaderFieldsTooLarge = 431; |
196 | |
197 | /** @var int The requested resource is unavailable for legal reasons. */ |
198 | case UnavailableForLegalReasons = 451; |
199 | |
200 | // Server Errors 5xx |
201 | |
202 | /** @var int The server encountered an unexpected condition that prevented it from fulfilling the request. */ |
203 | case InternalServerError = 500; |
204 | |
205 | /** @var int The server does not support the functionality required to fulfill the request. */ |
206 | case NotImplemented = 501; |
207 | |
208 | /** @var int The server, while acting as a gateway or proxy, received an invalid response from the upstream server. */ |
209 | case BadGateway = 502; |
210 | |
211 | /** @var int The server is currently unavailable due to maintenance or overload. */ |
212 | case ServiceUnavailable = 503; |
213 | |
214 | /** @var int The server did not receive a timely response from an upstream server. */ |
215 | case GatewayTimeout = 504; |
216 | |
217 | /** @var int The server does not support the HTTP protocol version used in the request. */ |
218 | case VersionNotSupported = 505; |
219 | |
220 | /** @var int Transparent content negotiation for the request results in a circular reference. */ |
221 | case VariantAlsoNegotiates = 506; |
222 | |
223 | /** @var int The server is unable to store the representation needed to complete the request. */ |
224 | case InsufficientStorage = 507; |
225 | |
226 | /** @var int The server detected an infinite loop while processing a request. */ |
227 | case LoopDetected = 508; |
228 | |
229 | /** @var int Further extensions to the request are required for the server to fulfill it. */ |
230 | case NotExtended = 510; |
231 | |
232 | /** @var int The client needs to authenticate to gain network access. */ |
233 | case NetworkAuthenticationRequired = 511; |
234 | |
235 | /** |
236 | * Returns the numeric HTTP status code. |
237 | * |
238 | * @return int the numeric status code as defined by the HTTP specification |
239 | */ |
240 | public function getCode(): int |
241 | { |
242 | return $this->value; |
243 | } |
244 | |
245 | /** |
246 | * Returns a human-readable description of the status code. |
247 | * |
248 | * The description is derived from the enum name, replacing underscores with spaces and capitalizing each word. |
249 | * |
250 | * @return string the reason phrase corresponding to the status code |
251 | */ |
252 | public function getReasonPhrase(): string |
253 | { |
254 | return preg_replace('/(?<!^)[A-Z]/', ' $0', $this->name); |
255 | } |
256 | |
257 | /** |
258 | * Returns the category of the status code. |
259 | * |
260 | * Categories are based on the first digit of the status code: |
261 | * - 1: Informational |
262 | * - 2: Success |
263 | * - 3: Redirection |
264 | * - 4: Client Error |
265 | * - 5: Server Error |
266 | */ |
267 | public function getCategory(): string |
268 | { |
269 | return match (intdiv($this->value, 100)) { |
270 | 1 => 'Informational', |
271 | 2 => 'Success', |
272 | 3 => 'Redirection', |
273 | 4 => 'Client Error', |
274 | 5 => 'Server Error', |
275 | }; |
276 | } |
277 | |
278 | /** |
279 | * Returns true if the status code is informational (1xx). |
280 | */ |
281 | public function isInformational(): bool |
282 | { |
283 | return 1 === intdiv($this->value, 100); |
284 | } |
285 | |
286 | /** |
287 | * Returns true if the status code indicates success (2xx). |
288 | */ |
289 | public function isSuccess(): bool |
290 | { |
291 | return 2 === intdiv($this->value, 100); |
292 | } |
293 | |
294 | /** |
295 | * Returns true if the status code indicates redirection (3xx). |
296 | */ |
297 | public function isRedirection(): bool |
298 | { |
299 | return 3 === intdiv($this->value, 100); |
300 | } |
301 | |
302 | /** |
303 | * Returns true if the status code indicates a client error (4xx). |
304 | */ |
305 | public function isClientError(): bool |
306 | { |
307 | return 4 === intdiv($this->value, 100); |
308 | } |
309 | |
310 | /** |
311 | * Returns true if the status code indicates a server error (5xx). |
312 | */ |
313 | public function isServerError(): bool |
314 | { |
315 | return 5 === intdiv($this->value, 100); |
316 | } |
317 | |
318 | /** |
319 | * Returns true if the status code indicates any type of error (client or server). |
320 | */ |
321 | public function isError(): bool |
322 | { |
323 | return $this->isClientError() || $this->isServerError(); |
324 | } |
325 | } |