HTTP Status Codes — PHP source
Searchable reference of all HTTP status codes with meaning, category, and usage notes.
This is the PHP implementation — the same logic the interactive tool runs, in a shareable, citable form.
<?php
declare(strict_types=1);
/**
* HTTP Status Codes reference — pure, deterministic data + filter.
*
* Language: PHP 8.1+ (enums, readonly properties, first-class closure syntax)
* CosmoDev polyglot showcase port of `http-status-codes`,
* ported from src/lib/httpStatus.ts.
* Display source — part of CosmoDev's polyglot tool pages.
*
* No I/O, no Composer dependencies — standard library only. Behavior matches
* the TypeScript lib: same inputs produce identical outputs.
*/
namespace CosmoDev\HttpStatus;
/**
* The five broad families an HTTP status code can belong to.
*
* A backed enum (string cases) lets us resolve an incoming category name via
* tryFrom(): a known name returns the case, an unknown name returns null,
* which is exactly how the filter yields an empty result.
*/
enum StatusCategory: string
{
case Informational = 'Informational';
case Success = 'Success';
case Redirection = 'Redirection';
case ClientError = 'Client Error';
case ServerError = 'Server Error';
}
/**
* A single HTTP status code entry. Readonly constructor promotion makes every
* property immutable after construction — the reference table never changes.
*/
final readonly class StatusCode
{
public function __construct(
public int $code,
public string $reason,
public StatusCategory $category,
public string $description,
) {}
}
/**
* Standard + widely-implemented HTTP status codes across 1xx–5xx.
*
* Returned as a fresh array on every call so callers can freely slice, splice,
* or reorder without mutating shared state. Order is grouped by category and
* ascending within each group.
*
* @return list<StatusCode>
*/
function status_codes(): array
{
return [
// --- 1xx Informational ---
new StatusCode(100, 'Continue', StatusCategory::Informational, 'The server has received the request headers and the client should proceed to send the request body.'),
new StatusCode(101, 'Switching Protocols', StatusCategory::Informational, 'The requester has asked the server to switch protocols and the server has agreed to do so.'),
new StatusCode(103, 'Early Hints', StatusCategory::Informational, 'Used to return some response headers before the final HTTP message so the browser can start preloading resources.'),
// --- 2xx Success ---
new StatusCode(200, 'OK', StatusCategory::Success, 'Standard response for a successful HTTP request.'),
new StatusCode(201, 'Created', StatusCategory::Success, 'The request succeeded and a new resource was created.'),
new StatusCode(202, 'Accepted', StatusCategory::Success, 'The request has been accepted for processing but is not yet complete.'),
new StatusCode(203, 'Non-Authoritative Information', StatusCategory::Success, 'The returned metadata originated from a local or third-party copy rather than the origin server.'),
new StatusCode(204, 'No Content', StatusCategory::Success, 'The server processed the request successfully but is not returning any content.'),
new StatusCode(205, 'Reset Content', StatusCategory::Success, 'The server asks the client to reset the document view that sent the request.'),
new StatusCode(206, 'Partial Content', StatusCategory::Success, 'The server is delivering only part of the resource because the client requested a byte range.'),
new StatusCode(207, 'Multi-Status', StatusCategory::Success, 'WebDAV: conveys information about multiple resources in a single XML response.'),
new StatusCode(208, 'Already Reported', StatusCategory::Success, 'WebDAV: the members of a DAV binding have already been enumerated in a previous reply.'),
new StatusCode(226, 'IM Used', StatusCategory::Success, 'The server fulfilled a GET request using an instance-manipulation applied to the current instance.'),
// --- 3xx Redirection ---
new StatusCode(300, 'Multiple Choices', StatusCategory::Redirection, 'The request has more than one possible response; the user agent can choose among them.'),
new StatusCode(301, 'Moved Permanently', StatusCategory::Redirection, 'This and all future requests should be directed to the given URL.'),
new StatusCode(302, 'Found', StatusCategory::Redirection, 'The resource resides temporarily under a different URL; the method may be changed to GET.'),
new StatusCode(303, 'See Other', StatusCategory::Redirection, 'The response to the request can be found under another URI using a GET request.'),
new StatusCode(304, 'Not Modified', StatusCategory::Redirection, 'The resource has not been modified since the version specified by the request headers.'),
new StatusCode(305, 'Use Proxy', StatusCategory::Redirection, 'The requested resource is available only through a proxy (deprecated).'),
new StatusCode(306, 'Switch Proxy', StatusCategory::Redirection, 'No longer used; originally meant subsequent requests should use a specified proxy.'),
new StatusCode(307, 'Temporary Redirect', StatusCategory::Redirection, 'The request should be repeated with another URL; the request method must not change.'),
new StatusCode(308, 'Permanent Redirect', StatusCategory::Redirection, 'This and all future requests should use another URL; the request method must not change.'),
// --- 4xx Client Error ---
new StatusCode(400, 'Bad Request', StatusCategory::ClientError, 'The server cannot process the request due to a client error such as malformed syntax.'),
new StatusCode(401, 'Unauthorized', StatusCategory::ClientError, 'Authentication is required and has either failed or not been provided.'),
new StatusCode(402, 'Payment Required', StatusCategory::ClientError, 'Reserved for future use; sometimes used for paywalled resources.'),
new StatusCode(403, 'Forbidden', StatusCategory::ClientError, 'The server understood the request but refuses to authorize it.'),
new StatusCode(404, 'Not Found', StatusCategory::ClientError, 'The requested resource could not be found on the server.'),
new StatusCode(405, 'Method Not Allowed', StatusCategory::ClientError, 'The request method is not supported for the requested resource.'),
new StatusCode(406, 'Not Acceptable', StatusCategory::ClientError, 'The requested resource can only generate content not acceptable per the Accept headers.'),
new StatusCode(407, 'Proxy Authentication Required', StatusCategory::ClientError, 'The client must first authenticate itself with the proxy.'),
new StatusCode(408, 'Request Timeout', StatusCategory::ClientError, 'The server timed out waiting for the client to send the request.'),
new StatusCode(409, 'Conflict', StatusCategory::ClientError, 'The request could not be processed because of a conflict with the current state of the resource.'),
new StatusCode(410, 'Gone', StatusCategory::ClientError, 'The resource is no longer available and will not be available again.'),
new StatusCode(411, 'Length Required', StatusCategory::ClientError, 'The request did not specify the length of its content, which is required by the resource.'),
new StatusCode(412, 'Precondition Failed', StatusCategory::ClientError, 'The server does not meet one of the preconditions given in the request headers.'),
new StatusCode(413, 'Content Too Large', StatusCategory::ClientError, 'The request payload is larger than the server is willing or able to process.'),
new StatusCode(414, 'URI Too Long', StatusCategory::ClientError, 'The URI provided was too long for the server to process.'),
new StatusCode(415, 'Unsupported Media Type', StatusCategory::ClientError, 'The request uses a media type the server does not support for the resource.'),
new StatusCode(416, 'Range Not Satisfiable', StatusCategory::ClientError, 'The portion of the resource requested in the Range header cannot be supplied by the server.'),
new StatusCode(417, 'Expectation Failed', StatusCategory::ClientError, 'The server cannot meet the requirements of the Expect request header field.'),
new StatusCode(418, 'I\'m a Teapot', StatusCategory::ClientError, 'RFC 2324 joke status: the server refuses to brew coffee because it is, permanently, a teapot.'),
new StatusCode(421, 'Misdirected Request', StatusCategory::ClientError, 'The request was directed at a server that is not able to produce a response.'),
new StatusCode(422, 'Unprocessable Content', StatusCategory::ClientError, 'The server understands the content type and syntax but cannot process the contained instructions (WebDAV).'),
new StatusCode(423, 'Locked', StatusCategory::ClientError, 'WebDAV: the source or destination resource of the method is locked.'),
new StatusCode(424, 'Failed Dependency', StatusCategory::ClientError, 'WebDAV: the method could not be performed because the requested action depended on another action that failed.'),
new StatusCode(425, 'Too Early', StatusCategory::ClientError, 'The server is unwilling to risk processing a request that might be a replay.'),
new StatusCode(428, 'Precondition Required', StatusCategory::ClientError, 'The origin server requires the request to be conditional.'),
new StatusCode(429, 'Too Many Requests', StatusCategory::ClientError, 'The user has sent too many requests in a given time (rate limiting).'),
new StatusCode(431, 'Request Header Fields Too Large', StatusCategory::ClientError, 'The server is unwilling to process the request because its header fields are too large.'),
new StatusCode(451, 'Unavailable For Legal Reasons', StatusCategory::ClientError, 'The resource is unavailable due to legal demands such as government censorship or a takedown.'),
// --- 5xx Server Error ---
new StatusCode(500, 'Internal Server Error', StatusCategory::ServerError, 'A generic error message: the server encountered an unexpected condition.'),
new StatusCode(501, 'Not Implemented', StatusCategory::ServerError, 'The server does not support the functionality required to fulfill the request.'),
new StatusCode(502, 'Bad Gateway', StatusCategory::ServerError, 'The server, acting as a gateway, received an invalid response from an upstream server.'),
new StatusCode(503, 'Service Unavailable', StatusCategory::ServerError, 'The server is currently unavailable, typically because it is overloaded or down for maintenance.'),
new StatusCode(504, 'Gateway Timeout', StatusCategory::ServerError, 'The server, acting as a gateway, timed out waiting for an upstream response.'),
new StatusCode(505, 'HTTP Version Not Supported', StatusCategory::ServerError, 'The server does not support the HTTP protocol version used in the request.'),
new StatusCode(506, 'Variant Also Negotiates', StatusCategory::ServerError, 'Transparent content negotiation for the request resulted in a circular reference.'),
new StatusCode(507, 'Insufficient Storage', StatusCategory::ServerError, 'WebDAV: the server is unable to store the representation needed to complete the request.'),
new StatusCode(508, 'Loop Detected', StatusCategory::ServerError, 'WebDAV: the server detected an infinite loop while processing the request.'),
new StatusCode(510, 'Not Extended', StatusCategory::ServerError, 'Further extensions to the request are required for the server to fulfill it.'),
new StatusCode(511, 'Network Authentication Required', StatusCategory::ServerError, 'The client must authenticate to gain network access, as with a captive portal.'),
];
}
/**
* Filter status codes by a free-text query and an optional category.
*
* - `query` is matched case-insensitively against the numeric code, the reason
* phrase, and the description. An empty/whitespace query returns every code
* (within the chosen category, if one is supplied).
* - `category`, when provided and a known StatusCategory name, restricts the
* pool to that category before the text match. A blank category means "no
* restriction"; an unknown name yields an empty list — matching the TS.
*
* @param string $query Free-text search term.
* @param list<StatusCode> $codes The pool to filter (typically status_codes()).
* @param string|null $category Optional category name; must match a case.
* @return list<StatusCode> Matching codes, in their original order.
*/
function filter_codes(string $query, array $codes, ?string $category = null): array
{
$catName = $category === null ? '' : trim($category);
// Step 1 — restrict to one category. tryFrom() returns null for an unknown
// name, which is why an invalid category produces [] rather than "all".
if ($catName === '') {
$pool = $codes;
} else {
$cat = StatusCategory::tryFrom($catName);
if ($cat === null) {
return [];
}
$pool = array_values(array_filter(
$codes,
fn (StatusCode $c): bool => $c->category === $cat,
));
}
// Step 2 — case-insensitive substring match across code/reason/description.
// mb_strtolower is used for correctness on arbitrary text; the data here is
// ASCII, so it coincides with strtolower.
$q = mb_strtolower(trim($query));
if ($q === '') {
return $pool;
}
return array_values(array_filter(
$pool,
fn (StatusCode $c): bool =>
str_contains((string) $c->code, $q)
|| str_contains(mb_strtolower($c->reason), $q)
|| str_contains(mb_strtolower($c->description), $q),
));
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →