推荐使用 net_get_interfaces()(PHP 8.1+)或解析 /proc/net/fib_trie(Linux)获取本机IP,避免 system() 调用和 gethostbyname(gethostname()) 的安全与准确性问题。

用 system() 调用 shell 命令获取本机 IP 在 PHP 中不推荐
直接调用 system("hostname -I") 或 system("ip addr show") 看似简单,但存在权限、环境依赖、输出不可控、安全风险等硬伤。PHP 进程若在容器或受限用户下运行,system() 很可能失败或返回空;更严重的是,一旦命令拼接中混入用户输入(哪怕只是日志路径),就构成命令注入漏洞。
gethostbyname(gethostname()) 为什么常返回 127.0.0.1
这是最常见误用:PHP 的 gethostname() 返回主机名(如 web-server),而 gethostbyname() 是查 DNS——本地 /etc/hosts 里往往只配了 127.0.0.1 web-server,结果必然回环地址。它不查网卡配置,也不考虑多网卡或多 IP 场景。
- 仅适用于 DNS 显式解析到真实外网 IP 的极少数部署
- 无法区分 IPv4/IPv6,无法跳过 lo 接口
- DNS 查询有延迟,且失败时返回 false,需额外容错
可靠方式:用 net_get_interfaces()(PHP 8.1+)或解析 /proc/net/fib_trie
PHP 8.1 引入的 net_get_interfaces() 是目前最干净的内置方案,能枚举所有接口及对应 IPv4/IPv6 地址,并过滤掉 lo、docker0 等非业务网卡:
$interfaces = net_get_interfaces();
foreach ($interfaces as $name => $iface) {
if ($name === 'lo') continue;
foreach ($iface['unicast'] as $addr) {
if (filter_var($addr['address'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
echo $addr['address']; // 如 192.168.1.10
break 2;
}
}
}
若 PHP 版本低于 8.1,可读取 Linux 系统文件 /proc/net/fib_trie(仅限 Linux):
立即学习“PHP免费学习笔记(深入)”;
- 比调用 shell 更轻量、无权限问题
- 输出稳定,无需解析复杂命令行格式
- 注意跳过
0.0.0.0和127.0.0.0/8段
Web 场景下「本机 IP」到底指什么?别混淆监听地址和出口地址
很多人没想清楚需求本质:
– 如果是让服务监听某 IP(如 0.0.0.0:8080),应看 $_SERVER['SERVER_ADDR'](但仅限 CGI/FPM 下有效);
– 如果是向外部 API 发起请求时想知道自己从哪个 IP 出去,得用 curl 实际连一次公网 DNS(如 curl https://api.ipify.org);
– 如果是容器内服务间通信,通常该用服务发现(Consul/K8s Service),而非硬编码 IP。
真正需要「本机网卡 IP」的场景极少,多数时候你真正要的只是一个可被对端访问的、稳定的网络标识——这时候用主机名 + 正确 DNS 解析,比抓 IP 更健壮。











