get_headers

(PHP 5, PHP 7, PHP 8)

get_headers获取服务器响应 HTTP 请求发送的所有头信息

描述

get_headers(string $url, bool $associative = false, ?resource $context = null): array|false

get_headers() 返回一个数组,其中包含服务器响应 HTTP 请求发送的头信息。

参数

url

目标 URL。

associative

如果可选的 associative 参数设置为 true,get_headers() 将解析响应并设置数组的键。

context

使用 stream_context_create() 创建的有效上下文资源,或 null 以使用默认上下文。

返回值

返回一个包含头信息的索引或关联数组,或在失败时返回 false

变更日志

版本 描述
8.0.0 associative 已从 int 更改为 bool.
7.1.0 添加了 context 参数。

示例

示例 #1 get_headers() 示例

<?php
$url
= 'http://www.example.com';

print_r(get_headers($url));

print_r(get_headers($url, true));
?>

上面的示例将输出类似于以下内容

Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Date: Sat, 29 May 2004 12:28:13 GMT
    [2] => Server: Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [3] => Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
    [4] => ETag: "3f80f-1b6-3e1cb03b"
    [5] => Accept-Ranges: bytes
    [6] => Content-Length: 438
    [7] => Connection: close
    [8] => Content-Type: text/html
)

Array
(
    [0] => HTTP/1.1 200 OK
    [Date] => Sat, 29 May 2004 12:28:14 GMT
    [Server] => Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [Last-Modified] => Wed, 08 Jan 2003 23:11:55 GMT
    [ETag] => "3f80f-1b6-3e1cb03b"
    [Accept-Ranges] => bytes
    [Content-Length] => 438
    [Connection] => close
    [Content-Type] => text/html
)

示例 #2 使用 HEAD 的 get_headers() 示例

<?php
// 默认情况下,get_headers 使用 GET 请求来获取头信息。 如果你
// 想要发送 HEAD 请求,你可以使用流上下文:
$context = stream_context_create(
[
'http' => array(
'method' => 'HEAD'
)
]
);
$headers = get_headers('http://example.com', false, $context);
?>

参见

添加备注

用户贡献的备注 17 个备注

nick at innovaweb dot co dot uk
14 年前
似乎有些人只想要 3 位数的 HTTP 响应代码 - 这是一个快速而肮脏的解决方案

<?php
function get_http_response_code($theURL) {
$headers = get_headers($theURL);
return
substr($headers[0], 9, 3);
}
?>

多么容易!将包含要检查响应代码的 URL 的函数回显出来,瞧!自定义重定向,替代被阻止的 is_file() 或 flie_exists() 函数(就像我似乎在我的服务器上拥有的那样),因此是廉价的解决方法。但嘿 - 它有效!

布丁
sey at sey dot prometheus-designs dot net
19 年前
aeontech at gmail dot com 更新的 get_headers 函数在 $format = 1 时,会错误地格式化日期。

替换
<?
else {
$headers[strtolower($h2[0])] = trim($h2[1]);
}
?>


<?
else {
$foo = implode( ':', $h2 );
$foo = preg_replace( '/[a-zA-Z- ]*: /', '', $foo );
$headers[strtolower($h2[0])] = trim( $foo );
}
mcilva
5 年前
如何检查 URL 是否指向有效的视频

<?php
function isVideo($url){
$url = get_headers($url,1);
if(
is_array($url['Content-Type'])){ // 在某些响应中,Content-type 是一个数组
$video = strpos($url['Content-Type'][1],'video');
}else{
$video = strpos($url['Content-Type'],'video');
}
if(
$video !== false)
return
true;

return
false;
}

?>
cees at cornelisdigitaal dot nl
9 年前
@Jim Greene

如果 URL 不存在,它将返回不完整的头信息,使子字符串默认为垃圾信息。

垃圾信息的整数值始终为 0。因此,您的低于 400 的值并不总是意味着它存在!
Jim Greene
11 年前
我知道你不应该参考其他备注,但真诚地赞扬 Innovaweb 的 Nick 的评论,我以此为基础在他的想法上添加了以下内容

如果你使用那个函数,它将返回一个字符串,如果你只检查返回 404 或 200 等等的文件,这很好。如果你将字符串值强制转换为整数,你就可以对其进行数学比较。

例如

<?php
function get_http_response_code($theURL) {
$headers = get_headers($theURL);
return
substr($headers[0], 9, 3);
}

if(
intval(get_http_response_code('filename.jpg')) < 400){
// 文件存在,万岁!
}
?>

经验法则是,如果响应小于 400,则文件就在那里,即使它没有返回 200。
Kubo2
10 年前
如果你不想在 get_headers() 函数失败时显示警告,你可以在它前面添加一个 at 符号 (@)。

