PHP get_headers()函数

PHP get_headers() 函数

get_headers() 函数用于获取指定 URL 的 HTTP 响应头信息。这是一个非常有用的函数,可以检查远程服务器返回的 HTTP 响应头,而无需实际下载整个响应体。

提示: get_headers() 函数通常用于检查 URL 的有效性、获取文件信息、检查重定向、验证 HTTP 状态码等场景。
注意: get_headers()apache_response_headers() 是不同的函数。前者获取远程URL的响应头,后者获取当前脚本的响应头。

语法

get_headers ( string $url [, int $format = 0 [, resource $context ]] ) : array|false

参数说明:

参数 说明 必需 默认值
$url 要获取响应头的目标 URL
$format 指定返回数组的格式。如果设置为 1,函数将解析响应头并返回关联数组 0
$context 使用 stream_context_create() 创建的上下文资源,可用于设置 HTTP 选项 null

返回值

函数返回一个包含 HTTP 响应头的索引数组或关联数组,失败则返回 FALSE

$format 参数为 0(默认)时,返回索引数组,每个元素是一个完整的响应头字符串。

$format 参数为 1 时,返回关联数组,键名为响应头名称,键值为对应的值。

返回值示例($format = 0):
Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Date: Mon, 14 Jun 2023 10:30:00 GMT
    [2] => Server: Apache/2.4.41
    [3] => Content-Type: text/html; charset=UTF-8
    [4] => Content-Length: 12345
)
返回值示例($format = 1):
Array
(
    [0] => HTTP/1.1 200 OK
    [Date] => Mon, 14 Jun 2023 10:30:00 GMT
    [Server] => Apache/2.4.41
    [Content-Type] => text/html; charset=UTF-8
    [Content-Length] => 12345
)

示例 1:获取 URL 的 HTTP 响应头

下面的示例演示如何使用 get_headers() 函数获取 URL 的 HTTP 响应头。

<?php
// 目标URL
$url = 'https://www.example.com';

// 获取响应头(默认格式)
$headers = get_headers($url);

// 检查是否成功
if ($headers !== false) {
    echo "<h3>URL: $url 的响应头信息:</h3>";
    echo "<div style='max-height: 300px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;'>";
    echo "<pre>";

    // 打印所有响应头
    foreach ($headers as $header) {
        echo htmlspecialchars($header) . "\n";
    }

    echo "</pre></div>";

    // 显示第一个元素(状态行)
    if (!empty($headers[0])) {
        echo "<p class='mt-3'><strong>状态行:</strong> " . htmlspecialchars($headers[0]) . "</p>";
    }
} else {
    echo "无法获取 URL 的响应头信息。";
}
?>

示例 2:使用关联数组格式获取响应头

下面的示例演示如何使用 $format = 1 参数获取关联数组格式的响应头。

<?php
// 目标URL
$url = 'https://www.example.com';

// 获取响应头(关联数组格式)
$headers = get_headers($url, 1);

// 检查是否成功
if ($headers !== false) {
    echo "<h3>URL: $url 的响应头(关联数组格式):</h3>";

    // 获取状态码
    if (isset($headers[0])) {
        $statusLine = $headers[0];
        echo "<p><strong>状态行:</strong> $statusLine</p>";

        // 提取状态码
        if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $statusLine, $matches)) {
            $statusCode = $matches[1];
            echo "<p><strong>状态码:</strong> $statusCode</p>";

            // 判断状态码类型
            if ($statusCode >= 200 && $statusCode < 300) {
                echo "<p class='text-success'><strong>状态:</strong> 成功</p>";
            } elseif ($statusCode >= 300 && $statusCode < 400) {
                echo "<p class='text-warning'><strong>状态:</strong> 重定向</p>";
            } elseif ($statusCode >= 400) {
                echo "<p class='text-danger'><strong>状态:</strong> 客户端错误</p>";
            } elseif ($statusCode >= 500) {
                echo "<p class='text-danger'><strong>状态:</strong> 服务器错误</p>";
            }
        }
    }

    // 显示响应头表格
    echo "<table class='table table-bordered table-striped mt-3'>";
    echo "<thead><tr><th>响应头名称</th><th>值</th></tr></thead>";
    echo "<tbody>";

    foreach ($headers as $name => $value) {
        // 跳过数字索引(状态行)
        if (is_numeric($name)) {
            continue;
        }

        // 处理值为数组的情况(当有多个相同名称的响应头时)
        if (is_array($value)) {
            $value = implode(', ', $value);
        }

        echo "<tr><td><strong>$name</strong></td><td>$value</td></tr>";
    }

    echo "</tbody></table>";
} else {
    echo "无法获取 URL 的响应头信息。";
}
?>

