如何使用PHP可靠获取域名nameservers并解决dns_get_record报错问题
问题原因
dns_get_record 默认依赖本地配置的递归DNS服务器执行查询,当域名的权威NS服务器对递归查询做了限制、或是域名未配置可解析的业务记录但NS记录已在顶级域根区生效时,递归DNS服务器可能无法正常返回结果,就会触发临时服务错误,且默认查询超时时间较长,会大幅拖慢批量查询效率。
可靠解决方案
方案1:使用PECL扩展Net_DNS2(推荐)
该扩展支持自定义DNS服务器、配置查询超时、指定查询类型,可绕过本地递归DNS的异常限制,稳定性和查询效率更高。
// 先安装扩展:pecl install Net_DNS2 $resolver = new Net_DNS2_Resolver([ 'nameservers' => ['8.8.8.8', '1.1.1.1'], // 指定公共DNS服务器 'timeout' => 2, // 单查询超时设为2秒,避免长时间阻塞 'recursion' => false, // 关闭递归查询,直接拉取权威NS记录 ]); try { $result = $resolver->query('fightthesmears.com', 'NS'); $nsRecords = []; foreach ($result->answer as $record) { $nsRecords[] = $record->nsdname; } print_r($nsRecords); } catch(Net_DNS2_Exception $e) { // 自定义错误处理,查询失败直接跳过进入下一个域名 echo "查询失败: " . $e->getMessage() . PHP_EOL; }
方案2:调用系统dig命令(适合无权限安装扩展的场景)
系统原生的dig命令对DNS查询的容错性更高,可自定义超时、重试次数,PHP通过exec调用即可,注意做好输入过滤避免命令注入。
$domain = escapeshellarg('fightthesmears.com'); // 配置2秒超时、重试1次,仅返回NS记录内容 $result = shell_exec("dig +timeout=2 +tries=1 +short NS {$domain}"); $nsRecords = array_filter(explode(PHP_EOL, trim($result))); print_r($nsRecords);
方案3:WHOIS查询兜底
如果DNS查询全部失败,可通过查询域名WHOIS信息获取NS记录,适合还未正式接入解析的域名,需注意适配不同顶级域的WHOIS返回格式,且控制查询频率避免被限制。
$domain = 'fightthesmears.com'; $whoisServer = 'whois.verisign-grs.com'; // com域名对应的WHOIS服务器 $fp = fsockopen($whoisServer, 43, $errno, $errstr, 2); if (!$fp) { echo "WHOIS连接失败: $errstr ($errno)" . PHP_EOL; } else { fwrite($fp, $domain . "\r\n"); $response = ''; while (!feof($fp)) { $response .= fgets($fp, 128); } fclose($fp); // 匹配返回结果中的NS记录 preg_match_all('/Name Server:\s*(\S+)/i', $response, $matches); $nsRecords = array_unique($matches[1] ?? []); print_r($nsRecords); }
批量查询优化建议
- 所有查询逻辑强制加超时控制,超时直接标记失败进入下一个域名,避免阻塞整个流程
- 提前对域名按顶级域分类,批量查询时可复用同顶级域的WHOIS连接、DNS查询缓存
- 批量场景可搭配多进程或Swoole协程处理,大幅提升整体查询效率
内容的提问来源于stack exchange,提问作者ShadowAccount
相关产品推荐
相关产品推荐

