2024 日本 PHP 研討會

dns_get_record

(PHP 5, PHP 7, PHP 8)

dns_get_record擷取與主機名稱關聯的 DNS 資源記錄

說明

dns_get_record(
    字串 $hostname,
    整數 $type = DNS_ANY,
    陣列 &$authoritative_name_servers = null,
    陣列 &$additional_records = null,
    布林值 $raw = false
): 陣列|false

擷取與指定 hostname 相關聯的 DNS 資源記錄。

參數

hostname

hostname 應為有效的 DNS 主機名稱,例如 "www.example.com"。可以使用 in-addr.arpa 標記法產生反向查詢,但 gethostbyaddr() 更適合大多數反向查詢。

注意事項:

根據 DNS 標準,電子郵件地址以 user.host 格式提供(例如:hostmaster.example.com,而不是 hostmaster@example.com),請務必檢查此值,並在使用諸如 mail() 等函式之前根據需要進行修改。

type

預設情況下,dns_get_record() 會搜尋與 hostname 相關聯的任何資源記錄。要限制查詢,請使用 DNS_* 常數之一。

authoritative_name_servers

以傳址方式傳遞,如果提供,將會填入 *授權名稱伺服器* 的資源記錄。

additional_records

以傳址方式傳遞,如果提供,將會填入任何 *額外記錄*。

raw

type 將被解釋為原始 DNS 類型 ID(不能使用 DNS_* 常數)。返回值將包含一個 data 鍵,需要手動解析。

返回值

此函式返回一個關聯陣列的陣列,或在失敗時返回 false。每個關聯陣列 *至少* 包含以下鍵值

基本 DNS 屬性
屬性 含義
host DNS 命名空間中的記錄,其餘相關聯的資料都參考此記錄。
class dns_get_record() 只返回網際網路類別記錄,因此此參數將始終返回 IN
type 包含記錄類型的字串。根據 `type` 的值,結果陣列中也會包含其他屬性。請參閱下表。
ttl 此記錄剩餘的「生存時間」(Time To Live)。這 *不會* 等於記錄的原始 ttl,而是等於原始 ttl 減去自查詢授權名稱伺服器以來經過的時間長度。

關聯陣列中的其他鍵值取決於 type
類型 額外欄位
A ip:以點分十進位標記法表示的 IPv4 地址。
MX pri:郵件交換器的優先順序。數字越小,優先順序越高。 target:郵件交換器的完整網域名稱 (FQDN)。另請參閱 dns_get_mx()
CNAME target:記錄所別名的 DNS 命名空間中位置的完整網域名稱 (FQDN)。
NS target:此主機名稱的授權名稱伺服器的完整網網域名稱 (FQDN)。
PTR target:此記錄指向的 DNS 命名空間中的位置。
TXT txt:與此記錄關聯的任意字串數據。
HINFO cpu:指定此記錄所參考的機器之 CPU 的 IANA 編號。 os:指定此記錄所參考的機器之作業系統的 IANA 編號。有關這些值的含義,請參閱 IANA 的 » 作業系統名稱
CAA flags:一個位元組的位元欄位;目前僅定義了位元 0,表示「關鍵」;其他位元保留,應忽略。 tag:CAA 標籤名稱(英數字 ASCII 字串)。 value:CAA 標籤值(二進位字串,可以使用子格式)。有關更多資訊,請參閱:» RFC 6844
SOA mname:資源記錄來源機器的完整網網域名稱 (FQDN)。 rname:此網網域的管理連絡人的電子郵件地址。 serial:此修訂版請求網網域的序號。 refresh:輔助名稱伺服器在更新此網網域的遠端副本時應使用的重新整理間隔(秒)。 retry:重新整理失敗後,在進行第二次嘗試之前等待的時間長度(秒)。 expire:輔助 DNS 伺服器在成功重新整理之前保留區域數據的遠端副本的最長時間(秒),超過此時間將捨棄。 minimum-ttl:用戶端在向伺服器請求新的解析之前可以繼續使用 DNS 解析的最短時間(秒)。可以被個別的資源記錄覆蓋。
AAAA ipv6:IPv6 地址
A6 masklen:要從 chain 指定的目標繼承的長度(以位元為單位)。 ipv6:要與 chain 合併的此特定記錄的地址。 chain:要與 ipv6 數據合併的父記錄。
SRV pri:(優先順序)應優先使用最低優先順序。 weight:用於在隨機選擇具有相同優先順序的 target 時的權重排名。 targetport:可以找到所請求服務的主機名稱和埠。有關更多資訊,請參閱:» RFC 2782
NAPTR orderpref:等效於上面的 priweightflagsservicesregexreplacement» RFC 2915 中定義的參數。

