web php
Headers
HTTP headers are metadata sent with requests and responses. They tell clients and servers how to interpret the body, whether to cache it, where to redirect, what cookies to store, and which security rules to apply.
In PHP, response headers must be set before output is sent. This is why stray whitespace, debugging echo, or accidental output before header() can break redirects, cookies, and content-type changes.
Setting response headers
Use header() for response headers and http_response_code() for the status code.
<?php
declare(strict_types=1);
http_response_code(200);
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(['ok' => true], JSON_THROW_ON_ERROR) . PHP_EOL;
// Output body:
// {"ok":true}
The example body prints in CLI, but headers only matter in an HTTP response. In a browser or API client, the Content-Type tells the client to treat the body as JSON.
Headers before body
Once PHP has sent body output, headers may already be committed.
<?php
declare(strict_types=1);
echo 'Body started' . PHP_EOL;
echo headers_sent() ? 'headers sent' : 'headers not sent';
echo PHP_EOL;
// Prints:
// Body started
// headers sent
Keep response decisions before rendering. In larger apps, controllers usually decide status and headers before templates produce the body.
Common response headers
You will often set or inspect:
Content-Type tells the client whether the body is HTML, JSON, text, etc.
Location redirects the client to another URL
Set-Cookie asks the browser to store a cookie
Cache-Control controls caching behaviour
Content-Disposition suggests download behaviour for files
Security headers such as Content-Security-Policy, X-Frame-Options, and Strict-Transport-Security are important too, but they need careful configuration rather than random copy-paste.
Reading request headers
Some request headers are exposed through $_SERVER with an HTTP_ prefix.
<?php
declare(strict_types=1);
$server = [
'HTTP_ACCEPT' => 'application/json',
'HTTP_USER_AGENT' => 'Example Browser',
];
echo 'Accept: ' . ($server['HTTP_ACCEPT'] ?? '*/*') . PHP_EOL;
echo 'User-Agent: ' . ($server['HTTP_USER_AGENT'] ?? 'unknown') . PHP_EOL;
// Prints:
// Accept: application/json
// User-Agent: Example Browser
Do not trust request headers automatically. Clients can send fake User-Agent, Referer, X-Forwarded-For, or Host values unless your infrastructure controls and validates them.
Cache And Download Headers
Headers often control browser behaviour rather than only body format.
For sensitive account pages, a response may need:
<?php
declare(strict_types=1);
header('Cache-Control: no-store');
echo 'Account response prepared.' . PHP_EOL;
// Prints:
// Account response prepared.
For a generated download, use a controlled filename:
<?php
declare(strict_types=1);
$filename = 'invoice-1001.pdf';
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . $filename . '"');
echo $filename . PHP_EOL;
// Prints:
// invoice-1001.pdf
Never place raw user input directly into a response header. Newlines can create header-injection problems, and unsafe filenames can produce confusing download behaviour.
Debugging Header Problems
When PHP reports that headers were already sent, find the first output. Common causes are stray whitespace before <?php, a UTF-8 byte-order mark, a debug echo, or a warning rendered before the response headers.
headers_sent($file, $line) can show where output began. Fix the early output rather than hiding the warning with output buffering.
What you should be able to do
After this lesson, you should be able to set status codes and response headers, explain why headers must come before body output, use cache and download headers, debug early output, and treat request headers as untrusted input unless your server/proxy setup proves otherwise.
Practice
Task: Describe A JSON Response
Create a small PHP example or checklist for returning a JSON response.
Requirements
- Set an HTTP status code.
- Set a
Content-Type: application/json; charset=UTF-8header. - Encode a small response body with
json_encode(). - Include a note about why headers must be sent before body output.
- Include a warning about trusting request headers.
Check your work
The example should make response metadata separate from the response body.
Show solution
<?php
declare(strict_types=1);
http_response_code(201);
header('Content-Type: application/json; charset=UTF-8');
echo json_encode([
'id' => 123,
'status' => 'created',
], JSON_THROW_ON_ERROR) . PHP_EOL;
// Output body:
// {"id":123,"status":"created"}
The status code and Content-Type header describe the response. The JSON string is the body. Headers must be sent before output because once the body starts, PHP may no longer be able to change response metadata.
Request headers should be treated as untrusted input. A client can fake values such as User-Agent, Referer, Host, or forwarding headers unless the server and proxy configuration control them.