PHP HTTP Headers: The Secret Messages of the Web
The Story of the Invisible Messenger
Imagine you’re sending a package to a friend. Before opening it, your friend sees:
- Who sent it (return address)
- What’s inside (fragile sticker, food label)
- Special instructions (“Open immediately!” or “Refrigerate”)
That’s exactly what HTTP Headers do! They’re invisible notes attached to every web page, telling the browser important information BEFORE the actual content arrives.
What Are HTTP Headers?
Think of a restaurant:
- The menu = your web page content
- The waiter’s instructions = HTTP headers
The waiter tells you: “This dish is hot,” “This is vegetarian,” or “Sorry, we’re out of that.” You don’t see these as part of the menu, but they help you understand what you’re getting!
graph TD A["Browser Requests Page"] --> B["Server Prepares Response"] B --> C["📋 Headers Sent First"] C --> D["📄 Content Sent After"] D --> E["Browser Displays Page"]
The header() Function: Your Message Sender
The header() function is PHP’s way of sending these invisible messages.
Basic Syntax
header("Header-Name: Value");
Real Example:
<?php
header("X-Greeting: Hello Browser!");
?>
Important Rules
- Headers MUST come first - before ANY output
- No
echo, no HTML, no spaces beforeheader()
This will BREAK:
Hello
<?php
header("Location: /home.php");
// ERROR! Output already sent
?>
This works:
<?php
header("Location: /home.php");
// Headers before everything!
?>
HTTP Status Codes: The Traffic Signals
Status codes are like traffic lights for the web:
| Code | Color | Meaning | Example |
|---|---|---|---|
| 2xx | 🟢 Green | Success! | 200 OK |
| 3xx | 🟡 Yellow | Redirect | 301 Moved |
| 4xx | 🔴 Red | Your mistake | 404 Not Found |
| 5xx | ⚫ Black | Server’s mistake | 500 Error |
Common Status Codes Explained
200 OK - “Here’s your page, everything is fine!”
<?php
header("HTTP/1.1 200 OK");
?>
404 Not Found - “Sorry, this page doesn’t exist!”
<?php
header("HTTP/1.1 404 Not Found");
echo "Oops! Page not found.";
?>
403 Forbidden - “You can’t come in!”
<?php
header("HTTP/1.1 403 Forbidden");
echo "Access denied.";
?>
500 Internal Server Error - “Something broke on our end!”
<?php
header("HTTP/1.1 500 Internal Server Error");
echo "We're fixing this!";
?>
Using http_response_code() - The Easy Way
<?php
http_response_code(404);
echo "Page not found!";
?>
Much simpler than writing the full header!
Redirects: The Web’s GPS
Sometimes you need to send visitors somewhere else. It’s like a sign saying: “We moved! Go to this new address.”
The 3 Types of Redirects
graph TD A["User Visits Old Page"] --> B{Redirect Type?} B -->|301| C["Permanent Move<br>Search engines update"] B -->|302| D["Temporary Move<br>Just visiting"] B -->|307| E["Temporary + Keep Method<br>POST stays POST"]
301 - Permanent Redirect
Use when a page has PERMANENTLY moved:
<?php
header("Location: /new-page.php", true, 301);
exit;
?>
When to use:
- Website redesign
- Changed URL structure
- Domain change
302 - Temporary Redirect
Use when a page is temporarily somewhere else:
<?php
header("Location: /maintenance.php", true, 302);
exit;
?>
When to use:
- Site maintenance
- A/B testing
- Temporary promotions
Simple Redirect (Default 302)
<?php
header("Location: https://example.com");
exit; // Always exit after redirect!
?>
Why exit After Redirect?
Without exit, PHP continues running code after the redirect. This can:
- Waste server resources
- Cause security issues
- Create unexpected behavior
Always use exit or die() after redirects!
Content-Type Headers: Telling Browsers What to Expect
Imagine getting a box with no label. Is it food? A toy? Clothes? You’d be confused!
Content-Type headers tell browsers: “This is HTML” or “This is an image” or “This is JSON.”
Common Content Types
| Type | Header | Use Case |
|---|---|---|
| Web Page | text/html |
Normal HTML pages |
| JSON | application/json |
API responses |
| Plain Text | text/plain |
Simple text |
application/pdf |
PDF documents | |
| Image | image/png |
PNG images |
Examples
Sending HTML (default):
<?php
header("Content-Type: text/html; charset=UTF-8");
echo "<h1>Hello World</h1>";
?>
Sending JSON:
<?php
header("Content-Type: application/json");
$data = ["name" => "John", "age" => 25];
echo json_encode($data);
?>
Forcing a Download:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename='file.pdf'");
readfile("document.pdf");
?>
Sending Plain Text:
<?php
header("Content-Type: text/plain");
echo "This is just plain text.";
echo "No HTML formatting here!";
?>
Character Encoding
Always specify UTF-8 to support all languages:
<?php
header("Content-Type: text/html; charset=UTF-8");
echo "Hello! Bonjour! 你好! مرحبا!";
?>
Putting It All Together
Here’s a real-world example using all header types:
<?php
// Check if user is logged in
if (!isset($_SESSION['user'])) {
// 401 Unauthorized
http_response_code(401);
header("Content-Type: application/json");
echo json_encode(["error" => "Please log in"]);
exit;
}
// Check if page exists
$page = $_GET['page'] ?? 'home';
if (!file_exists("pages/$page.php")) {
// 404 Not Found
http_response_code(404);
header("Content-Type: text/html");
echo "<h1>Page not found</h1>";
exit;
}
// Page moved permanently?
if ($page === 'old-blog') {
header("Location: /blog", true, 301);
exit;
}
// Success! Send the page
http_response_code(200);
header("Content-Type: text/html; charset=UTF-8");
include "pages/$page.php";
?>
Quick Summary
graph TD A["header Function"] --> B["Status Codes"] A --> C["Redirects"] A --> D["Content-Type"] B --> B1["200 OK"] B --> B2["404 Not Found"] B --> B3["500 Server Error"] C --> C1["301 Permanent"] C --> C2["302 Temporary"] D --> D1["text/html"] D --> D2["application/json"] D --> D3["text/plain"]
Remember These Golden Rules
- Headers before output - Always call
header()before any echo or HTML - Exit after redirects - Always use
exitafterheader("Location: ...") - Set Content-Type - Tell browsers what you’re sending
- Use proper status codes - 200 for success, 404 for not found, etc.
You now understand how web servers secretly communicate with browsers. These invisible messages control everything from page redirects to file downloads. Pretty cool, right?