示例 3:检查 URL 状态和重定向

下面的示例演示如何使用 get_headers() 函数检查 URL 的状态码和重定向信息。

<?php
/**
 * 检查URL状态和重定向
 * @param string $url 要检查的URL
 * @return array 包含状态信息的数组
 */
function checkUrlStatus($url) {
    $result = [
        'url' => $url,
        'status_code' => 0,
        'status_message' => '',
        'redirect_count' => 0,
        'final_url' => '',
        'headers' => []
    ];

    // 设置上下文以跟随重定向
    $context = stream_context_create([
        'http' => [
            'method' => 'HEAD', // 使用HEAD方法,只获取头部
            'follow_location' => 1, // 跟随重定向
            'max_redirects' => 5, // 最大重定向次数
            'timeout' => 10 // 超时时间(秒)
        ]
    ]);

    // 获取响应头
    $headers = @get_headers($url, 1, $context);

    if ($headers === false) {
        $result['status_message'] = '无法连接到URL';
        return $result;
    }

    // 获取状态码
    if (isset($headers[0])) {
        $statusLine = $headers[0];

        // 提取状态码
        if (preg_match('/HTTP\/\d\.\d\s+(\d+)\s+(.+)/', $statusLine, $matches)) {
            $result['status_code'] = (int)$matches[1];
            $result['status_message'] = $matches[2];
        }
    }

    // 检查重定向
    $redirectHistory = [];
    if (isset($headers['Location'])) {
        $locations = is_array($headers['Location']) ? $headers['Location'] : [$headers['Location']];
        $result['redirect_count'] = count($locations);
        $result['final_url'] = end($locations);
        $redirectHistory = $locations;
    } else {
        $result['final_url'] = $url;
    }

    $result['headers'] = $headers;

    return $result;
}

// 测试多个URL
$urls = [
    'https://www.example.com',
    'https://httpbin.org/redirect/2',
    'https://httpbin.org/status/404',
    'https://httpbin.org/status/500',
    'https://nonexistent-domain-12345.com'
];

echo "<h3>URL状态检查结果:</h3>";
echo "<div class='table-responsive'>";
echo "<table class='table table-bordered table-hover'>";
echo "<thead class='table-dark'>";
echo "<tr><th>URL</th><th>状态码</th><th>状态</th><th>重定向次数</th><th>最终URL</th></tr>";
echo "</thead><tbody>";

foreach ($urls as $url) {
    $status = checkUrlStatus($url);

    // 根据状态码设置颜色
    $statusClass = '';
    if ($status['status_code'] >= 200 && $status['status_code'] < 300) {
        $statusClass = 'table-success';
    } elseif ($status['status_code'] >= 300 && $status['status_code'] < 400) {
        $statusClass = 'table-warning';
    } elseif ($status['status_code'] >= 400) {
        $statusClass = 'table-danger';
    } elseif ($status['status_code'] == 0) {
        $statusClass = 'table-secondary';
    }

    echo "<tr class='$statusClass'>";
    echo "<td><a href='{$status['url']}' target='_blank'>{$status['url']}</a></td>";
    echo "<td><strong>{$status['status_code']}</strong></td>";
    echo "<td>{$status['status_message']}</td>";
    echo "<td>{$status['redirect_count']}</td>";
    echo "<td>{$status['final_url']}</td>";
    echo "</tr>";
}

