• PHP 跟据用户IP获取所在国家高效解决方案(GEOIP)


    最近项目中有一个需求统计访客数据,为了保证效率。前端尽量轻量化,仅将访客原始请求信息不作任何处理直接写入消息队列。后端计划任务服务器监听消息队列,解析 user agent, ip 地址,处理结果写入 ES  供报表使用,其中 IP地址处理需要跟据 IP地址获取国家,本文主要研究解决PHP语言跟据IP获取国家的单一需求。

    首先解决数据源

    1 纯真IP库
        缺点:主要为国内IP库,如果仅需要国家信息,则冗余信息多,解析效率低
    2 高用第三方接口(如:ip138)解析。
        缺点:延时高,稳定性差

    排除以上数据源方案。

    当前比较可靠的数据源:GEOIP 库,商业化运作,更新频率很高,有提供免费的IP库供下载

    官网:
    https://geoip.com/
    https://www.maxmind.com/

    这两个网站是同一家公司。

    PHP官方 支持 geoip 扩展,相关方法见官方文档: 
    https://www.php.net/manual/zh/book.geoip.php

    更多的时候,项目不方便安装扩展,可以使用纯 php 的 composer 安装包

    官方开发的 PHP composer 安装包:

    在 composer 包管理网站 packagist.org 搜 geoip
    排名靠前的. geoip2/geoip2,maxmind-db/reader, geoip/geoip 是官方提供的安装包,其中 "geoip/geoip". Abandoned,转到了 geo2/geoip2,
     



    下载库文件:

    composer requre geoip2/geoip2


    编写代码前,首先需要下载最新版的 IP数据库, 官网下载地址:

    https://www.maxmind.com/en/geoip2-country-database

    默认是商业版,下载需要一定的费用。支持一次性/按月/按年三种付费方式
     




    同时,官方提供了免费版本,首先在官网注册一个账号,成功后使用账号登录,在用户中心 点 "download files" 下载相关文件


     

     

    程序示例:

    1. // 指定 IP数据库,在调用代码中引用该文件:
    2. $reader = new \GeoIp2\Database\Reader('/path/tp/your/GeoLite2-Country.mmdb');
    3. $record = $reader->country('128.101.101.101');
    4. print($record->country->isoCode . "\n"); // 'US'
    5. print($record->country->name . "\n"); // 'United States'
    6. print($record->country->names['zh-CN'] . "\n"); // '美国'
    7. ?>


    简单测试下效率:

    1. $reader = new \GeoIp2\Database\Reader( '/path/tp/your/GeoLite2-Country.mmdb');
    2. $success = 0;
    3. $t0 = microtime(1);
    4. for ($i = 0; $i<2000; $i++) {
    5. try {
    6. $ip = rand(1,255) . '.' . rand(1,255) . '.' .rand(1,255) . '.' . rand(1,255);
    7. $record = $reader->country($ip);
    8. // echo $ip . ':' . $record->country->isoCode . "
      \r\n";
    9. $success++;
    10. } catch (\Throwable $t) {
    11. }
    12. }
    13. $t1 = microtime(1);
    14. echo '用时:' . number_format($t1 - $t0, 3, '.', '') . '秒
      '
      ;
    15. echo '有效IP: ' . $success . ' 个';
    16. ?>


    18款MAC笔记本电脑(4核16G 固态硬盘) docker 环境运行结果:
    用时:0.834秒
    有效IP: 1723 个

    随机生成的IP有一部分无效,相当于1秒执行了 2000+ 随机IP查询,已经相当高了,这种高IO 的查询操作固态硬盘是主要因素


    如果有更高的效率需求,可以将 IP数据库转入 REDIS
    跟据CSV版本的IP数据,当前版本的 IPv4(IPv6 应该需求不多) 数据库仅有 37万多条记录(3711110),

    GeoLite2-Country-Blocks-IPv4.csv 内容示例:

    network,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider
    1.0.0.0/24,2077456,2077456,,0,0
    1.0.1.0/24,1814991,1814991,,0,0
    1.0.2.0/23,1814991,1814991,,0,0
    1.0.4.0/22,2077456,2077456,,0,0
    1.0.8.0/21,1814991,1814991,,0,0
    ...
    223.255.244.0/22,1269750,1269750,,0,0
    223.255.248.0/22,1819730,1819730,,0,0
    223.255.252.0/23,1814991,1814991,,0,0
    223.255.254.0/24,1880251,1880251,,0,0
    223.255.255.0/24,2077456,2077456,,0,0

    其中第一列 network 为网段/子网掩码,geoname_id 等列关联了另一个 csv 中的国家信息元数据。

    可以以网段为键名(可IP2Long 转INT),子网掩码+对应的国家二字码为键值 存入 redis, 以内存换取更快的IO操作,相信查询效率会有更大提升。


    国为当前项目是在计划任务中执行,有消息队列缓冲,可多台计划任务服务器并行处理。官方 composer 库效率也足够高,暂时不折腾了,以后有机会了再尝试 REDIS 方案

    本文原始网址:PHP 跟据用户IP获取所在国家高效解决方案(GEOIP),转载请保留出处

  • 相关阅读:
    结构与联合
    es部署保姆教程
    Hive日分区表如何快速导入到StarRocks
    阿里云服务器经济型e实例租用价格和CPU性能测评
    绕过防盗链的几种方式
    等级保护详解
    Typora收费了,于是乎我自己写了一个
    Freeswitch中Java ESL Client
    Python环境下LaTeX数学公式转图像方案调研与探讨
    Spring Security认证器实现
  • 原文地址:https://blog.csdn.net/iua1024/article/details/125898081