获取本机IP不能用$_SERVER['REMOTE_ADDR'],应绕开HTTP上下文;推荐用exec('ip -4 addr show eth0')解析具体网卡IPv4地址,或备选gethostbyname(gethostname())但有DNS依赖和单IP局限。

PHP 获取本机 IP 不是 $_SERVER['REMOTE_ADDR']
很多人一上来就用 $_SERVER['REMOTE_ADDR'],结果拿到的是客户端 IP,不是本机(服务器)IP。真要查 PHP 所在机器自己的 IP 地址,得绕开 HTTP 请求上下文,直接查系统网络接口。
用 gethostbyname() + gethostname() 最简但有局限
这是最轻量的组合,适合单网卡、主机名能正确解析的环境:
echo gethostbyname(gethostname());
但它依赖 DNS 或 /etc/hosts 配置。如果 gethostname() 返回 localhost 或解析失败,结果就是 127.0.0.1 或 false。常见于 Docker 容器、某些云主机或 /etc/hosts 被改写的情况。
- 只返回第一个 A 记录,不保证是外网 IP
- 无法区分 eth0、ens3、docker0 等具体网卡
- Windows 下可能返回 IPv6 地址(需额外过滤)
用 exec('ip addr show') 或 ifconfig 更可靠但需权限和命令支持
Linux 系统下推荐走系统命令,能精确控制网卡和地址类型:
立即学习“PHP免费学习笔记(深入)”;
$ip = exec("ip -4 addr show eth0 | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'");
注意点:
-
eth0要换成你实际主网卡名(可用ip link show查),云服务器常用ens3、ens5,Docker 里可能是eth1 -
ip命令比ifconfig更现代,但旧系统可能没装iproute2,可 fallback 到ifconfig eth0 | grep 'inet ' | awk '{print $2}' - PHP 进程需有执行 shell 命令权限(
disable_functions里不能禁掉exec、shell_exec) - 别漏掉
-4参数,否则可能混入 IPv6 地址
跨平台兼容方案:用 net_get_interfaces()(PHP 7.2+)
PHP 原生函数,不用依赖外部命令,但仅限较新版本:
$interfaces = net_get_interfaces();
foreach ($interfaces as $name => $iface) {
if (isset($iface['unicast'][0]['address']) && !filter_var($iface['unicast'][0]['address'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
echo $iface['unicast'][0]['address'];
break;
}
}
关键逻辑:
- 跳过
lo(回环)、docker0、veth*等非物理网卡 - 用
FILTER_FLAG_NO_PRIV_RANGE和FILTER_FLAG_NO_RES_RANGE排除私有网段(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)和保留地址,确保拿到的是公网可路由 IP(如果有的话) - 不同网卡可能有多个 unicast 地址,取第一个有效非私有地址即可
这个函数在 Windows 上也能用,但返回结构略有差异,建议加 isset() 判断字段存在性。
真正难的不是“怎么写一行代码”,而是判断你要的 IP 是什么:是监听服务用的绑定地址?是发 HTTP 请求时对外显示的出口 IP?还是容器内网通信用的 bridge IP?没明确场景,所有“获取本机 IP”方案都可能跑偏。











