headers_list() 函数用于返回已发送(或准备发送)的响应头列表。
该函数返回一个包含所有已添加到响应的 HTTP 头的数组。这些头可以是使用 header() 函数设置的,也可以是 PHP 自动生成的。
headers_list() 可以调试和检查当前页面发送了哪些 HTTP 头信息。
headers_list ( ) : array
该函数没有参数。
返回一个索引数组,包含已发送(或准备发送)的响应头列表。
每个数组元素都是一个字符串,格式为 "Header-Name: value"。
如果没有头信息要发送,则返回一个空数组。
以下示例展示了如何获取当前响应的所有 HTTP 头信息。
<?php
// 设置一些 HTTP 头
header("Content-Type: text/html; charset=UTF-8");
header("X-Powered-By: PHP/7.4");
header("X-Custom-Header: MyValue");
// 获取所有头信息
$headers = headers_list();
echo "<h1>已发送的 HTTP 头信息:</h1>";
echo "<ul>";
foreach ($headers as $header) {
echo "<li>" . htmlspecialchars($header) . "</li>";
}
echo "</ul>";
// 显示数组的原始格式
echo "<h2>原始数组格式:</h2>";
echo "<pre>";
print_r($headers);
echo "</pre>";
?>
检查特定的 HTTP 头是否已经设置。
<?php
// 设置一些头
header("Content-Type: application/json");
header("Cache-Control: no-cache");
/**
* 检查特定的 HTTP 头是否已设置
* @param string $header_name 要检查的头名称(不区分大小写)
* @return bool 如果头已设置返回 true,否则返回 false
*/
function is_header_set($header_name) {
$headers = headers_list();
$header_name_lower = strtolower($header_name);
foreach ($headers as $header) {
// 分割头名称和值
$parts = explode(':', $header, 2);
if (count($parts) === 2) {
$current_header_name = strtolower(trim($parts[0]));
if ($current_header_name === $header_name_lower) {
return true;
}
}
}
return false;
}
// 检查特定头是否已设置
if (is_header_set('Content-Type')) {
echo "Content-Type 头已设置\n";
} else {
echo "Content-Type 头未设置\n";
}
if (is_header_set('X-Custom-Header')) {
echo "X-Custom-Header 头已设置\n";
} else {
echo "X-Custom-Header 头未设置\n";
}
// 也可以直接检查返回值
$headers = headers_list();
echo "总共设置了 " . count($headers) . " 个头信息\n";
?>
将头信息记录到日志文件中,用于调试目的。
<?php
/**
* 记录 HTTP 头信息到日志文件
* @param string $log_file 日志文件路径
*/
function log_headers($log_file = 'headers.log') {
$headers = headers_list();
$log_entry = "[" . date('Y-m-d H:i:s') . "] HTTP Headers:\n";
foreach ($headers as $header) {
$log_entry .= " " . $header . "\n";
}
$log_entry .= str_repeat("-", 40) . "\n";
// 写入日志文件
file_put_contents($log_file, $log_entry, FILE_APPEND);
return count($headers);
}
// 设置一些头
header("Content-Type: text/html; charset=UTF-8");
header("X-Debug-Id: " . uniqid());
header("Cache-Control: max-age=3600");
// 记录头信息到日志
$header_count = log_headers();
echo "已记录 $header_count 个 HTTP 头到日志文件\n";
// 也可以在页面中显示头信息用于调试
if (isset($_GET['debug'])) {
echo "<h2>调试信息 - HTTP 头:</h2>";
echo "<pre>";
print_r(headers_list());
echo "</pre>";
}
?>
在发送头信息之前检查并获取头信息列表。
<?php
// 检查头信息是否已经发送
if (headers_sent()) {
echo "头信息已经发送,无法修改\n";
// 获取已发送的头信息
$sent_headers = headers_list();
echo "已发送的头信息数量: " . count($sent_headers) . "\n";
} else {
echo "头信息尚未发送,可以设置新的头信息\n";
// 设置一些头
header("Content-Type: text/plain");
header("X-Generated-At: " . date('Y-m-d H:i:s'));
// 获取当前准备发送的头信息
$pending_headers = headers_list();
echo "准备发送的头信息:\n";
foreach ($pending_headers as $header) {
echo " - " . $header . "\n";
}
}
// 更复杂的例子:只在头信息未发送时添加新头
function safe_add_header($header, $value = '', $replace = true) {
if (!headers_sent()) {
if ($value === '') {
header($header, $replace);
} else {
header("$header: $value", $replace);
}
return true;
} else {
error_log("无法添加头信息 '$header',头信息已发送");
return false;
}
}
// 使用安全添加头信息函数
safe_add_header('X-Custom-Header', 'MyValue');
safe_add_header('Cache-Control', 'no-cache');
// 显示所有头信息
echo "\n当前所有头信息:\n";
print_r(headers_list());
?>
在 REST API 中管理和检查响应头。
<?php
/**
* REST API 响应类
*/
class ApiResponse {
private $headers = [];
/**
* 添加响应头
*/
public function addHeader($name, $value, $replace = true) {
if (!headers_sent()) {
header("$name: $value", $replace);
$this->headers[] = "$name: $value";
return true;
}
return false;
}
/**
* 设置 JSON 响应头
*/
public function setJsonResponse() {
$this->addHeader('Content-Type', 'application/json');
$this->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
$this->addHeader('Pragma', 'no-cache');
$this->addHeader('Expires', '0');
}
/**
* 设置 CORS 头
*/
public function setCorsHeaders($origin = '*') {
$this->addHeader('Access-Control-Allow-Origin', $origin);
$this->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
$this->addHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
$this->addHeader('Access-Control-Allow-Credentials', 'true');
}
/**
* 获取已设置的头信息
*/
public function getHeaders() {
return headers_list();
}
/**
* 显示头信息(用于调试)
*/
public function debugHeaders() {
$headers = $this->getHeaders();
if (php_sapi_name() === 'cli') {
// 命令行模式
echo "HTTP Headers:\n";
foreach ($headers as $header) {
echo " $header\n";
}
} else {
// Web 模式
echo "<h3>HTTP Headers:</h3>";
echo "<ul>";
foreach ($headers as $header) {
echo "<li><code>" . htmlspecialchars($header) . "</code></li>";
}
echo "</ul>";
}
return $headers;
}
/**
* 发送 JSON 响应
*/
public function sendJson($data, $status_code = 200) {
$this->setJsonResponse();
http_response_code($status_code);
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
// 记录响应头(用于调试)
if (isset($_GET['debug'])) {
echo "\n\n<!-- Debug Headers -->\n";
$this->debugHeaders();
}
}
}
// 使用示例
$response = new ApiResponse();
// 设置 CORS 头
$response->setCorsHeaders('*');
// 模拟 API 请求处理
$request_method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
if ($request_method === 'GET') {
// 返回 JSON 数据
$data = [
'status' => 'success',
'message' => 'API is working',
'timestamp' => time(),
'headers_count' => count($response->getHeaders())
];
$response->sendJson($data);
} elseif ($request_method === 'OPTIONS') {
// 处理预检请求
$response->addHeader('Access-Control-Max-Age', '86400');
http_response_code(200);
exit;
} else {
http_response_code(405);
$response->sendJson(['error' => 'Method not allowed'], 405);
}
?>
headers_list() 返回的是已经通过 header() 函数设置但可能尚未发送到头信息列表。实际的发送发生在 PHP 开始输出内容时。headers_sent() 检查头信息是否已经发送,而 headers_list() 返回准备发送的头信息列表。headers_list() 可能会有轻微的性能影响,但通常可以忽略不计。headers_list() 仍然会返回已设置的头信息。Content-Type(如果未显式设置)和 X-Powered-By(取决于 PHP 配置)。Header-Name: value"。| 问题 | 解决方案 |
|---|---|
| 返回空数组 | 这可能是因为还没有设置任何 HTTP 头,或者头信息已经发送且无法获取。检查是否在输出之后调用此函数。 |
| 无法获取某些头信息 | 某些头信息(如 Set-Cookie)可能有多个值,需要检查 $replace 参数或使用 header_remove() 后再重新设置。 |
| 头信息顺序问题 | headers_list() 返回的头信息顺序可能与设置顺序不同。如果需要特定顺序,需要手动管理。 |
| 与输出缓冲的交互 | 当使用 ob_start() 时,头信息可能不会立即发送。使用 headers_list() 可以查看已设置但未发送的头信息。 |
| 区分已发送和待发送头信息 | 使用 headers_sent() 判断头信息是否已发送,结合 headers_list() 获取头信息列表。 |
<?php
function get_header_value($header_name) {
$headers = headers_list();
$header_name_lower = strtolower($header_name);
foreach ($headers as $header) {
list($name, $value) = explode(':', $header, 2);
if (strtolower(trim($name)) === $header_name_lower) {
return trim($value);
}
}
return null;
}
// 使用示例
header("X-Custom: MyValue");
$value = get_header_value("X-Custom"); // 返回 "MyValue"
?>
<?php
function add_header_if_not_exists($header_name, $header_value) {
$headers = headers_list();
$header_name_lower = strtolower($header_name);
foreach ($headers as $header) {
list($name, $value) = explode(':', $header, 2);
if (strtolower(trim($name)) === $header_name_lower) {
return false; // 头信息已存在
}
}
// 头信息不存在,添加它
header("$header_name: $header_value");
return true;
}
?>
<?php
function debug_headers() {
if (!isset($_GET['debug'])) {
return;
}
$headers = headers_list();
echo "<div style='background:#f0f0f0;padding:10px;margin:10px 0;'>";
echo "<h3>HTTP Headers Debug:</h3>";
echo "<ul>";
foreach ($headers as $header) {
echo "<li><code>" . htmlspecialchars($header) . "</code></li>";
}
echo "</ul>";
echo "</div>";
}
// 在页面适当位置调用
debug_headers();
?>