更新日誌

版本 說明
7.0.16, 7.1.2 新增了對 CAA 記錄類型的支援。

範例

範例 #1 使用 dns_get_record()

<?php
$result
= dns_get_record("php.net");
print_r($result);
?>

以上範例將輸出類似以下的內容

Array
(
    [0] => Array
        (
            [host] => php.net
            [type] => MX
            [pri] => 5
            [target] => pair2.php.net
            [class] => IN
            [ttl] => 6765
        )

    [1] => Array
        (
            [host] => php.net
            [type] => A
            [ip] => 64.246.30.37
            [class] => IN
            [ttl] => 8125
        )

)

範例 #2 使用 dns_get_record() 和 DNS_ANY

由於在解析 MX 記錄後,通常需要取得郵件伺服器的 IP 位址,因此 dns_get_record() 也會在 additional_records 中返回一個陣列,其中包含關聯記錄。同時也會返回 authoritative_name_servers,其中包含一份權威名稱伺服器的清單。

<?php
/* 請求 php.net 的「ANY」記錄,
並建立包含名稱伺服器清單的 $authns 和 $addtl 陣列,
以及與之相關的任何額外記錄 */
$result = dns_get_record("php.net", DNS_ANY, $authns, $addtl);
echo
"Result = ";
print_r($result);
echo
"Auth NS = ";
print_r($authns);
echo
"Additional = ";
print_r($addtl);
?>

以上範例將輸出類似以下的內容

Result = Array
(
    [0] => Array
        (
            [host] => php.net
            [type] => MX
            [pri] => 5
            [target] => pair2.php.net
            [class] => IN
            [ttl] => 6765
        )

    [1] => Array
        (
            [host] => php.net
            [type] => A
            [ip] => 64.246.30.37
            [class] => IN
            [ttl] => 8125
        )

)
Auth NS = Array
(
    [0] => Array
        (
            [host] => php.net
            [type] => NS
            [target] => remote1.easydns.com
            [class] => IN
            [ttl] => 10722
        )

    [1] => Array
        (
            [host] => php.net
            [type] => NS
            [target] => remote2.easydns.com
            [class] => IN
            [ttl] => 10722
        )

    [2] => Array
        (
            [host] => php.net
            [type] => NS
            [target] => ns1.easydns.com
            [class] => IN
            [ttl] => 10722
        )

    [3] => Array
        (
            [host] => php.net
            [type] => NS
            [target] => ns2.easydns.com
            [class] => IN
            [ttl] => 10722
        )

)
Additional = Array
(
    [0] => Array
        (
            [host] => pair2.php.net
            [type] => A
            [ip] => 216.92.131.5
            [class] => IN
            [ttl] => 6766
        )

    [1] => Array
        (
            [host] => remote1.easydns.com
            [type] => A
            [ip] => 64.39.29.212
            [class] => IN
            [ttl] => 100384
        )

    [2] => Array
        (
            [host] => remote2.easydns.com
            [type] => A
            [ip] => 212.100.224.80
            [class] => IN
            [ttl] => 81241
        )

    [3] => Array
        (
            [host] => ns1.easydns.com
            [type] => A
            [ip] => 216.220.40.243
            [class] => IN
            [ttl] => 81241
        )

    [4] => Array
        (
            [host] => ns2.easydns.com
            [type] => A
            [ip] => 216.220.40.244
            [class] => IN
            [ttl] => 81241
        )

)

