2024 年 PHP 大会日本站

gethostbyname

(PHP 4, PHP 5, PHP 7, PHP 8)

gethostbyname获取与给定互联网主机名对应的 IPv4 地址

描述

gethostbyname(字符串 $hostname): 字符串

返回由 hostname 指定的互联网主机的 IPv4 地址。

参数

hostname

主机名。

返回值

返回 IPv4 地址,如果失败则返回包含未修改的 hostname 的字符串。

示例

示例 #1 一个简单的 gethostbyname() 示例

<?php
$ip
= gethostbyname('www.example.com');

echo
$ip;
?>

参见

  • gethostbyaddr() - 获取与给定 IP 地址对应的互联网主机名
  • gethostbynamel() - 获取与给定互联网主机名对应的 IPv4 地址列表
  • inet_pton() - 将人类可读的 IP 地址转换为其打包的 in_addr 表示形式
  • inet_ntop() - 将打包的互联网地址转换为人类可读的表示形式

添加备注

用户贡献的备注 27 条备注

Ome Ko
11 年前
如果您执行 gethostbyname() 并且域名后没有尾随点,并且该域名无法解析,则 nslookup 最终会将此域名附加到服务器 FQDN。

因此,如果您查找 nonexistentdomainname.be,您的服务器可能会返回 nonexistentdomainname.be.yourhostname.com 的 IP 地址,即服务器 IP 地址。

要避免此行为,只需在域名后添加尾随点;例如 gethostbyname('nonexistentdomainname.be.')
devers
9 年前
此函数表示“返回 IPv4 地址,或者在失败时返回包含未修改的主机名的字符串”。

这并不完全正确,任何主机名中包含空字节都只会返回空字节之前的字符。

<?php
$hostname
= "foo\0bar";
var_dump($hostname );
var_dump(gethostbyname($hostname ));
?>

结果
string 'foo�bar' (length=7)
string 'foo' (length=3)
Alexandre (d)
13 年前
重要说明:您应该避免在生产环境中使用它。

DNS 解析可能需要 0.5 到 4 秒,在此期间您的脚本不会执行。

您的客户可能会认为服务器速度慢,但实际上它只是在等待 DNS 解析响应。

您可以使用它,但如果您想要性能,则应避免使用它,或将其安排到某个 CRON 脚本中……
Dennis B.
8 年前
可以通过使用 RES_OPTIONS 环境变量来提供底层解析器函数的选项。(至少在 Linux 下,请参阅 man resolv.conf)

将超时和重试设置为 1,使 DNS 查找的最大执行时间为 1 秒
<?php
putenv
('RES_OPTIONS=retrans:1 retry:1 timeout:1 attempts:1');
gethostbyname($something);
?>

您还应该使用以点结尾的完全限定域名。这可以防止解析器遍历所有搜索域并尝试附加搜索域的域名。
cox at idecnet dot com
19 年前
要使用此函数进行基本的 RBL(实时黑名单)查找,请执行以下操作

<?php
$host
= '64.53.200.156';
$rbl = 'sbl-xbl.spamhaus.org';
// 有效的查询格式是:156.200.53.64.sbl-xbl.spamhaus.org
$rev = array_reverse(explode('.', $host));
$lookup = implode('.', $rev) . '.' . $rbl;
if (
$lookup != gethostbyname($lookup)) {
echo
"ip: $host is listed in $rbl\n";
} else {
echo
"ip: $host NOT listed in $rbl\n";
}
?>

Tomas V.V.Cox
Josh Finlay josh at glamourcastle dot com
18 年前
gethostbyname 和 gethostbynamel 不会请求 AAAA 记录。我已经编写了两个函数来实现此功能。gethostbyname6 和 gethostbynamel6。我不认为这个问题已经得到解决。

它们旨在替换 gethostbyname[l],如果 $try_a 为真,如果无法获取 AAAA 记录,它将回退到尝试获取 A 记录。

