php获取本机ip返回错误段咋校验_php合法ip校验法【步骤】

1次阅读

应使用ip2long转整型后按RFC标准位运算校验:先filter_var验证IPv4格式,再排除127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、100.64.0.0/10及0.0.0.0和255.255.255.255。

php获取本机ip返回错误段咋校验_php合法ip校验法【步骤】

php 获取本机 IP 时返回 127.0.0.1 或私有段,怎么判断它不合法?

PHP 中用 $_SERVER['SERVER_ADDR']gethostbyname(gethostname()) 拿到的“本机 IP”,很可能只是回环地址或内网地址(如 127.0.0.1192.168.x.x10.x.x.x172.16.x.x–172.31.x.x),不能直接用于外网通信或日志标记。关键不是“获取失败”,而是“获取到了但不可用”。

校验逻辑必须分两步:先确认是否为 IPv4 地址格式,再排除所有 RFC 1918 / RFC 5735 定义的保留段。

  • filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) 是基础门槛,过滤掉空值、ipv6、格式错误
  • 接着用 ip2long($ip) 转整型后做位运算比字符串匹配更可靠(避免 strpos 误判 192.168.10.1 匹配到 192.168 就截断)
  • 特别注意 0.0.0.0255.255.255.255 也属于非法主机地址,需单独排除

用 ip2long 做私有网段精确拦截(推荐写法)

字符串前缀匹配易出错,比如 stripos($ip, '10.') === 0 会漏掉 10.0.0.1 以外的变体,也挡不住 100.64.0.0/10(CGNAT 段)。用整型比较最稳:

function isValidpublicIp($ip) {     if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {         return false;     }     $ipLong = ip2long($ip);     if ($ipLong === false || $ipLong === -1) return false;      // 127.0.0.0/8     if (($ipLong & 0xFF000000) === 0x7F000000) return false;     // 10.0.0.0/8     if (($ipLong & 0xFF000000) === 0x0A000000) return false;     // 172.16.0.0/12     if (($ipLong & 0xFFF00000) === 0xAC100000) return false;     // 192.168.0.0/16     if (($ipLong & 0xFFFF0000) === 0xC0A80000) return false;     // 100.64.0.0/10(CGNAT)     if (($ipLong & 0xFFC00000) === 0x64400000) return false;     // 0.0.0.0/8 和 255.255.255.255     if ($ipLong === 0 || $ipLong === 0xFFFFFFFF) return false;      return true; }

$_SERVER[‘SERVER_ADDR’] 为什么经常不准?

这个值取决于 Web 服务器(apache/nginx)绑定的监听地址,不是系统真实网卡 IP。常见陷阱:

立即学习PHP免费学习笔记(深入)”;

  • Nginx 反向代理后,PHP 看到的是 Nginx 所在机器的 127.0.0.1,不是源服务器外网 IP
  • docker 容器里默认只有 172.17.0.x 等桥接地址,SERVER_ADDR 返回的是容器内网 IP
  • 多网卡服务器若 Apache 绑定在 192.168.1.100,就拿不到公网 203.0.113.5
  • 云厂商(如阿里云腾讯云)的元数据服务返回的才是真实弹性公网 IP,需主动调用 curl http://100.100.100.200/latest/meta-data/public-ipv4

别信 gethostbyname(gethostname()) —— 它根本不可靠

该组合在多数 linux 发行版上返回 127.0.0.1,因为 /etc/hosts 通常把 hostname 映射到本地回环。即使改 hosts,也无法覆盖多网卡、虚拟化、容器等场景。

真正需要本机公网 IP 的业务(比如注册 webhook 回调地址、生成签名用的源 IP),应该:

  • 运维侧明确配置一个 app_PUBLIC_IP 环境变量
  • 从云平台元数据接口拉取(注意超时和重试)
  • 启动时用 ip route get 1.1.1.1 | awk '{print $7}' 类命令查默认出口 IP(仅限有路由能力的环境)

IP 校验本身不难,难的是搞清你到底要哪个“本机”——是监听地址?出口地址?还是部署环境承诺的对外服务地址?没想清楚这点,代码写得再严谨也没用。

text=ZqhQzanResources