Skip to content

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 →