php怎样获取本机ip并判断地域_php结合ip库定位法【技巧】

2026-01-31 00:00:00 作者:絕刀狂花
PHP获取服务器公网IP只能通过调用外部API(如api.ipify.org)或解析网卡地址(需过滤私有IP),$_SERVER['SERVER_ADDR']不可靠;ipip.net的ipdb库是离线地理定位最优选,支持IPv6且原生中文,优于需扩展和授权的MaxMind方案。

PHP 怎么拿到服务器本机的公网 IP(不是 127.0.0.1 或内网)

直接读 $_SERVER['SERVER_ADDR'] 多数情况下返回的是监听地址,比如 0.0.0.0127.0.0.1 或内网 IP(如 192.168.x.x),并不能反映真实对外 IP。真正能用的只有两种方式:

  • 调用外部 HTTP 接口(如 https://api.ipify.org 或国内可用的 https://myip.ipip.net),用 file_get_contents()curl 获取返回值,注意加超时和错误处理
  • 从网卡设备读取(Linux 下可用 exec('hostname -I') 或解析 /sys/class/net/ 下的 inet 地址),但需确保 PHP 有执行权限,且多网卡时要过滤掉 127.0.0.1 和私有地址段(10.0.0.0/8172.16.0.0/12192.168.0.0/16

不推荐依赖 $_SERVER['REMOTE_ADDR']——那是客户端 IP,不是本机。

用 ipip.net 免费库做地域识别(纯离线、无 API 调用)

ipip.net 提供的 ipdb 格式数据库(如 ipipfree.ipdb)是目前 PHP 离线定位最轻量可靠的方案,比老牌 qqwry.dat 更新勤、结构清晰、支持 IPv6。

  • 下载地址:官方 GitHub 发布页(搜 ipipnet/ipdb-php),选最新 .ipdb 文件
  • 安装扩展:composer require ipip/ipdb
  • 基础用法示例:

$db = new \Ipip\IPDB('/path/to/ipipfree.ipdb');
$result = $db->find('202.102.110.204', 'CN'); // 返回数组,含 country, province, city 等键
// 注意:第二个参数是语言代码,'CN' 表示中文字段;用 'EN' 则返回英文

首次加载 .ipdb 文件会有毫秒级开销,建议在常驻进程(如 Swoole)中复用实例,或用 opcache 加速反序列化。

为什么不用 GeoLite2 + MaxMind DB(常见踩坑点)

MaxMind 官方的 GeoLite2-Country.mmdb 确实权威,但 PHP 使用它有几个硬伤:

  • 必须装 maxminddb 扩展(非纯 PHP 实现),部分共享主机不支持
  • 免费版自 2025 年起需注册账号+API key 才能下载,且每月限次;离线使用也得填 license key 生成下载链接
  • geoip2/geoip2 Composer 包默认走在线查询,若没配好本地 DB 路径,会静默 fallback 到 HTTP 请求,导致超时或暴露 IP
  • 中文字段需额外映射(DB 里只有英文),不如 ipip.net 原生支持 'CN' 输出

除非项目已深度绑定 MaxMind 生态,否则没必要绕路。

IPv6 地址怎么查?要注意什么

ipip.net 的 .ipdb 支持 IPv6,但 PHP 中传入前必须标准化:

  • 不能直接用 $_SERVER['REMOTE_ADDR'] 原样传——IPv6 地址可能带方括号(如 [2001:db8::1])或压缩写法(::1
  • 先用 filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) 校验,再用 inet_pton() + inet_ntop() 归一化(去掉 :: 简写,补全为完整 128 位)
  • 某些 CDN(如 Cloudflare)会把 IPv6 客户端地址转成 IPv4 格式(100:: 开头的 IPv6-mapped IPv4),这种要提前识别并跳过地理库查询,否则结果错乱

真实环境里,IPv6 查询失败往往不是库问题,而是输入格式没规整——这点比 IPv4 容易忽略得多。

猜你喜欢

联络方式:

400 9058 355

邮箱:8955556@qq.com

Q Q:8955556

微信二维码
在线咨询 拨打电话

电话

400 9058 355

微信二维码

微信二维码