Home / Blog / URL HTTP & cURL

PHP HTTP clients

PHP HTTP Response Headers: Scope and Current APIs

Read HTTP response headers in PHP, handle scope and redirects, and migrate from the deprecated variable to the current response-header API.

Http_response_header

In PHP, the historical variable $http_response_header contains headers from an HTTP stream-wrapper request in the scope where that request occurred. It is not a browser JavaScript variable and not a replacement for PHP’s outgoing header() function. The PHP manual marks the variable deprecated as of PHP 8.5 and directs new code to http_get_last_response_headers(), available since PHP 8.4.

Capture headers immediately after the request

The example uses a loopback fixture you control. It reads an HTTP response with a short timeout and then obtains the response headers. The compatibility branch is for older PHP installations; projects targeting PHP 8.4 or later can use the function directly.

<?php
$context = stream_context_create(['http' => [
    'timeout' => 5,
    'ignore_errors' => true,
]]);
$body = file_get_contents('http://127.0.0.1:8080/example', false, $context);
$headers = function_exists('http_get_last_response_headers')
    ? (http_get_last_response_headers() ?? [])
    : ($http_response_header ?? []);
if ($body === false) {
    throw new RuntimeException('The HTTP request did not return a body.');
}
foreach ($headers as $line) {
    echo $line, PHP_EOL;
}

Run this code with a PHP environment and an intentional local test server. A plain browser code formatter cannot execute PHP. The ignore_errors option asks the stream wrapper to retrieve a response body for HTTP error statuses; it does not turn those statuses into business success. Network failure still needs error handling, and a successful read can still contain a 404 or 500 response.

Why the old variable can be undefined

If a request happens inside a function, inspect the historical variable in that same function and return the captured result explicitly. Reading an unrelated global variable after the function returns is not equivalent. Capture headers before making another request, because the API describes the last response. An application that interleaves requests should associate each response body and its headers in one result object.

When migrating, check the actual PHP runtime used by the web server as well as your command-line runtime. They may run different versions or configurations. Test function_exists in the deployed environment and remove an old compatibility branch only when your supported-version policy permits it.

Parse without losing repeated fields

Header arrays contain status lines as well as field lines. A redirect chain can include more than one response block. Track the final block intentionally instead of assuming the first status is the final result. Split a field at its first colon only, because a value may itself contain colons. Compare field names without case sensitivity, and retain repeated values rather than silently overwriting them in a simple dictionary.

Set-Cookie is a practical reason to preserve repeated fields separately. Combining every occurrence with commas is not a universally safe normalization. Avoid logging complete authentication or cookie values while debugging; record the field name and a redacted description when the actual secret is unnecessary.

Use three predictable fixtures

  1. A 200 response with a short JSON body and two ordinary headers should preserve both the body and the fields.
  2. A 302 response followed by a 200 should be interpreted as a chain, with the final status selected deliberately.
  3. A 404 with a small error body should remain an HTTP error in your application logic even when the body can be read.

Also test a refused local connection or a controlled timeout. Distinguish that transport failure from a valid HTTP response containing an error status. Do not display a previous successful response after a later request fails. Store the status, headers, body and error for each operation together.

Choosing a client

The stream wrapper is useful for simple requests, but an application may need a fuller client library for structured errors, connection options or request middleware. Regardless of library, define allowed destinations before accepting arbitrary user-supplied URLs in server-side code. A local pasted-header parser does not perform that request and therefore cannot validate network access or server behavior.

References

PHP historical response-header variable and current response-header function. The example is a PHP workflow; it is not presented as browser-executed PHP.