PHP HTTP

Response headers, status codes, redirects and content types.

Intermediate
Key Points`header()` must run before any output or you get headers-already-sent.

Functions

FunctionPurpose
header发送一个原始 HTTP 头
header_remove删除已设置的响应头
headers_list已设置的响应头列表
headers_sent是否已发送(含输出缓冲)
http_response_code设置/读取状态码
setcookie发送 Set-Cookie
get_headers对 URL 发 HEAD 请求取头
getallheaders取全部请求头(FPM 下可用)

Status and content type

PHP
<?php
http_response_code(404);
header("Content-Type: text/plain; charset=utf-8");
header("X-Content-Type-Options: nosniff");

echo http_response_code(), "\n";
print_r(headers_list());
Output
404
Array
(
    [0] => Content-Type: text/plain; charset=utf-8
    [1] => X-Content-Type-Options: nosniff
)

header("HTTP/1.1 404 Not Found") is the old form; http_response_code(404) is clearer and protocol-agnostic.

Common headers

HeaderValuePurpose
Content-Typeapplication/json; charset=utf-8声明响应格式
LocationURL配合 3xx 重定向
Cache-Controlno-store / max-age=3600缓存策略
Content-Dispositionattachment; filename="a.csv"触发下载
X-Content-Type-Optionsnosniff禁止 MIME 嗅探
X-Frame-OptionsDENY / SAMEORIGIN防点击劫持
Access-Control-Allow-Origin来源或 *CORS 白名单

Redirect

PHP
<?php
// 302 临时重定向
// header("Location: /login.php");
// exit;

// 301 永久重定向(会进浏览器缓存)
// header("Location: https://example.com/new", true, 301);
// exit;

// 重定向必须先输出状态,再 Location
http_response_code(302);
header("Location: /login.php");

echo "Location: /login.php\n";
Output
Location: /login.php
**Always exit after Location.** Otherwise the rest of the script runs and may write data even though the user was redirected.

File download

PHP
<?php
$name = "report.csv";
$body = "id,name\n1,Tom\n2,Amy\n";

header("Content-Type: text/csv; charset=utf-8");
header("Content-Disposition: attachment; filename=\"" . $name . "\"");
header("Content-Length: " . strlen($body));
header("Cache-Control: no-store");

echo $body;
Output
id,name
1,Tom
2,Amy
Non-ASCII filenames need RFC 5987 encoding: filename*=UTF-8''.... Raw Chinese gets mangled in some browsers.

CORS

PHP
<?php
$allowed = ["https://app.example.com", "https://admin.example.com"];
$origin = $_SERVER["HTTP_ORIGIN"] ?? "";

if (in_array($origin, $allowed, true)) {
    header("Access-Control-Allow-Origin: " . $origin);
    header("Access-Control-Allow-Credentials: true");
    header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
    header("Access-Control-Allow-Headers: Content-Type, Authorization");
    header("Vary: Origin");
}

// 预检请求直接返回 204
if (($_SERVER["REQUEST_METHOD"] ?? "") === "OPTIONS") {
    http_response_code(204);
    exit;
}

echo "ok";
Output
ok
Allow-Origin: * cannot combine with Allow-Credentials: true. With cookies you must echo the exact origin and add Vary: Origin.

Friends & Partners