PHP Conference Japan 2024

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 則註釋

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 ));
?>

結果
字串 'foo�bar' (長度=7)
字串 'foo' (長度=3)
21
Alexandre (d)
13 年前
重要注意事項:應避免在正式環境中使用此函式。

DNS 解析可能需要 0.5 到 4 秒的時間,在此期間您的程式碼不會執行。

您的客戶可能會認為伺服器速度很慢,但實際上它只是在等待 DNS 解析回應。

您可以使用它,但如果您想要效能,則應避免使用它,或是將其排程到某些 CRON 指令碼中...
14
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);
?>

您也應該使用以點結尾的完整網域名稱 (FQDN)。這樣可以防止解析器遍歷所有搜尋網域,並在網域名稱附加搜尋網域後重試。
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 列於 $rbl 中\n";
} else {
echo
"ip: $host 未列於 $rbl 中\n";
}
?>

Tomas V.V. Cox
7
Josh Finlay josh at glamourcastle dot com
18 年前
gethostbyname 和 gethostbynamel 不會查詢 AAAA 記錄。我寫了兩個函式來實現這個功能:gethostbyname6 和 gethostbynamel6。我認為這個問題尚未得到解決。

它們是用來取代 gethostbyname[l] 的,如果 `$try_a` 為 true,且獲取 AAAA 記錄失敗,它會嘗試獲取 A 記錄。

歡迎更正任何錯誤,我知道它會同時要求 A 和 AAAA 記錄,這意味著兩次 DNS 呼叫…如果在查詢之前檢查 `$try_a` 可能會更有效率,但这對我來說有效,所以我把它留給其他人實作…總之,提示就在這裡了。

程式碼如下:

function gethostbyname6($host, $try_a = false) {
// 獲取 $host 的 AAAA 記錄
// 如果 $try_a 為 true,且 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 為 true,且 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 年起,為了應對 CVE-2015-0235 漏洞,hostname 參數被任意限制為 255 個字元,這可能是為了 mirroring RFC1035 對網域名稱的八位元組限制。
0
Vincent
20 年前
請注意,如果您將 IP 位址傳遞給 gethostbyname(),它將返回該 IP 位址。
-1
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;
?>
-2
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)(假設是預設安裝目錄)。
-1
mcgrof at gmail dot com
19 年前
在 PHP4 中,您可以使用 gethostbyname(),但我發現當查詢返回私人網路上的 A 記錄時,這個函數不太可靠。PHP5 有一個更好的函數 -- dns_get_record()。如果您只能使用 PHP4 或不想升級,您可以使用 dig

<?php
$ip
= `/usr/bin/dig $host A +short`;
?>
-4
chris at chollis dot net
18 年前
mmucklo 提出了一个有效的观点,然而在最簡單的情況下,應該使用的函數是 getmxrr(),或者如果您願意,也可以使用 checkdnsrr();getdnsrr() 這個函數並不存在。

另一方面,當 `gethostbyname()` 失敗時,它會返回主機名稱而不是 FALSE,這在使用 while 迴圈迭代時可能會很麻煩。您可以將它包裝在一個簡單的使用者函式中來「修正」這個問題。

<?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 解析時間的程式
//(上述程式略作修改以顯示微秒時間)
// 對我來說速度非常快.. 我最差的情況下 badhost 時間是 .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 應用程式修正方法:
// 將網址儲存到暫存表格
// 定期執行第二個程序來
// 檢查網址並更新主表格
?>
-2
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。
-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
19 年前
我正在對一組網址使用 file_get_contents。其中一些網址無效(網址結構正常,但 DNS 主機無法解析它們),我不斷收到惱人的警告。我想以某種方式檢查 DNS,但 PHP 中現有的 DNS 檢查函數沒有適用於 Windows 的函數,而且有人在那裡提供的函數並不能 100% 的時間正常工作。

請改用這個函數來嘗試解析主機。這不會拋出任何警告,您只需檢查輸出即可。使用 fopen 和 fsockopen 時,您會收到相同的警告。
-2
Marc M
18 年前
提醒一下。我在我的網站上使用這個函數來驗證電子郵件主機地址。我原以為一切正常,直到一位潛在客戶聯繫我,說他們無法正確註冊。他們有一個有效的電子郵件地址和網域,但這個函數失敗了。

祝你好運。
-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>
18 年前
自動偵測 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 應用程式修復方法:
// 將網址儲存到暫存資料表
// 定期執行第二個程序來
// 檢查網址並更新主資料表
?>
-2
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;
}
-3
von at student dot chalmers dot se
17 年前
當在 RedHat Linux 的 chroot 環境中使用 PHP 和 Apache 時,我發現我需要 bind-mount /var/run/nscd 才能使其正常工作。顯然,該目錄中的 socket 是所有 DNS 操作所必需的。
-3
mmucklo at yahoo dot com
18 年前
關於使用 gethostbyname() 檢查電子郵件地址網域的注意事項

如果名稱無法解析,請接著使用 getdnsrr() 檢查,並確認它們沒有 MX 記錄,再返回錯誤。

網域名稱可能沒有 A 記錄,但仍然有 MX 記錄。
-3
匿名
20 年前
DNS 記錄會被快取,無論它們是否存在。在第一次查詢後,預期會有非常好的回應時間。
-4
Florian Holzhauer
17 年前
如果在使用 apache2、mod_chroot 和 php5 時名稱解析失敗,請在 mod_chroot 設定中加入
LoadFile /lib/libnss_dns.so.2
這一行。
To Top