PHP Headers — HTTP Header Manipulation, Redirects, and Content Types
In this tutorial, you will learn about PHP Headers. We cover key concepts, practical examples, and best practices to help you master this topic.
PHP headers are HTTP header lines sent from the server to the browser before any body content, enabling redirects, content type declarations, cache control, and file downloads through the header function.
Why It Matters
HTTP headers control how the browser interprets your response. A redirect header tells the browser to go to another URL. A content-type header tells the browser whether to render HTML, display an image, or download a file. Cache headers control whether pages are cached. Understanding headers is essential for building REST APIs, file download handlers, and any application that needs precise HTTP control.
Real-World Use
A login system redirects to the dashboard with header('Location: dashboard.php'). A PDF generation script sets Content-Type: application/pdf. An API returns JSON with Content-Type: application/json. A download handler forces file download with Content-Disposition: attachment. DodaTech uses headers for authentication redirects, security headers, and API responses.
What You Will Learn
- Setting HTTP headers with the header() function
- Redirect responses with Location headers
- Content-Type headers for different response formats
- Cache control and expiration headers
- File download headers with Content-Disposition
- Status codes and custom headers
- Security headers: CSP, HSTS, X-Frame-Options
Learning Path
flowchart LR A[Cookies] --> B[Headers
You are here] B --> C[File Upload] C --> D[JSON API] D --> E[Error Handling] style B fill:#f90,color:#fff
Basic Header Function
The header() function sets a raw HTTP header:
<?php
header('Content-Type: text/html; charset=utf-8');
header('X-Custom-Header: MyValue');
Rules for Using header()
- Call
header()before any output (HTML, echo, whitespace) - Use
headers_sent()to check if headers were already sent - Call
header_remove()to remove a previously set header - Use
headers_list()to see all headers that will be sent
Redirects
The most common use of headers is redirecting the browser:
<?php
// Simple redirect
header('Location: /dashboard.php');
exit; // Always call exit after redirect
// With status code
header('Location: /new-page.php', true, 301); // Permanent redirect
header('Location: /temporary.php', true, 302); // Temporary redirect
// Redirect with delay (meta refresh alternative)
header('Refresh: 5; URL=/new-page.php');
echo 'You will be redirected in 5 seconds.';
Always call exit or die after a redirect header. Otherwise the script continues executing, and the browser may ignore the redirect if more output follows.
Content-Type Headers
Tell the browser what kind of content you are sending:
<?php
// HTML
header('Content-Type: text/html; charset=utf-8');
// Plain text
header('Content-Type: text/plain; charset=utf-8');
// JSON API response
header('Content-Type: application/json');
echo json_encode(['status' => 'ok', 'data' => $data]);
// XML
header('Content-Type: application/xml');
echo $xmlString;
// CSS
header('Content-Type: text/css');
// JavaScript
header('Content-Type: application/javascript');
// Image
header('Content-Type: image/png');
readfile('image.png');
File Download Headers
Force a file to download instead of displaying in the browser:
<?php
$file = 'document.pdf';
$filename = 'user-document.pdf';
// Validate file exists
if (!file_exists($file)) {
header('HTTP/1.1 404 Not Found');
echo 'File not found';
exit;
}
// Set download headers
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
// Clear output buffer and send file
ob_clean();
flush();
readfile($file);
exit;
Serving Different File Types for Download
<?php
function serveFile(string $filePath, string $downloadName = ''): void {
if (!file_exists($filePath)) {
header('HTTP/1.1 404 Not Found');
exit;
}
$mimeTypes = [
'pdf' => 'application/pdf',
'zip' => 'application/zip',
'jpg' => 'image/jpeg',
'png' => 'image/png',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
];
$ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
$mime = $mimeTypes[$ext] ?? 'application/octet-stream';
$name = $downloadName ?: basename($filePath);
header('Content-Type: ' . $mime);
header('Content-Disposition: attachment; filename="' . $name . '"');
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
}
Status Codes
Set HTTP status codes with the header function:
<?php
header('HTTP/1.1 200 OK'); // Success
header('HTTP/1.1 201 Created'); // Resource created
header('HTTP/1.1 301 Moved Permanently'); // Permanent redirect
header('HTTP/1.1 400 Bad Request'); // Client error
header('HTTP/1.1 401 Unauthorized'); // Authentication required
header('HTTP/1.1 403 Forbidden'); // Permission denied
header('HTTP/1.1 404 Not Found'); // Resource not found
header('HTTP/1.1 500 Internal Server Error'); // Server error
In PHP 5.4+, use http_response_code():
<?php
http_response_code(404);
echo 'Page not found';
Cache Control Headers
Control whether and how browsers and proxies cache your content:
<?php
// No caching
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() - 3600) . ' GMT');
// Cache for 1 hour
header('Cache-Control: public, max-age=3600');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT');
// Cache for 1 week
$expires = time() + 86400 * 7;
header('Cache-Control: public, max-age=' . (86400 * 7));
header('Expires: ' . gmdate('D, d M Y H:i:s', $expires) . ' GMT');
// Validate with ETag
$etag = md5_file(__FILE__);
header('ETag: "' . $etag . '"');
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
trim($_SERVER['HTTP_IF_NONE_MATCH'], '"') === $etag) {
header('HTTP/1.1 304 Not Modified');
exit;
}
Security Headers
Modern web applications should set security headers to protect against common attacks:
<?php
// Prevent MIME-type sniffing
header('X-Content-Type-Options: nosniff');
// Prevent clickjacking
header('X-Frame-Options: DENY');
// Enable XSS filter in older browsers
header('X-XSS-Protection: 1; mode=block');
// Strict Transport Security (HTTPS only)
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
// Content Security Policy
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'");
// Referrer Policy
header('Referrer-Policy: strict-origin-when-cross-origin');
// Permissions Policy
header('Permissions-Policy: geolocation=(), microphone=(), camera=()');
CORS Headers
Allow cross-origin requests from other domains:
<?php
// Allow all origins (simple APIs)
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
// Specific origin (secure)
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
$allowed = ['https://app.example.com', 'https://admin.example.com'];
if (in_array($origin, $allowed)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Vary: Origin');
}
// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('HTTP/1.1 204 No Content');
exit;
}
Common Mistakes
1. Output Before header() Call
echo "Hello";
header('Location: /login.php'); // Warning: Cannot modify header information
Any whitespace, HTML, or echo before header() causes this error. Use output buffering if you cannot avoid output.
2. Forgetting exit After Redirect
header('Location: /dashboard.php');
// Script continues executing!
Always call exit after a Location header to stop execution.
3. Not Checking headers_sent()
if (!headers_sent()) {
header('Location: /error.php');
}
Check headers_sent() before sending a header in code that may have already produced output.
4. Wrong Status Code Syntax
header('401 Unauthorized'); // Wrong
header('HTTP/1.1 401 Unauthorized'); // Correct
5. Not Setting CORS Headers for API Calls
If your API is called from a different domain, the browser blocks the request without proper CORS headers. Always set them for public APIs.
Practice Questions
Why must header() be called before any output? HTTP headers must be sent before the response body. Once output starts, headers cannot be modified.
What is the difference between a 301 and 302 redirect? 301 is permanent (browsers cache the redirect). 302 is temporary. Use 301 for moved pages, 302 for temporary redirects.
How do you force a file to download instead of displaying? Set
Content-Disposition: attachment; filename="file.pdf"andContent-Type: application/octet-stream.What security headers should every site set? X-Content-Type-Options, X-Frame-Options, Content-Security-Policy, Strict-Transport-Security, Referrer-Policy.
Challenge: Build a script that serves different content types based on a URL parameter: ?format=json, ?format=xml, ?format=download, with appropriate headers for each.
Mini Project: JSON API Router
Create a simple JSON API with proper headers:
<?php
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-store');
function jsonResponse(mixed $data, int $status = 200): never {
http_response_code($status);
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
}
function jsonError(string $message, int $status = 400): never {
jsonResponse(['error' => true, 'message' => $message], $status);
}
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
match (true) {
$path === '/api/users' => jsonResponse([
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
]),
preg_match('#^/api/users/(\d+)$#', $path, $m) === 1 => jsonResponse([
'id' => (int)$m[1], 'name' => 'User ' . $m[1]
]),
default => jsonError('Not found', 404),
};
FAQ
What is Next
Now that you understand headers, proceed to File Upload to learn secure file upload handling. Then read JSON API to build RESTful API endpoints.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro