PHP header() Function: Everything You Need to Know
As a PHP developer, you may need to manipulate HTTP headers in your web application. The header() function is a powerful tool that allows you to set HTTP
Every HTTP response a web server sends has two parts: a set of headers (metadata such as the content type, caching rules, and status code) followed by the response body (the HTML, JSON, image, or file the browser receives). PHP's header() function lets you write those headers from your script — so you can redirect users, serve downloads, set the content type, control caching, and send custom status codes.
This guide covers the syntax and parameters of header(), the one rule that trips up almost everyone (the "headers already sent" error), and the most common real-world recipes.
What is the header() Function?
header() is a built-in PHP function that sends a raw HTTP header to the client. A header is a single line such as Content-Type: text/html or Location: /login that the browser reads before the page body. Because the headers come first in the response, header() only works while PHP is still building that header section — see the "headers already sent" rule below.
Syntax and Parameters
header(string $header, bool $replace = true, int $response_code = 0): void| Parameter | Type | Description |
|---|---|---|
$header | string | The header line to send, e.g. "Content-Type: application/json". |
$replace | bool | Whether this call replaces a previous header of the same name. When false, multiple headers of the same name are sent. Defaults to true. |
$response_code | int | Forces the HTTP status code of the response. 0 (the default) means "leave the status unchanged". |
The function returns nothing (void). It does not tell you whether the header was accepted — if output was already sent, it raises a warning instead.
Setting a header
The simplest use is declaring what kind of content the response contains. This is essential when your script returns JSON, XML, plain text, or a file instead of HTML:
<?php
header("Content-Type: application/json");
echo json_encode(["status" => "ok", "id" => 42]);The Content-Type header tells the browser to treat the body as JSON, so it parses {"status":"ok","id":42} as data rather than rendering it as a web page.
The "headers already sent" rule
This is the single most important thing to know about header(): it must be called before any output leaves your script. Output includes HTML, echo/print, var_dump(), and even a stray space or blank line before the opening <?php tag. Once one byte of the body has been sent, the header section is closed and PHP raises:
Warning: Cannot modify header information - headers already sentYou have two ways to avoid it:
<?php
// 1. Check first — useful when a header is optional
if (!headers_sent()) {
header("X-Powered-By: MyApp");
}
// 2. Buffer output so nothing is flushed until you choose to
ob_start(); // capture everything that gets echoed
echo "page content...";
header("X-Cache: MISS"); // still works — body is held in the buffer
ob_end_flush(); // now send headers + buffered body togetherA common cause is an editor saving the file with a UTF-8 BOM or a newline after ?>. Omitting the closing ?> tag entirely in pure-PHP files is the recommended way to avoid that.
Common use cases
Redirecting to another URL
Send a Location header, then stop the script so no further code runs:
<?php
header("Location: https://example.com/login");
exit; // always exit after a redirectBy default this is a 302 Found (temporary) redirect. For a permanent move, pass 301 as the status code so search engines update their index:
<?php
// 301 Moved Permanently
header("Location: https://example.com/new-page", true, 301);
exit;Sending a custom status code
You can set a status without redirecting — for an API returning "not found", for example:
<?php
header("HTTP/1.1 404 Not Found");
// or, more portably:
header("Status: 404 Not Found", true, 404);
echo "Resource not found";For status codes specifically, the dedicated http_response_code() function is clearer and easier to read.
Forcing a file download
Combine Content-Type with Content-Disposition: attachment to make the browser save the file instead of displaying it:
<?php
$file = "report.pdf";
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=\"$file\"");
header("Content-Length: " . filesize($file));
readfile($file); // stream the file to the client
exit;See readfile() for streaming the file contents to the output.
Controlling browser caching
Headers let you tell the browser whether (and for how long) it may reuse a response:
<?php
// Tell the browser never to cache this response
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Expires: 0");Sending multiple headers of the same name
Most headers replace any previous one with the same name. Set the second argument to false when you genuinely need more than one (rare, but valid for some headers):
<?php
header("X-Sample: first");
header("X-Sample: second", false); // both X-Sample headers are sentRelated functions
header() writes one header at a time, but PHP has higher-level helpers for the most common cases:
setcookie()andsetrawcookie()— set aSet-Cookieheader without formatting it by hand. See PHP Cookies.http_response_code()— read or set the status code.- PHP Sessions —
session_start()itself sends cookie headers, so it has the same "before output" requirement.
To go deeper on defining and calling your own functions, see PHP Functions.
Conclusion
The header() function is your direct line to the HTTP response headers in PHP. The rules are simple: build the header string, call header() before any output, and exit after a redirect. With it you can redirect users, set content types, serve downloads, send status codes, and control caching — the building blocks of almost every dynamic PHP response.