PHP HTTP
Response headers, status codes, redirects and content types.
Key Points`header()` must run before any output or you get headers-already-sent.
Functions
| Function | Purpose |
|---|---|
| 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
| Header | Value | Purpose |
|---|---|---|
| Content-Type | application/json; charset=utf-8 | 声明响应格式 |
| Location | URL | 配合 3xx 重定向 |
| Cache-Control | no-store / max-age=3600 | 缓存策略 |
| Content-Disposition | attachment; filename="a.csv" | 触发下载 |
| X-Content-Type-Options | nosniff | 禁止 MIME 嗅探 |
| X-Frame-Options | DENY / 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,AmyNon-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
okAllow-Origin: * cannot combine with Allow-Credentials: true. With cookies you must echo the exact origin and add Vary: Origin.常用函数
| 函数 | 作用 |
|---|---|
| header | 发送一个原始 HTTP 头 |
| header_remove | 删除已设置的响应头 |
| headers_list | 已设置的响应头列表 |
| headers_sent | 是否已发送(含输出缓冲) |
| http_response_code | 设置/读取状态码 |
| setcookie | 发送 Set-Cookie |
| get_headers | 对 URL 发 HEAD 请求取头 |
| getallheaders | 取全部请求头(FPM 下可用) |
状态码与内容类型
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") 是老写法,http_response_code(404) 更清楚,而且不依赖协议版本。
常见响应头
| 响应头 | 值 | 作用 |
|---|---|---|
| Content-Type | application/json; charset=utf-8 | 声明响应格式 |
| Location | URL | 配合 3xx 重定向 |
| Cache-Control | no-store / max-age=3600 | 缓存策略 |
| Content-Disposition | attachment; filename="a.csv" | 触发下载 |
| X-Content-Type-Options | nosniff | 禁止 MIME 嗅探 |
| X-Frame-Options | DENY / SAMEORIGIN | 防点击劫持 |
| Access-Control-Allow-Origin | 来源或 * | CORS 白名单 |
重定向
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.phpheader("Location: ...") 之后**必须 exit**。不退出的话后面的代码继续执行,可能已经写入了数据或输出了内容,用户却已被跳转。文件下载
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,Amyfilename 里如果有中文,要按 RFC 5987 编码:filename*=UTF-8''%E4%B8%AD%E6%96%87.csv。直接放中文在部分浏览器里会变成乱码或截断。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
okAccess-Control-Allow-Origin: * 和 Allow-Credentials: true 不能同时用。要带 Cookie 就必须回显具体来源,并加 Vary: Origin 避免缓存串味。