另請參閱

新增註釋

使用者貢獻的註釋 7 則註釋

29
tobias at herkula dot info
9 年前
這個方法沒有錯誤處理,它只會輸出「false」,而且無法檢查 NXDOMAIN、SERVFAIL、TIMEOUT 或任何其他錯誤...
15
dylan at pow7 dot com
15 年前
像這樣一次取得多種類型
<?php
$dnsr
= dns_get_record('php.net', DNS_A + DNS_NS);
print_r($dnsr);
?>

在某些 DNS_ANY 可用的網域上,使用 DNS_ALL 會失敗。我注意到該函式卡在 DNS_PTR 記錄上,導致它返回 FALSE 並顯示此錯誤
PHP 警告:dns_get_record(): res_nsend() 失敗,檔案位於 ....

這會取得除 DNS_PTR 之外的所有記錄
<?php
$dnsr
= dns_get_record('php.net', DNS_ALL - DNS_PTR);
print_r($dnsr);
?>
12
NaturalBornCamper
7 年前
你可能跟我遇到過一樣的問題,在測試一個不存在的網域時,它會搜尋相對於你執行程式網域的子網域,例如:

// 使用有效的網域進行測試
var_dump( dns_get_record('google.com', DNS_A) );
/* 正常運作,返回
陣列
(
[host] => google.com
[class] => IN
[ttl] => 299
[type] => A
[ip] => 172.217.12.142
)
*/

// 在我們的網站 (example.com) 上測試無效的網域
var_dump( dns_get_record('invalidtestingname.com', DNS_A) );
/* 無法正常運作,會將其視為子網域
陣列
(
[host] => invalidtestingname.com.example.com
[class] => IN
[ttl] => 299
[type] => A
[ip] => xxx.xxx.xxx.xxx
)
*/

如果有人遇到這個問題,請在網域名稱後面加上一個「點」,例如,不要這樣寫
dns_get_record('invalidtestingname.com', DNS_A);
而應該這樣寫
dns_get_record('invalidtestingname.com.', DNS_A);
13
PHP Joe
11 年前
雖然這對於一般的 DNS 查詢非常有效,但如果您想對指定的 DNS 伺服器進行直接 DNS 查詢(而不是使用作業系統解析),請嘗試 PHPDNS:http://www.purplepixie.org/phpdns/

您可以對名稱伺服器執行直接(TCP 或 UDP)的低階查詢,並根據需要遞迴查詢。這對於測試特定伺服器以及逐步執行遞迴解析非常有用。
3
heinjan at eendrachtstraat dot nl
8 年前
請注意,防火牆和反惡意軟體會偵測(根據公司政策甚至會封鎖)DNS_ANY 請求。
在這種情況下,使用此函式會失敗。
這是因為 DNS_ANY 請求可能會被利用來發動「放大 (D)DoS 攻擊」:您發送 1 個 DNS_ANY 請求,卻會收到大量的資訊,因此即使是小請求也可能導致巨大的網路負載。

我建議使用更明確的名稱請求,而不是使用 DNS_ANY。
1
ohcc at 163 dot com
7 年前
當我在 Windows 作業系統上使用 DNS_ALL 作為第二個參數來呼叫 dns_get_record() 時,PHP 會發出警告訊息:「警告:dns_get_record():blah.php 的第 blah 行不支援類型 '251721779'」,而 DNS_ANY 始終正常。
1
bohwaz
2 年前
遺憾的是,此方法不允許使用任意名稱伺服器。

如果您需要使用特定的 DNS 伺服器發出請求,則需要使用 Pear/Net_DNS2 或 libdns (https://github.com/DaveRandom/LibDNS)。

如果您想要更簡短、更輕量的解決方案,也可以使用這個 150 行的函式:https://gist.github.com/bohwaz/ddc61c4f7e031c3221a89981e70b830c
To Top