echo "</tbody></table>";
echo "</div>";
?>

示例 4:获取远程文件信息和大小

下面的示例演示如何使用 get_headers() 函数获取远程文件的信息,如文件大小、最后修改时间等。

<?php
/**
 * 获取远程文件信息
 * @param string $fileUrl 远程文件的URL
 * @return array 文件信息数组
 */
function getRemoteFileInfo($fileUrl) {
    $info = [
        'exists' => false,
        'size' => 0,
        'size_formatted' => '0 B',
        'last_modified' => '',
        'content_type' => '',
        'status_code' => 0
    ];

    // 获取响应头
    $headers = @get_headers($fileUrl, 1);

    if ($headers === false) {
        return $info;
    }

    // 获取状态码
    if (isset($headers[0])) {
        if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $headers[0], $matches)) {
            $info['status_code'] = (int)$matches[1];
            $info['exists'] = ($info['status_code'] == 200);
        }
    }

    // 获取文件大小
    if (isset($headers['Content-Length'])) {
        $size = is_array($headers['Content-Length']) ?
                end($headers['Content-Length']) : $headers['Content-Length'];
        $info['size'] = (int)$size;
        $info['size_formatted'] = formatBytes($info['size']);
    }

    // 获取最后修改时间
    if (isset($headers['Last-Modified'])) {
        $lastModified = is_array($headers['Last-Modified']) ?
                       end($headers['Last-Modified']) : $headers['Last-Modified'];
        $info['last_modified'] = $lastModified;
    }

    // 获取内容类型
    if (isset($headers['Content-Type'])) {
        $contentType = is_array($headers['Content-Type']) ?
                      end($headers['Content-Type']) : $headers['Content-Type'];
        $info['content_type'] = $contentType;
    }

    return $info;
}

/**
 * 格式化字节大小
 * @param int $bytes 字节数
 * @param int $precision 精度
 * @return string 格式化后的字符串
 */
function formatBytes($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . ' ' . $units[$pow];
}

// 测试文件URL(这里使用示例URL,实际使用时需要替换)
$fileUrls = [
    'https://www.example.com/index.html',
    'https://raw.githubusercontent.com/php/php-src/master/LICENSE',
    'https://www.w3.org/TR/PNG/iso_8859-1.txt',
    'https://nonexistent.example.com/file.txt'
];

echo "<h3>远程文件信息检查:</h3>";
echo "<div class='table-responsive'>";
echo "<table class='table table-bordered'>";
echo "<thead class='table-primary'>";
echo "<tr>";
echo "<th>文件URL</th>";
echo "<th>存在</th>";
echo "<th>大小</th>";
echo "<th>类型</th>";
echo "<th>最后修改</th>";
echo "</tr>";
echo "</thead><tbody>";

foreach ($fileUrls as $fileUrl) {
    $fileInfo = getRemoteFileInfo($fileUrl);

    echo "<tr>";
    echo "<td><a href='$fileUrl' target='_blank'>" . htmlspecialchars($fileUrl) . "</a></td>";

    // 存在状态
    if ($fileInfo['exists']) {
        echo "<td><span class='badge bg-success'>是</span></td>";
    } else {
        echo "<td><span class='badge bg-danger'>否</span></td>";
    }

    // 文件大小
    echo "<td>{$fileInfo['size_formatted']}</td>";

    // 内容类型
    echo "<td><code>" . htmlspecialchars($fileInfo['content_type']) . "</code></td>";

    // 最后修改时间
    echo "<td>" . htmlspecialchars($fileInfo['last_modified']) . "</td>";
    echo "</tr>";
}

echo "</tbody></table>";
echo "</div>";

