gethostbyname

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

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

描述

gethostbyname(string $hostname): string

返回由 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() - 将打包的互联网地址转换为人类可读的表示形式

添加注释

用户贡献的注释 31 个注释

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

因此,如果您查找不存在的域名 nonexistentdomainname.be,您的服务器可能会返回 nonexistentdomainname.be.yourhostname.com 的 IP,即服务器 IP。

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

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

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

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

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

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

您可以使用它,但如果您想要性能,您应该避免使用它,或者将其安排到某个 CRON 脚本中……
15
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);
?>

您还应该使用以点结尾的完全限定域名。这可以防止解析器遍历所有搜索域并尝试在后面附加搜索域的域名。
7
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
7
Josh Finlay josh at glamourcastle dot com
17 年前
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;
}
}
-1
hypolite at mrpetovan dot com
1 年前
自 2015 年以来,主机名参数被任意限制为 255 个字符,以解决 CVE-2015-0235,可能是为了反映 RFC1035 对域名中八位字节的限制。
0
Vincent
20 年前
请注意,如果您将 IP 地址传递给 gethostbyname(),它将返回该 IP 地址。
-2
christian at SPAM at IS at DEAD at MEAT at karg dot org
21 年前
我在 OpenBSD 3.2 和 Apache 下使用 gethostbyname 时遇到了困难,直到我发现默认的 Apache chroot 导致了问题。

要使 PHP 的 gethostbyname 正常工作,您需要 resolv.conf(可能还有 hosts)位于 /var/www/etc(假设默认安装目录)。
-2
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;
?>
-1
mcgrof at gmail dot com
18 年前
在 PHP4 中,您可以使用 gethostbyname(),但我发现当对返回私有网络上的 A 记录的条目进行查找时,它不可靠。PHP5 有一个更好的例程 - dns_get_record()。如果您仍然使用 PHP4 或者不想升级,您可以使用 dig

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

另一方面,当使用 while 循环迭代时(例如),gethostbyname() 在失败时返回主机名而不是 FALSE,这可能会很麻烦。您可以将其封装在一个简单的用户函数中,以“纠正”此问题

<?php

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

?>
-3
tonyhana at sixzeros dot com
22 年前
<?php
// 用于计时 DNS 传播的脚本
//(上面脚本略作修改以显示微秒时间)
// 似乎非常快.. 我得到的最差情况坏主机时间是 .0055 秒。

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

// 调用地址测试函数
$time_start = getmicrotime();
testipaddress($nametotest);
$time_end = getmicrotime();
$time = $time_end - $time_start;
echo
"Good Host Search took $time seconds<br><br>";

// 一个已知的错误名称(相信我)
$nametotest = "providence.mascot.com";
$time_start = getmicrotime();
testipaddress($nametotest);
$time_end = getmicrotime();
$time = $time_end - $time_start;
echo
"Bad Host Search took $time seconds<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
"No ip address for host<br>";
}
else {
echo
"good hostname, $nametotest ipaddress = $ipaddress<br>";
}
}

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

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

它确实在您的 /etc/resolv.conf 中缓存条目(例如使用哪个 DNS),所以我同意他的说法,停止和启动 Apache 将重新加载 resolv.conf。
-2
ralphbolton at mail2sexy dot com
18 年前
另外,PHP(5.0.4,但可能还有其他版本)可以缓存 gethostbyname 信息。

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

简而言之,如果您更改了 resolv.conf,请停止并重启 Apache。
-1
tabascopete78 at yahoo dot com
18 年前
我正在对一组 URL 使用 file_get_contents。其中一些 URL 无效(它的结构没问题,但 DNS 主机无法解析它们),我一直收到烦人的警告。我想以某种方式检查 DNS,但是 PHP 中现有的检查 DNS 函数在 Windows 上没有,而一个人提供的一个函数在大多数情况下无法正常工作。

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

祝您好运。
-7
nirazuelos at gmail dot com
15 年前
这是我想到的将任何主机名解析为 IP 地址的最佳方法,它快速可靠并且支持超时!无效地址(例如 unicode 字符串)将在 4~ 秒后返回,而不是 gethostbyname 的 8~ 秒!不过它仅适用于 Unix。

<?php
function getAddrByHost($host, $timeout = 3) {
$query = `nslookup -timeout=$timeout -retry=1 $host`;
if(
preg_match('/\nAddress: (.*)\n/', $query, $matches))
return
trim($matches[1]);
return
$host;
}
?>
-6
mcgrof at gmail dot com
18 年前
更好的是
<?php
$ip
= rtrim(`/usr/bin/dig $host A +short`);
?>
-4
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 地址时,此方法同样有效。

如果解析失败(无效主机名),将返回空字符串。
-4
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
'成功';
}
?>
-3
Peter <toomuchphp-phpman at yahoo dot com>
17 年前
一种自动发现您的 IP 地址的方法。

<?php

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

?>
-2
seb dot gibbs at ymail dot com
1 年前
当同时使用 gethostbynamel() 和 gethostbyname() 时,必须先执行 gethostbynamel(),否则它将始终从缓存中返回一个 IP(或没有),而不是返回完整的查找结果。
-3
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 并更新主表
?>
-2
php at nemon dot be
8 年前
始终在末尾添加根域名 ".",否则您的服务器可能会添加自己的后缀。
例如:abc.com 可能会变成 abc.com.yourcompany.com,如果您没有使用 abc.com。

我还发现这个函数有点局限性,因为它无法告诉您是否解析失败。

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

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

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

一个域名可能没有 A 记录,但仍然有 MX 记录。
-3
匿名
20 年前
DNS 条目会被缓存,无论它们是否存在。预计第一次之后会得到非常好的响应时间。
-8
geoff at spacevs dot com
16 年前
我将它放在我所有网站的前置脚本中,以减少来自自动化脚本的滥用量。
<?PHP
$blacklists
= array('web.sorbs.net');
$parts = explode('.', $_SERVER['REMOTE_ADDR']);
$ip = implode('.', array_reverse($parts)) . '.';
foreach(
$blacklists as $bl) {
$check = $ip . $bl;
if (
$check != gethostbyname($check)) {
error_log('PHP 安全性: [DNSBL] - ' . $_SERVER['REMOTE_ADDR'] . ' - ' . $bl);
die(
'在此处放置详细的错误信息,以便客户端知道他们被阻止的原因');
}
}
?>
-4
Florian Holzhauer
16 年前
如果使用 apache2、mod_chroot 和 php5 时名称解析失败,请在 mod_chroot 配置中添加
LoadFile /lib/libnss_dns.so.2
-7
ivan[DOT]pirog[AT]gmail[DOT]com
18 年前
函数返回布尔值。
<?php
function isDomainResolves($domain)
{
return
gethostbyname($domain) != $domain;
}
?>
To Top