PHP Conference Japan 2024

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而不是[email protected]),请务必检查此值并在使用诸如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() 只返回Internet类记录,因此此参数将始终返回IN
type 包含记录类型的字符串。根据type的值,结果数组中还将包含其他属性。见下表。
ttl "生存时间" 此记录的剩余时间。这等于记录的原始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的» Operating System Names
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指定的target继承的长度(以位为单位)。ipv6:此特定记录的地址,与chain合并。chain:与ipv6数据合并的父记录。
SRV pri:(优先级)应首先使用最低优先级。weight:排名,用于随机选择通常具有优先级的targets中的哪一个。targetport:可以找到请求服务的hostname和端口。更多信息请参见:» RFC 2782
NAPTR orderpref:与上面的priweight等效。flagsservicesregexreplacement:由» 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 的“任意”记录,
并创建包含域名服务器列表的 $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 Warning: dns_get_record(): res_nsend() failed in ....

这将获取所有记录,除了 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 会发出一条警告消息“Warning: dns_get_record(): Type '251721779' not supported in blah.php on line blah”,而 DNS_ANY 始终正常。
1
bohwaz
2 年前
遗憾的是,此方法不允许使用任意名称服务器。

如果您需要使用特定 DNS 服务器发出请求,则需要使用 Pear/Net_DNS2 或 libdns(https://github.com/DaveRandom/LibDNS)。

如果您想要更短更轻量的东西,您也可以使用这个 150 行的函数:https://gist.github.com/bohwaz/ddc61c4f7e031c3221a89981e70b830c
To Top