<?php

// 失败时,警告将被隐藏并返回 false
$withoutWarning = @get_headers("http://www.some-domain.com");

// 失败时,警告显示,并将返回 false
$withWarning = get_headers("http://www.some-domain.com");

// bool(false)
var_dump($withoutWarning);
// bool(false)
var_dump($withWarning);
?>
Weboide
13 年前
注意,get_headers **将跟踪重定向**(HTTP 重定向)。如果 $format=0,新的标头将被附加到数组中。如果 $format=1,每个冗余标头将是多个值的数组,每个重定向一个值。

例如

<?php
$url
= 'http://google.com';
var_dump(get_headers($url,0));
/*array(18) {
[0]=> string(30) "HTTP/1.0 301 Moved Permanently"
[1]=> string(32) "Location: http://www.google.com/"
[2]=> string(38) "Content-Type: text/html; charset=UTF-8"
[3]=> string(35) "Date: Sun, 26 Sep 2010 00:59:50 GMT"
[4]=> string(38) "Expires: Tue, 26 Oct 2010 00:59:50 GMT"
[5]=> string(38) "Cache-Control: public, max-age=2592000"
....
string(15) "HTTP/1.0 200 OK"
[10]=> string(35) "Date: Sun, 26 Sep 2010 00:59:51 GMT"
[11]=> string(11) "Expires: -1"
[12]=> string(33) "Cache-Control: private, max-age=0"
.....
}*/

/*===========================*/

var_dump(get_headers($url,1));
/*array(11) {
[0]=>
string(30) "HTTP/1.0 301 Moved Permanently"
["Location"]=> string(22) "http://www.google.com/"
["Content-Type"]=> array(2) {
[0]=> string(24) "text/html; charset=UTF-8"
[1]=> string(29) "text/html; charset=ISO-8859-1"
}
["Date"]=> array(2) {
[0]=> string(29) "Sun, 26 Sep 2010 01:03:39 GMT"
[1]=> string(29) "Sun, 26 Sep 2010 01:03:39 GMT"
}
["Expires"]=> array(2) {
[0]=> string(29) "Tue, 26 Oct 2010 01:03:39 GMT"
[1]=> string(2) "-1"
}
["Cache-Control"]=> array(2) {
[0]=> string(23) "public, max-age=2592000"
[1]=> string(18) "private, max-age=0"
}
.....
}*/
?>
bunny at bunny dot hu
7 年前
如果 URL 被重定向,并且新的目标也被重定向,我们将得到数组中的 Location。我们还将在数字索引的值中得到 HTTP 代码。

这是一个标头的部分(并非全部),显示了它在此重定向链中的外观(id=4 是目标页面)
/test.php?id=1 -> /test.php?id=2 -> /test.php?id=3 -> /test.php?id=4

数组
(
[0] => HTTP/1.1 302 Moved Temporarily

[Location] => 数组
(
[0] => /test.php?id=2
[1] => /test.php?id=3
[2] => /test.php?id=4
)

[1] => HTTP/1.1 302 Moved Temporarily
[2] => HTTP/1.1 302 Moved Temporarily
[3] => HTTP/1.1 200 OK
)

在典型情况下,我们只需要目标页面的信息,所以这里有一段小代码来获取它

$result = array();
$header = get_headers($url, 1);
foreach ($header as $key=>$value) {
if (is_array($value)) {
$value = end($value);
}
$result[$key] = $value;
}
pegasus at vaultwiki dot org
9 年前
注意,不要对通过用户输入收集的 URL 使用 get_headers。流上下文中的超时选项仅影响流中数据之间的空闲时间。它不会影响连接时间或请求的总时间。

(不幸的是,超时选项的文档中没有提到这一点,但在其他一些代码讨论中有所讨论,我也做了自己的测试来确认这些讨论的结论。)

因此,用户很容易提供一个类似于 Slowloris 攻击的 URL,该 URL 以足够低的频率向你的 get_headers 函数提供一个标头,以避免流超时。

如果你要发布你的代码,即使是 default_socket_timeout 也不可靠,因为它在许多 PHP 版本(除了更新的版本)中对于 HTTPS 协议都存在问题: https://bugs.php.net/bug.php?id=41631

如果 get_headers 接受用户输入,攻击者很容易让你的所有 PHP 子进程变得繁忙。

相反,使用 cURL 函数来获取用户提供的 URL 的标头,并手动解析这些标头,因为 CURLOPT_TIMEOUT 适用于整个请求。
sidnash56 at gmail dot com
8 年前
为了检查 URL 有效性,这对我很有效

