获取本机IP不能用$_SERVER['REMOTE_ADDR'](返回客户端IP),应通过系统命令如ip addr show或ipconfig结合正则提取,并用filter_var校验排除私有/保留地址。

PHP 获取本机 IP 不能靠 $_SERVER['REMOTE_ADDR']
想拿服务器自己的公网或内网 IP,却误用了 $_SERVER['REMOTE_ADDR']——它返回的是客户端(比如浏览器)的 IP,不是 PHP 所在机器的。真要取本机 IP,得走系统命令或网络接口查询,正则只是后续清洗手段,不是源头。
常见错误现象:$_SERVER['SERVER_ADDR'] 看似合理,但它可能返回 127.0.0.1(尤其 Nginx + PHP-FPM 反向代理时),或绑定在 localhost 的任意地址,不可靠。
- 用
gethostbyname(gethostname())最简,但只返回首个 A 记录,可能仍是127.0.0.1 - 更稳的方式是执行
ip addr show(Linux)或ipconfig(Windows),再用正则提取非回环、非空链路本地的 IPv4 - 注意:PHP 需开启
shell_exec,且 Web 服务器用户要有对应命令权限
preg_match 提取 IPv4 地址的可靠正则模式
别用网上泛滥的 /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/——它会匹配 999.999.999.999 这种非法 IP,也抓不到 CIDR 掩码后的地址(如 192.168.1.10/24)。
真正实用的模式是:
立即学习“PHP免费学习笔记(深入)”;
/(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\/\d{1,2})?/
这个正则做了三件事:
从 ip addr show 输出中过滤出有效 IPv4(排除 127.0.0.0/8 和 169.254.0.0/16)
Linux 下 ip addr show 输出含多行 inet,但包括 loopback、link-local、Docker bridge 等无效地址。光靠正则不够,得结合上下文过滤。
实操建议:
- 先用
shell_exec('ip -4 addr show | grep "inet "')只取 IPv4 行 - 逐行用
preg_match()提取 IP,再用filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)排除私有网段和保留地址 - 若需优先选“主网卡”,可限定接口名,例如
ip -4 addr show eth0或ens33,避免取到虚拟网卡
示例片段:
$output = shell_exec('ip -4 addr show | grep "inet "');
$ips = [];
if ($output) {
foreach (explode("\n", trim($output)) as $line) {
if (preg_match('/inet\s+([0-9.]+)\/\d+/i', $line, $m)) {
$ip = $m[1];
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$ips[] = $ip;
}
}
}
}
Windows 下 ipconfig 的适配要点
Windows 的 ipconfig 输出格式不统一:中文系统带“IPv4 地址”,英文系统是 “IPv4 Address”,还夹杂换行和空格。直接硬匹配容易断裂。
关键处理点:
- 用
shell_exec('ipconfig | findstr /R "IPv4.*:"')(英文)或findstr "IPv4"(中文)缩小范围 - 正则改用宽松匹配:
/IPv4[\s\S]*?:\s*([0-9.]+)/i,容忍中间任意空白和换行 - 必须做二次校验:
filter_var($ip, FILTER_VALIDATE_IP),因为ipconfig可能输出0.0.0.0(未获取到 DHCP) - 注意:IIS 或某些安全策略会禁用
shell_exec,此时只能退回到gethostbyname(gethostname())并接受其局限性
复杂点在于,没有一个函数能跨平台、无条件返回“正确”的本机 IP;你得根据部署环境(容器?云主机?WAMP?)、权限、是否代理,组合判断。正则只是工具链里最末端的一环,前置逻辑比匹配本身更重要。











