关于把 IP 地址转换为地理位置可以使用网络上很多的 API,好处就是不用在本地存储一个 IP 数据库,而且一般网络上的 IP 库会自动更新,不利的地方就是太依赖于网络,性能表现也可能会弱些。比如像下面的 API:
http://api.hostip.info/get_html.php?ip=58.63.236.31
http://api.hostip.info/flag.php?ip=58.63.236.31
这里介绍 PHP 如何使用 GeoLiteCity.dat 库把 IP 转换为地理位置,GeoLiteCity.dat 可以在 http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz 下,解压出 GeoLiteCity.dat,即可,我们可以手动去更新新的 IP 库。
下面 PHP 解析 IP 的过程参考自 WordPress 插件 Visitor Maps and Who's Online 的实现。可以找到该插件的两个文件 include-whos-online-geoip.php 和 visitor-maps.php 告诉了我们怎么做。你可以点击这里的链接下载到这两个文件,我这里把 include-whos-online-geoip.php 改名为 geoipcity.inc.php,然后参考 visitor-maps.php 中的 get_location_info($user_ip) 函数,那么我们可以写出自己的解析 IP 地址的程序 resolve_ip.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<?php require_once("geoipcity.inc.php"); //ini_set("memory_limit","96M"); //最简单的函数只要这一个 function get_ip_record($user_ip) { global $path_visitor_maps; //假定 GeoLiteCity.data 放在与此文件同一目录下 $gi = geoip_open_VMWO('GeoLiteCity.dat', VMWO_GEOIP_STANDARD); $record = geoip_record_by_addr_VMWO($gi, "$user_ip"); geoip_close_VMWO($gi); //你可以直接使用上面取出的 $record 数据 return $record; } function get_location_info($user_ip) { $record = get_ip_record($user_ip); //或者使用下面加工后的 $location_info global $GEOIP_REGION_NAME; $location_info = array(); // Create Result Array $location_info['city_name'] = (isset($record->city)) ? $record->city : ''; //城市 $location_info['state_name'] = (isset($record->country_code) && isset($record->region)) //州名 ? $GEOIP_REGION_NAME[$record->country_code][$record->region] : ''; $location_info['state_code'] = (isset($record->region)) ? strtoupper($record->region) : ''; //州代号 $location_info['country_name'] = (isset($record->country_name)) ? $record->country_name : '--'; //国家名 $location_info['country_code'] = (isset($record->country_code)) ? strtoupper($record->country_code) : '--'; //国家代号 $location_info['latitude'] = (isset($record->latitude)) ? $record->latitude : '0'; //维度 $location_info['longitude'] = (isset($record->longitude)) ? $record->longitude : '0'; //经度 //php 站点设置了 utf-8 字符集必要时进行转码 $charset = 'utf-8'; // this fixes accent characters on UTF-8, only when the blog charset is set to UTF-8 if ( strtolower($charset) == 'utf-8' && function_exists('utf8_encode') ) { if ($location_info['city_name'] != '' ) { $location_info['city_name'] = utf8_encode($location_info['city_name']); } if ($location_info['state_name'] != '') { $location_info['state_name'] = utf8_encode($location_info['state_name']); } if ($location_info['country_name'] != '') { $location_info['country_name'] = utf8_encode($location_info['country_name']); } } return $location_info; } //查询一个 IP 测试下 $record = get_ip_record("206.19.49.154"); var_dump($record); $location = get_location_info("206.19.49.154"); var_dump($location); ?> |
执行后输出如下(可以作为系统脚本直接用 php resolve_ip.php 来执行):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
object(geoiprecord_VMWO)#2 (10) { ["country_code"]=> string(2) "US" ["country_code3"]=> string(3) "USA" ["country_name"]=> string(13) "United States" ["region"]=> string(2) "TX" ["city"]=> string(10) "Richardson" ["postal_code"]=> string(5) "75080" ["latitude"]=> float(32.9722) ["longitude"]=> float(-96.7376) ["area_code"]=> int(972) ["dma_code"]=> float(623) } array(7) { ["city_name"]=> string(10) "Richardson" ["state_name"]=> string(5) "Texas" ["state_code"]=> string(2) "TX" ["country_name"]=> string(13) "United States" ["country_code"]=> string(2) "US" ["latitude"]=> float(32.9722) ["longitude"]=> float(-96.7376) } |
只要取你想要的数据就是了,里面还有诸如区号,邮编等数所,GeoLiteCity.dat 是个二进制文件,比普通文本要紧凑省空间。
不知道您有没有多留一份心,有无浏览链接:http://geolite.maxmind.com/download/geoip/api/php/,是这样的:
看到 GeoIp 给我们提供了不少的例子,那么多 sample.php,而实际上前面用到的 geoipcity.inc.php,就是 geopip.inc、geoipcity.inc 和 geoipregionvars.php 三个程序的内容合体。
再往上看:
官方提供的 API 何止 PHP 啊,几乎能全线满足您的实际需求了,c、java、perl、python、vb、ruby、tcl 等......,放其他程序里以后也不用愁了。
再进到 http://geolite.maxmind.com/download/geoip/database/ 瞧瞧:
正考虑着呢,不是说 IPv4 快用净了吗?IPv6 的数据也正为我们准备着呢?当然,天朝的 IPv9 恐怕永远不会有的。
本只是把 Visitor Maps and Who's Online 里的解析 IP 的做法抽出来用用,可总能不断 深入再深入,不知道可喜还是可怕了。
本文链接 https://yanbin.blog/php-geolitecity-ip-location/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。