Get request headers in PHP

php
tutorial
http
headers
Nabil Hassen
Nabil Hassen
Nov 27, 2025
Get request headers in PHP
Last updated on Nov 27, 2025
Table of contents:

How to Get HTTP Request Headers in PHP

You want to read HTTP request headers from PHP code running behind a web server. This guide walks through the practical ways to do that: directly via $_SERVER, using getallheaders or apache_request_headers, and via PSR-7 request objects that many modern frameworks use.

Using getallheaders and apache_request_headers

PHP also provides functions that return all request headers directly as an associative array.

  • getallheaders()
  • apache_request_headers()

getallheaders is an alias of apache_request_headers and both fetch all HTTP request headers from the current request.

Basic usage of getallheaders

If getallheaders is available in your environment, this is usually the easiest way to see everything the client sent:

$headers = getallheaders();
 
foreach ($headers as $name => $value) {
echo $name . ': ' . $value . PHP_EOL;
}

What this does:

  • Calls getallheaders() to retrieve an associative array of all headers.
  • Iterates and prints each header.
  • Header names come back in a normalized form (for example Accept-Language, User-Agent, Content-Type).

When this is appropriate:

  • You are running under Apache, FastCGI, or FPM where these functions are available.
  • You do not want to deal with the $_SERVER naming convention manually.
  • You want a full dump of headers for debugging or logging.

In some environments (for example plain CLI, or PHP built without the Apache related extension) these functions may not exist, and calling them would trigger a fatal error.

Fallback polyfill for getallheaders

On servers where getallheaders is missing (for example some nginx setups), a common pattern is to provide a compatible function that rebuilds the headers from $_SERVER.

if (!function_exists('getallheaders')) {
function getallheaders(): array
{
$headers = [];
 
foreach ($_SERVER as $name => $value) {
if (str_starts_with($name, 'HTTP_')) {
$headerName = substr($name, 5);
$headerName = str_replace('_', ' ', $headerName);
$headerName = ucwords(strtolower($headerName));
$headerName = str_replace(' ', '-', $headerName);
 
$headers[$headerName] = $value;
}
}
 
if (isset($_SERVER['CONTENT_TYPE'])) {
$headers['Content-Type'] = $_SERVER['CONTENT_TYPE'];
}
 
if (isset($_SERVER['CONTENT_LENGTH'])) {
$headers['Content-Length'] = $_SERVER['CONTENT_LENGTH'];
}
 
return $headers;
}
}
 
foreach (getallheaders() as $name => $value) {
echo $name . ': ' . $value . PHP_EOL;
}

Why this is useful:

  • Your application can call getallheaders() unconditionally.
  • On hosts that provide the native function, you get the built-in implementation.
  • On hosts that do not, you still get a compatible behavior based on $_SERVER.

Note on Authorization:

  • getallheaders often includes the Authorization header where $_SERVER alone does not.
  • If you care about auth headers, test this behavior on your specific server and PHP setup.

Accessing a single header via getallheaders

Request header names are case insensitive, but the array keys returned by getallheaders have a specific casing (for example User-Agent). To avoid guessing, you can normalize them before lookup.

<?php
$headers = getallheaders();
 
// Normalize keys to lowercase for case insensitive lookup
$headersLower = array_change_key_case($headers, CASE_LOWER);
 
$userAgent = $headersLower['user-agent'] ?? null;
$authHeader = $headersLower['authorization'] ?? null;
 
echo 'User-Agent: ' . ($userAgent ?? '[none]') . PHP_EOL;
echo 'Authorization: ' . ($authHeader ?? '[none]') . PHP_EOL;

What matters here:

  • array_change_key_case creates a new array with lowercase keys.
  • You can then look up any header using a consistent key, like 'authorization'.
  • This pattern avoids subtle bugs when a server or extension uses slightly different header name capitalization.

Reading request headers from $_SERVER

PHP exposes incoming request headers through the $_SERVER superglobal. For most headers, PHP creates keys that:

  • Start with HTTP_
  • Use uppercase letters
  • Replace hyphens with underscores

For example, the header:

Accept-Language: en-US,en;q=0.9

is usually available as:

$_SERVER['HTTP_ACCEPT_LANGUAGE'];

This behavior is documented in the PHP manual, which explains that request headers are mapped to $_SERVER entries following this naming pattern.

Reading specific headers from $_SERVER

Minimal example that reads a few common headers and a custom one:

// Common request headers
$acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? null;
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;
 
// Custom header: X-Requested-With
$requestedWith = $_SERVER['HTTP_X_REQUESTED_WITH'] ?? null;
 
echo "Accept-Language: " . ($acceptLanguage ?? '[none]') . PHP_EOL;
echo "User-Agent: " . ($userAgent ?? '[none]') . PHP_EOL;
echo "X-Requested-With: " . ($requestedWith ?? '[none]') . PHP_EOL;

What this does:

  • Reads values from $_SERVER using the HTTP_ prefix and uppercase names with underscores.
  • Uses the null coalescing operator ?? so the script does not throw notices if a header is missing.
  • Prints each header as plain text.

Directly using $_SERVER is simple and works in any SAPI where PHP exposed the header as an environment variable. However, you have to know the exact key name or build it yourself.

Building a full header list from $_SERVER

If you want all headers but cannot rely on getallheaders, you can reconstruct them by scanning $_SERVER for keys that start with HTTP_.

Here is a small helper that:

  • Turns HTTP_ACCEPT_LANGUAGE into Accept-Language
  • Collects all such headers into an associative array
  • Adds Content-Type and Content-Length, which may be exposed without the HTTP_ prefix
<?php
 
function headers_from_server(): array
{
$headers = [];
 
foreach ($_SERVER as $name => $value) {
if (str_starts_with($name, 'HTTP_')) {
$headerName = substr($name, 5); // remove "HTTP_"
$headerName = str_replace('_', ' ', $headerName);
$headerName = ucwords(strtolower($headerName));
$headerName = str_replace(' ', '-', $headerName);
 
$headers[$headerName] = $value;
}
}
 
// Some headers are not prefixed with HTTP_
if (isset($_SERVER['CONTENT_TYPE'])) {
$headers['Content-Type'] = $_SERVER['CONTENT_TYPE'];
}
 
if (isset($_SERVER['CONTENT_LENGTH'])) {
$headers['Content-Length'] = $_SERVER['CONTENT_LENGTH'];
}
 
return $headers;
}
 
$headers = headers_from_server();
 
foreach ($headers as $name => $value) {
echo $name . ': ' . $value . PHP_EOL;
}

Points to notice:

  • str_starts_with requires PHP 8.
  • The transformation normalizes header names into the common Title-Case-Format.
  • This gives you a consistent array of headers even in environments where getallheaders is not defined.

Keep in mind that some server setups may still hide specific headers (for example Authorization) unless configured to forward them into the CGI environment.

Quick note about environment and CLI

Request headers only exist for real HTTP requests. If you run your script from the command line:

  • $_SERVER will not contain meaningful HTTP header entries for a normal CLI invocation.
  • getallheaders or apache_request_headers may not even be defined or may not return anything useful if there is no actual HTTP request in progress.

So any code that relies on headers should either:

  • Be executed only in an HTTP context, or
  • Be defensive and handle the case where headers are missing or functions are not available.
Nabil Hassen
Nabil Hassen
Full Stack Web Developer

Stay Updated.

I'll you email you as soon as new, fresh content is published.

Thanks for subscribing to my blog.

Latest Posts