function url_valid(&$url) {
$file_headers = @get_headers($url);
if ($file_headers === false) return false; // 当服务器未找到时
foreach($file_headers as $header) { // 解析所有标头
// 当 301/302 重定向导致 200 时,更正 $url
if(preg_match("/^Location: (http.+)$/",$header,$m)) $url=$m[1];
// 获取最后一个 $header $code,以防重定向
if(preg_match("/^HTTP.+\s(\d\d\d)\s/",$header,$m)) $code=$m[1];
} // 结束 foreach...
if($code==200) return true; // $code 200 == 全部正常
else return false; // 其他情况都失败了,所以这肯定是一个坏链接
} // 结束函数 url_exists
stuart at sixletterwords dot com
18 年前
嘿,几周前我偶然发现了这个,并在一个记录公司拥有的域信息应用程序中使用了该函数,发现它返回的状态大多数时候都是错误的(对于显然在线的网站,返回 400 错误请求或无效)。然后,仔细研究后,我注意到问题在于它无法获取有关具有重定向的网站的正确信息。但这不是全部问题,因为我服务器上的所有内容都返回了错误的状态。我在 php.net 上搜索了其他信息,发现 fsockopen 的示例效果更好,只需要一些调整。

这是我根据它组合的函数,并进行了一些小的更改。

<?php
if(!function_exists('get_headers')) {
function
get_headers($url,$format=0,$httpn=0){
$fp = fsockopen($url, 80, $errno, $errstr, 30);
if (
$fp) {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: $url\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!
feof($fp)) {
$var.=fgets($fp, 1280);
}

$var=explode("<",$var);
$var=$var[0];
$var=explode("\n",$var);
fclose($fp);
return
$var;
}
}
}
?>

它返回标头的数组(唯一的问题是,如果网站没有正确的 HTML,它也会提取一些内容)。

希望这对其他人有所帮助。
php at hm2k dot org
14 年前
<?php
/**
* 检索服务器响应 HTTP 请求时发送的所有真实标头,不进行重定向
*
* @link https://php.net/function.get_headers
* @link http://bugs.php.net/bug.php?id=50719
*/

function get_real_headers($url,$format=0,$follow_redirect=0) {
if (!
$follow_redirect) {
// 设置新的默认选项
$opts = array('http' =>
array(
'max_redirects'=>1,'ignore_errors'=>1)
);
stream_context_get_default($opts);
}
// 获取标头
$headers=get_headers($url,$format);
// 恢复默认选项
if (isset($opts)) {
$opts = array('http' =>
array(
'max_redirects'=>20,'ignore_errors'=>0)
);
stream_context_get_default($opts);
}
// 返回
return $headers;
}
?>
info at marc-gutt dot de
16 年前
应该与原始的 get_headers() 相同

<?php
if (!function_exists('get_headers')) {
function
get_headers($url, $format=0) {
$headers = array();
$url = parse_url($url);
$host = isset($url['host']) ? $url['host'] : '';
$port = isset($url['port']) ? $url['port'] : 80;
$path = (isset($url['path']) ? $url['path'] : '/') . (isset($url['query']) ? '?' . $url['query'] : '');
$fp = fsockopen($host, $port, $errno, $errstr, 3);
if (
$fp)
{
$hdr = "GET $path HTTP/1.1\r\n";
$hdr .= "Host: $host \r\n";
$hdr .= "Connection: Close\r\n\r\n";
fwrite($fp, $hdr);
while (!
feof($fp) && $line = trim(fgets($fp, 1024)))
{
if (
$line == "\r\n") break;
list(
$key, $val) = explode(': ', $line, 2);
if (
$format)
if (
$val) $headers[$key] = $val;
else
$headers[] = $key;
else
$headers[] = $line;
}
fclose($fp);
return
$headers;
}
return
false;
}
}
?>
匿名
17 年前
我注意到了。
一些服务器在发送 'HEAD' 请求而不是 'GET' 请求时,只会返回错误的响应头。'GET' 请求头始终接收最新的 HTTP 头,而不是 'HEAD' 请求头。但如果您不介意使用一种快速但有风险的方法,那么 'HEAD' 请求更适合您。