// 显示详细信息
echo "<h4 class='mt-4'>使用示例:</h4>";
echo "<div class='alert alert-info'>";
echo "<strong>注意:</strong> 这个函数使用 HEAD 请求获取文件信息,不会下载整个文件,因此对于大文件检查非常高效。";
echo "</div>";
?>

示例 5:使用上下文参数定制 HTTP 请求

下面的示例演示如何使用 $context 参数定制 HTTP 请求,如设置超时、用户代理、请求方法等。

<?php
// 目标URL
$url = 'https://httpbin.org/headers';

// 创建上下文选项
$options = [
    'http' => [
        'method' => 'GET', // 请求方法
        'timeout' => 5, // 超时时间(秒)
        'header' => [ // 自定义请求头
            'User-Agent: MyCustomAgent/1.0',
            'Accept: application/json',
            'X-Custom-Header: MyValue',
            'Accept-Language: en-US,en;q=0.9'
        ],
        'ignore_errors' => true // 忽略HTTP错误,继续获取响应头
    ],
    'ssl' => [
        'verify_peer' => false, // 不验证SSL证书(仅用于测试)
        'verify_peer_name' => false
    ]
];

// 创建上下文
$context = stream_context_create($options);

// 获取响应头
$headers = get_headers($url, 1, $context);

if ($headers !== false) {
    echo "<h3>自定义HTTP请求的响应头:</h3>";

    // 显示状态
    if (isset($headers[0])) {
        echo "<p><strong>状态:</strong> {$headers[0]}</p>";
    }

    // 显示响应头
    echo "<table class='table table-bordered'>";
    echo "<thead><tr><th>响应头</th><th>值</th></tr></thead>";
    echo "<tbody>";

    foreach ($headers as $name => $value) {
        if (is_numeric($name)) {
            continue;
        }

        if (is_array($value)) {
            $value = implode(', ', $value);
        }

        echo "<tr><td><strong>$name</strong></td><td>$value</td></tr>";
    }

    echo "</tbody></table>";

    // 显示请求信息
    echo "<h4 class='mt-4'>请求配置:</h4>";
    echo "<pre>";
    echo "URL: $url\n";
    echo "方法: GET\n";
    echo "超时: 5秒\n";
    echo "自定义请求头:\n";
    echo "  - User-Agent: MyCustomAgent/1.0\n";
    echo "  - Accept: application/json\n";
    echo "  - X-Custom-Header: MyValue\n";
    echo "  - Accept-Language: en-US,en;q=0.9";
    echo "</pre>";
} else {
    echo "请求失败或超时。";
}
?>

注意事项和限制

  • 超时设置:默认情况下,get_headers() 可能会因为网络问题而阻塞。建议使用上下文参数设置超时时间。
  • 性能影响:频繁调用此函数可能会对服务器和网络造成负担,建议缓存结果或使用适当的延迟。
  • HTTP 方法:默认使用 GET 方法,但可以通过上下文参数设置为 HEAD 方法以提高性能。
  • SSL 验证:默认情况下会验证 SSL 证书,可以通过上下文参数禁用(仅用于测试环境)。
  • 重定向处理:默认不跟随重定向,需要通过上下文参数设置 follow_location 为 1 来启用。
  • 错误处理:函数失败时返回 FALSE,建议使用错误控制运算符 @ 或检查返回值。
  • 服务器限制:某些服务器可能会限制或阻止频繁的 HEAD/GET 请求。
  • PHP 版本:该函数自 PHP 5.0.0 版本开始可用,上下文参数自 PHP 5.1.3 开始可用。

常见使用场景

URL 验证

检查链接是否有效,返回正确的 HTTP 状态码。

重定向跟踪

跟踪 URL 的重定向链,获取最终目标 URL。

文件信息获取

获取远程文件的大小、类型和最后修改时间。

服务器检测

检测远程服务器使用的 Web 服务器软件和版本。

相关函数