随意更正任何错误,我意识到它是在请求 *同时* 获取 A 和 AAAA 记录,这意味着两次 DNS 调用……如果它在发出查询之前检查 $try_a,可能会更高效,但这对我来说有效,所以我将把它留给其他人去在他们自己的工作中实现……提示已经发布了……

这是代码

function gethostbyname6($host, $try_a = false) {
// 获取 $host 的 AAAA 记录
// 如果 $try_a 为真,如果 AAAA 失败,则尝试获取 A 记录
// 返回找到的第一个匹配项
// 否则返回 false

$dns = gethostbynamel6($host, $try_a);
if ($dns == false) { return false; }
else { return $dns[0]; }
}

function gethostbynamel6($host, $try_a = false) {
// 获取 $host 的 AAAA 记录,
// 如果 $try_a 为真,如果 AAAA 失败,则尝试获取 A 记录
// 结果以找到的匹配类型的 ip 数组返回
// 否则返回 false

$dns6 = dns_get_record($host, DNS_AAAA);
if ($try_a == true) {
$dns4 = dns_get_record($host, DNS_A);
$dns = array_merge($dns4, $dns6);
}
else { $dns = $dns6; }
$ip6 = array();
$ip4 = array();
foreach ($dns as $record) {
if ($record["type"] == "A") {
$ip4[] = $record["ip"];
}
if ($record["type"] == "AAAA") {
$ip6[] = $record["ipv6"];
}
}
if (count($ip6) < 1) {
if ($try_a == true) {
if (count($ip4) < 1) {
return false;
}
else {
return $ip4;
}
}
else {
return false;
}
}
else {
return $ip6;
}
}
hypolite at mrpetovan dot com
1年前
自2015年以来,为了解决CVE-2015-0235漏洞,主机名参数被任意限制为255个字符,这可能是为了与RFC1035中对域名字节数的限制相对应。
Vincent
20年前
请注意,如果将IP地址传递给gethostbyname(),它将返回该IP地址。
Emmett Brosnan
12年前
获取多个主机的IP地址

<?php
function getAddrByHost($hosts, $timeout = 3) {
$returnString = '';
foreach (
$hosts as $host) {
$query = `nslookup -timeout=$timeout -retry=1 $host`;
if (
preg_match('/\nAddress: (.*)\n/', $query, $matches))
$returnString .= trim($matches[1]) . '<br>';
$returnString .= $host . '<br>';
}
return
$returnString;

}

$hostArray[] = 'www.domain1.com';
$hostArray[] = 'www.domain2.com';
//$hostArray[] = 'www.domain3.com';
//$hostArray[] = 'www.domain4.com';

$returnString = getAddrByHost($hostArray);
echo
$returnString;
?>
christian at SPAM at IS at DEAD at MEAT at karg dot org
21年前
在OpenBSD 3.2和Apache下,我很难让gethostbyname工作,直到我发现默认的Apache chroot导致了这个问题。

要使PHP的gethostbyname工作,你需要在/var/www/etc中(假设是默认安装目录)放置resolv.conf(可能还有hosts)。
mcgrof at gmail dot com
19 年前
在PHP4中可以使用gethostbyname(),但我发现当查找返回私有网络上的A记录的条目时,它不可靠。PHP5有一个更好的例程——dns_get_record()。如果你仍然使用PHP4或者不想升级,可以使用dig。

<?php
$ip
= `/usr/bin/dig $host A +short`;
?>
chris at chollis dot net
18 年前
mmucklo提出了一个有效的观点,但是最简单的函数应该是getmxrr(),或者如果你愿意,也可以使用checkdnsrr();getdnsrr()不存在。

另一方面,当使用while循环迭代时,gethostbyname()在失败时返回主机名而不是FALSE,这可能会很麻烦。你可以用一个简单的用户函数来“修正”这个问题。

<?php