顺便说一下... 这是带有附加信息(如用户、密码和来源)的获取头... ...
<?php
function get_headers_x($url,$format=0, $user='', $pass='', $referer='') {
if (!empty(
$user)) {
$authentification = base64_encode($user.':'.$pass);
$authline = "Authorization: Basic $authentification\r\n";
}

if (!empty(
$referer)) {
$refererline = "Referer: $referer\r\n";
}

$url_info=parse_url($url);
$port = isset($url_info['port']) ? $url_info['port'] : 80;
$fp=fsockopen($url_info['host'], $port, $errno, $errstr, 30);
if(
$fp) {
$head = "GET ".@$url_info['path']."?".@$url_info['query']." HTTP/1.0\r\n";
if (!empty(
$url_info['port'])) {
$head .= "Host: ".@$url_info['host'].":".$url_info['port']."\r\n";
} else {
$head .= "Host: ".@$url_info['host']."\r\n";
}
$head .= "Connection: Close\r\n";
$head .= "Accept: */*\r\n";
$head .= $refererline;
$head .= $authline;
$head .= "\r\n";

fputs($fp, $head);
while(!
feof($fp) or ($eoheader==true)) {
if(
$header=fgets($fp, 1024)) {
if (
$header == "\r\n") {
$eoheader = true;
break;
} else {
$header = trim($header);
}

if(
$format == 1) {
$key = array_shift(explode(':',$header));
if(
$key == $header) {
$headers[] = $header;
} else {
$headers[$key]=substr($header,strlen($key)+2);
}
unset(
$key);
} else {
$headers[] = $header;
}
}
}
return
$headers;

} else {
return
false;
}
}
?>

此致。
Donovan
drfickle2 at yahoo dot com
19 年前
aeontech,以下更改添加了对 SSL 连接的支持。感谢您的代码!

if (isset($url_info['scheme']) && $url_info['scheme'] == 'https') {
$port = 443;
$fp=fsockopen('ssl://'.$url_info['host'], $port, $errno, $errstr, 30);
} else {
$port = isset($url_info['port']) ? $url_info['port'] : 80;
$fp=fsockopen($url_info['host'], $port, $errno, $errstr, 30);
}
Backslider
12 年前
需要注意的是,此函数(以及其他函数)在失败时,不会返回“false”,而是返回一个巨大的警告,如果您的脚本没有关闭错误报告/警告,就会停止脚本执行。

太疯狂了!任何执行类似获取 URL 操作的函数,如果 URL 由于任何原因(除了格式错误)而失败,都应该简单地返回 false,而不是发出警告。
php dot sirlancelot at spamgourmet dot com
16 年前
我尝试尽可能地复制本机行为,用于没有 get_headers() 函数的系统。这是它
<?php
if (!function_exists('get_headers')) {
function
get_headers($Url, $Format= 0, $Depth= 0) {
if (
$Depth > 5) return;
$Parts = parse_url($Url);
if (!
array_key_exists('path', $Parts)) $Parts['path'] = '/';
if (!
array_key_exists('port', $Parts)) $Parts['port'] = 80;
if (!
array_key_exists('scheme', $Parts)) $Parts['scheme'] = 'http';

$Return = array();
$fp = fsockopen($Parts['host'], $Parts['port'], $errno, $errstr, 30);
if (
$fp) {
$Out = 'GET '.$Parts['path'].(isset($Parts['query']) ? '?'.@$Parts['query'] : '')." HTTP/1.1\r\n".
'Host: '.$Parts['host'].($Parts['port'] != 80 ? ':'.$Parts['port'] : '')."\r\n".
'Connection: Close'."\r\n";
fwrite($fp, $Out."\r\n");
$Redirect = false; $RedirectUrl = '';
while (!
feof($fp) && $InLine = fgets($fp, 1280)) {
if (
$InLine == "\r\n") break;
$InLine = rtrim($InLine);

list(
$Key, $Value) = explode(': ', $InLine, 2);
if (
$Key == $InLine) {
if (
$Format == 1)
$Return[$Depth] = $InLine;
else
$Return[] = $InLine;

if (
strpos($InLine, 'Moved') > 0) $Redirect = true;
} else {
if (
$Key == 'Location') $RedirectUrl = $Value;
if (
$Format == 1)
$Return[$Key] = $Value;
else
$Return[] = $Key.': '.$Value;
}
}
fclose($fp);
if (
$Redirect && !empty($RedirectUrl)) {
$NewParts = parse_url($RedirectUrl);
if (!
array_key_exists('host', $NewParts)) $RedirectUrl = $Parts['host'].$RedirectUrl;
if (!
array_key_exists('scheme', $NewParts)) $RedirectUrl = $Parts['scheme'].'://'.$RedirectUrl;
$RedirectHeaders = get_headers($RedirectUrl, $Format, $Depth+1);
if (
$RedirectHeaders) $Return = array_merge_recursive($Return, $RedirectHeaders);
}
return
$Return;
}
return
false;
}}
?>
该函数将处理最多五个重定向。
享受!
To Top