PHP获取域名及其对应IP地址,核心是分开处理“当前访问域名”和“目标域名解析”:当前域名取 $_SERVER['HTTP_HOST'] 或 parse_url(),对应IP用 gethostbyname()、dns_get_record() 或 cURL 的 CURLINFO_PRIMARY_IP。 多数业务只需要其中一两步,不必把DNS查询和HTTP请求混在一起。
PHP获取当前访问域名和对应IP的基础方法
PHP如何获取当前访问域名和IP地址?先分清请求上下文
当前请求的域名通常来自HTTP头,而不是DNS查询结果,常见取值有:
$_SERVER['HTTP_HOST']:包含端口,example.com:8080。$_SERVER['SERVER_NAME']:来自服务器配置,可能和用户访问域名不一致。parse_url('https://www.example.com/a', PHP_URL_HOST):从完整URL中提取主机名。
如果只想拿域名,建议先去掉端口并转小写:
$host = $_SERVER['HTTP_HOST'] ?? '';
$host = strtolower(explode(':', $host)[0]);
当前服务器的IP可用 $_SERVER['SERVER_ADDR'],客户端IP用 $_SERVER['REMOTE_ADDR'],代理场景下会有 X-Forwarded-For,但这个头可伪造,必须配合可信代理白名单使用。
目标域名解析:gethostbyname 与 dns_get_record 怎么选
PHP内置函数足够应付大多数域名转IP需求,关键差别如下:
| 方法 | 支持IPv6 | 解析方式 | 适用场景 | |
|---|---|---|---|---|
gethostbyname() |
单个IPv4 | 否 | 系统解析器 | 快速查A记录 |
gethostbynamel() |
IPv4数组 | 否 | 系统解析器 | 一个域名多个A记录 |
dns_get_record() |
A、AAAA、MX等记录 | 是 | DNS查询 | 需要记录类型、IPv6 |
cURL CURLINFO_PRIMARY_IP |
实际连接IP | 是 | HTTP连接 | 重定向、CDN、真实访问IP |
gethostbyname() 失败时会返回原域名,所以判断时要检查返回值是否为合法IP:
$ip = gethostbyname($host);
if (filter_var($ip, FILTER_VALIDATE_IP)) {
echo $ip;
} else {
echo '解析失败';
}
dns_get_record() 更适合拿多条记录:
$records = dns_get_record($host, DNS_A | DNS_AAAA);
foreach ($records as $r) {
if (!empty($r['ip'])) echo $r['ip'];
if (!empty($r['ipv6'])) echo $r['ipv6'];
}
据IANA(互联网号码分配机构)公开说明,A记录用于IPv4,AAAA记录用于IPv6,需要IPv6时,不要只依赖 gethostbyname()。
从完整URL中提取域名并查询IP
用户输入往往是URL,不是纯域名,先校验,再解析:
$url = 'https://www.example.com/path?x=1';
if (!filter_var($url, FILTER_VALIDATE_URL)) {
exit('URL不合法');
}
$host = parse_url($url, PHP_URL_HOST);
$ip = gethostbyname($host);
国际化域名可先转ASCII,再查询,对于后台采集、回调白名单、日志归因这类场景,限制协议和域名格式比解析本身更重要。
PHP获取域名IP地址的几种方法对比:gethostbyname、dns_get_record 与 cURL
gethostbyname 系列:简单但信息有限
gethostbyname() 和 gethostbynamel() 走系统解析器,会受 /etc/hosts、DNS缓存和本机配置影响,优点是代码短,适合快速判断域名是否能解析,缺点是不返回TTL、不返回记录类型,也不支持IPv6。
dns_get_record:更适合做记录级查询
dns_get_record() 直接查询DNS记录,可拿到A、AAAA、CNAME、MX、TXT等,做域名健康检查、邮件域校验、CDN识别时更合适,它不经过系统hosts的同样逻辑,结果更接近DNS服务端返回。