function fixed_gethostbyname ($host) {
// 尝试正常的查找…
$ip = gethostbyname($host);
// …但是如果失败,则返回FALSE而不是未解析的主机
if ($ip != $host) { return $ip; } else return false;
}

?>
tonyhana at sixzeros dot com
22年前
<?php
// 用于测试DNS传播时间的脚本
//(上面的脚本略作修改以显示微秒时间)
// 看起来非常快……我得到的最悪情况(badhost)时间是0.0055秒。

// 一个已知的良好DNS名称(我自己的)
$nametotest = "fuzzygroup.com";

// 调用地址测试函数
$time_start = getmicrotime();
testipaddress($nametotest);
$time_end = getmicrotime();
$time = $time_end - $time_start;
echo
"良好主机搜索耗时 $time 秒<br><br>";

// 一个已知的错误名称(相信我)
$nametotest = "providence.mascot.com";
$time_start = getmicrotime();
testipaddress($nametotest);
$time_end = getmicrotime();
$time = $time_end - $time_start;
echo
"错误主机搜索耗时 $time 秒<br>";


function
getmicrotime(){
list(
$usec, $sec) = explode(" ",microtime());
return ((float)
$usec + (float)$sec);
}

// IP地址检查函数
// 实际使用应该有返回值,但这是示例代码
function testipaddress ($nametotest) {
$ipaddress = $nametotest;
$ipaddress = gethostbyname($nametotest);
if (
$ipaddress == $nametotest) {
echo
"主机没有IP地址<br>";
}
else {
echo
"良好主机名,$nametotest IP地址为 $ipaddress<br>";
}
}

// 建议用于SQL应用程序的修复:
// 将URL存储到临时表中
// 定期运行第二个进程来
// 检查URL并更新主表
?>
guwapo at thedoghouse dot bz
17年前
参考ralphbolton at mail2sexy dot com的评论

(至少在5.2.0 + djbdns-dnscache中)gethostbyname似乎并没有真正缓存条目。如果有人注意到在第二次查找相同域名后速度加快了——那很可能是你的DNS缓存本身,而不是某种PHP内部的DNS缓存。

它确实缓存了你/etc/resolv.conf中的条目(例如,使用哪个DNS),所以我同意他的说法,停止并启动Apache将重新加载resolv.conf。
ralphbolton at mail2sexy dot com
18 年前
顺便说一句,PHP(5.0.4,但也可能是其他版本)可以缓存gethostbyname信息。

简而言之,一旦PHP查找地址,它可能不会像你预期的那样执行另一次查找。在我的特定情况下(我认为)问题是resolv.conf的更改在PHP内部没有生效(尽管nslookup/ping等工作正常)。停止/启动Apache解决了这个问题(尽管简单的“重启”(kill -HUP)没有解决)。

简而言之,如果你更改了resolv.conf,请停止并重新启动Apache。
tabascopete78 at yahoo dot com
19 年前
我正在对一组URL使用file_get_contents。其中一些URL无效(其结构没问题,但DNS主机无法解析它们),我一直收到烦人的警告。我想以某种方式检查DNS,但是PHP中现有的检查DNS函数在Windows中没有,而其他人提供的函数也不能100%地工作。

相反,使用此函数尝试解析主机。这不会引发任何警告,你只需要检查输出。你将使用fopen和fsockopen获得相同的警告。
Marc M
18 年前
提醒一下。我一直在我的网站上使用此函数来验证电子邮件主机地址。我以为一切都很顺利,直到一个潜在的客户联系我说他们无法正确注册。他们有有效的电子邮件地址和域名,但是此函数失败了。

祝你好运。
gabriel at nexcore dot com dot br
8 年前
对于“dig”解决方案,这里有一个更好的方法

<?php
$IP
= `/usr/bin/dig $host. A +short | /usr/bin/tail -n1`
?>

使用tail是因为dig,即使在+short形式下,也可能首先返回CNAME条目,也可能返回许多条目(参见“dig google.com”)。