cURL:拿实际连接IP
如果域名走了CDN,或者URL会重定向,gethostbyname() 拿到的可能只是某个解析节点,cURL 的 CURLINFO_PRIMARY_IP 返回实际建立连接的IP:
$ch = curl_init('https://www.example.com/');
curl_setopt_array($ch, [
CURLOPT_NOBODY => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 3,
CURLOPT_TIMEOUT => 5,
]);
curl_exec($ch);
$ip = curl_getinfo($ch, CURLINFO_PRIMARY_IP);
curl_close($ch);
这个方法适合排查“域名解析正常但访问异常”的问题,如果预算有限,PHP获取域名IP地址免费方案通常优先用内置函数加公共DNS,成本为零,也便于部署。
北京PHP项目里常见的域名解析获取IP方案
在北京机房或华北地区部署的PHP项目,常见需求是判断域名解析是否生效、采集目标站IP、做回源检查,可以按场景选:
- 后台脚本查IP:
gethostbyname()加缓存。 - 域名健康检查:
dns_get_record()查A和AAAA。 - 访问链路排查:cURL 取
CURLINFO_PRIMARY_IP。 - 命令行验证:
dig @223.5.5.5 example.com +short或nslookup example.com。 - 本地开发:检查
/etc/hosts,避免hosts覆盖导致结果和线上不同。
在北京、上海、深圳等不同地域,递归DNS和线路可能返回不同IP,业内专家指出,同一域名在不同网络下解析到不同节点属于常见调度现象,不能简单判断为故障。
域名有CDN时,PHP获取到的IP为什么不是源站?
CDN会把域名解析到边缘节点IP,PHP通过公网DNS或cURL拿到的,通常是离用户较近的CDN节点,不是源站服务器,行业共识认为,获取到的IP通常只是当前解析链路返回的接入IP,不等同于服务器真实源站。
想确认源站,需要从这些地方核对:

- DNS服务商控制台的回源配置。
- 源站服务器网卡IP和内网IP。
- CDN回源日志中的真实源站地址。
- 负载均衡、WAF或反向代理的转发配置。
直接通过公网域名反查源站,多数情况下不可行,也不建议绕过CDN防护。
PHP域名解析慢怎么办:缓存、超时与并发
DNS查询可能阻塞PHP进程,尤其是循环查大量域名时,处理思路:
- 缓存解析结果:用APCu、Redis或本地文件,按TTL设置过期时间。
- 设置超时:cURL用
CURLOPT_CONNECTTIMEOUT,避免长时间等待。 - 批量并发:
curl_multi_同时查询多个URL,减少串行耗时。 - 限制重试:失败后最多重试一次,避免雪崩。
- 记录日志:保存域名、返回IP、耗时、错误码,方便定位。
gethostbyname() 本身没有直接超时参数,对稳定性要求高的任务,优先用cURL或异步DNS扩展,PHP的 dns_get_record() 在部分Windows环境行为不一致,生产环境要验证。
把场景分清,再选函数和缓存策略,PHP获取域名及其对应IP地址就不容易踩坑。 当前域名看请求头,目标域名看解析函数,实际连接IP看cURL。
Q&A:PHP获取域名及其对应IP地址常见问题
gethostbyname 返回域名本身是什么原因?
说明解析失败或返回了非IP结果,检查域名拼写、DNS配置、网络连通性,以及 /etc/hosts 是否有覆盖,用 dns_get_record() 或 dig 交叉验证。
PHP能获取IPv6地址吗?
可以,用 dns_get_record($host, DNS_AAAA) 获取AAAA记录。gethostbyname() 只返回IPv4,不适合IPv6场景,Web服务器和网络也要支持IPv6,否则拿到地址也无法连接。
获取到的IP是CDN节点,怎么拿源站IP?
公网DNS通常只能返回CDN节点IP,源站IP需要从服务器配置、DNS服务商控制台或回源日志中核对。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/909206.html


评论列表(1条)
读了这篇文章,我深有感触。作者对记录的理解非常深刻,论述也很有逻辑性。内容既有理论深度,又有实践指导意义,确实是一篇值得细细品味的好文章。希望作者能继续创作更多优秀的作品!