在主机末尾使用点以不执行域名搜索。

当$host已经是IP地址时,这也适用。

如果解析失败(无效主机名),将返回空字符串。
manalejandro at gmail dot com
16年前
这个逻辑解决方案用于检查DNS反向名称解析问题。

<?php
$ip
= gethostbyname($host);
if(
ip2long($ip) == -1 || ($ip == gethostbyaddr($ip) && preg_match("/.*\.[a-zA-Z]{2,3}$/",$host) == 0) ) {
echo
'错误,主机名或IP地址不正确';
}
else {
echo
'正确';
}
?>
Peter <toomuchphp-phpman at yahoo dot com>
18 年前
一种自动发现您的IP地址的方法

<?php

// 需要使用 trim(),因为空格会干扰名称查找
$myIP = gethostbyname(trim(`hostname`));
echo
$myIP;

?>
seb dot gibbs at ymail dot com
1年前
同时使用 gethostbynamel() 和 gethostbyname() 时,必须先执行 gethostbynamel(),否则它将始终从缓存中返回一个IP(或无), 而不是返回完整的查找结果。
sjohnson at fuzzygroup dot com
22年前
<?php

// 用于查看主机是否在互联网上存在的脚本

// 针对上面关于主机名检查和SQL超时的问题的后续处理,运行此测试脚本
// 并查看第二次主机名检查失败需要多长时间
// 注意 -- 这不是PHP的错误 -- 这是DNS的特性

// 一个已知的良好DNS名称(我自己的)
$nametotest = "fuzzygroup.com";

// 调用地址测试函数
testipaddress($nametotest);

// 一个已知的错误名称(相信我)
$nametotest = "providence.mascot.com";
// 调用地址测试函数
testipaddress($nametotest);

// IP地址检查函数
// 对于实际使用应该有一个返回值,但这是示例代码
function testipaddress ($nametotest) {
$ipaddress = $nametotest;
$ipaddress = gethostbyname($nametotest);
if (
$ipaddress == $nametotest) {
echo
"主机没有IP地址,因此主机"
. "当前在DNS中不可用,并且"
. "可能已离线一段时间<BR>";
}
else {
echo
"主机名正确,ip地址 = $ipaddress<BR>";
}
}

// 建议用于SQL应用程序的修复方案:
// 将URL存储到临时表中
// 定期运行第二个进程来
// 检查URL并更新主表
?>
php at nemon dot be
9 年前
始终在末尾添加根“. ”,否则您的服务器可能会添加它自己的后缀。
例如:如果不使用 abc.com,abc.com 可能会变为 abc.com.yourcompany.com。

我还发现此函数有点局限,因为它不会告诉您解析是否失败。

为了解决所有这些问题,我使用

function host2ip($host)
{
$host=trim($host.'.'); // 清理并添加根“.”
$ip= gethostbyname($host);
if($ip==$host) $ip='';// 如果没有IP,则IP为空
return $ip;
}
von at student dot chalmers dot se
17年前
在 RedHat Linux 上的 chroot 环境中使用 PHP 和 Apache 时,我发现我需要绑定挂载 /var/run/nscd 才能使其工作。显然,该目录中的套接字对于所有 DNS 事务都是必需的。
mmucklo at yahoo dot com
18 年前
关于使用 gethostbyname() 检查电子邮件地址域的一个说明

如果名称无法解析,请继续使用 getdnsrr() 并确保它们没有 MX 条目,然后再返回错误。

域名可能没有 A 记录,但仍然有 MX 条目。
匿名
20年前
DNS 条目会被缓存,无论它们是否存在。第一次之后,可以预期非常好的响应时间。
Florian Holzhauer
17年前
如果使用 apache2、mod_chroot 和 php5 时名称解析失败,请添加
LoadFile /lib/libnss_dns.so.2
到 mod_chroot 配置中。
To Top