设为首页 收藏本站
查看: 1183|回复: 0

[经验分享] PHP转换IP地址到真实地址

[复制链接]

尚未签到

发表于 2018-12-20 07:23:09 | 显示全部楼层 |阅读模式
  

生在红旗下长在春风里,长期浸泡在河蟹社会里面所以久而久之就有了一些河蟹的思维方式,正好有一段时间在做一个.NET的网站访问统计系统,顺便想着怎么“监视”下每一个留言的博主们的所在地,于是就有了如今下图(网易留言板的样式)所示的根据获取到的留言者的IP地址得到留言者所在的地区,当然并没有河蟹社会监视人民群众的意思,纯属了解一下各位博主所在的真实地点,万一是个美女博主不就可以让我有线索可循。

想要把IPv4地址转为真实的地址,肯定要参考IP数据库,商业的IP数据库存储在关系型数据库中,查询和使用都非常方便,但是成本不是个人和小公司愿意承受的,所以简单应用的思路就是利用一些免费的IP数据库或者一些大网站提供的查询API,他们的数据量足够我们使用了。

1. 利用纯真IP数据库

利用本地的QQWry.Dat文件,优点是查询速度非常快,缺点是数据库文件要放在自己的空间内并且要偶尔更新数据库。时间关系废话不多说,下面是使用这个文件的函数,如果是在WordPress里面使用这个功能,把下面的代码写入主题下面的functions.php里面,然后在comments-list的输出即可;如果是其他程序引用,输入一个有效的IPv4地址就可以得到一个真实的地址。



  • function convertip($ip) {
  •     //IP数据文件路径
  •     $dat_path = 'QQWry.Dat';

  •     //检查IP地址
  •     //if(!preg_match("/^d{1,3}.d{1,3}.d{1,3}.d{1,3}$/", $ip)) {
  •     //    return 'IP Address Error';
  •     //}
  •     //打开IP数据文件
  •     if(!$fd = @fopen($dat_path, 'rb')){
  •         return 'IP date file not exists or access denied';
  •     }

  •     //分解IP进行运算,得出整形数
  •     $ip = explode('.', $ip);
  •     $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];

  •     //获取IP数据索引开始和结束位置
  •     $DataBegin = fread($fd, 4);
  •     $DataEnd = fread($fd, 4);
  •     $ipbegin = implode('', unpack('L', $DataBegin));
  •     if($ipbegin < 0) $ipbegin += pow(2, 32);
  •     $ipend = implode('', unpack('L', $DataEnd));
  •     if($ipend < 0) $ipend += pow(2, 32);
  •     $ipAllNum = ($ipend - $ipbegin) / 7 + 1;

  •     $BeginNum = 0;
  •     $EndNum = $ipAllNum;

  •     //使用二分查找法从索引记录中搜索匹配的IP记录
  •     while($ip1num>$ipNum || $ip2num $ipNum) {
  •             $EndNum = $Middle;
  •             continue;
  •         }

  •         //取完上一个索引后取下一个索引
  •         $DataSeek = fread($fd, 3);
  •         if(strlen($DataSeek) < 3) {
  •             fclose($fd);
  •             return 'System Error';
  •         }
  •         $DataSeek = implode('', unpack('L', $DataSeek.chr(0)));
  •         fseek($fd, $DataSeek);
  •         $ipData2 = fread($fd, 4);
  •         if(strlen($ipData2) < 4) {
  •             fclose($fd);
  •             return 'System Error';
  •         }
  •         $ip2num = implode('', unpack('L', $ipData2));
  •         if($ip2num < 0) $ip2num += pow(2, 32);

  •         //没找到提示未知
  •         if($ip2num < $ipNum) {
  •             if($Middle == $BeginNum) {
  •                 fclose($fd);
  •                 return 'Unknown';
  •             }
  •             $BeginNum = $Middle;
  •         }
  •     }

  •     $ipFlag = fread($fd, 1);
  •     if($ipFlag == chr(1)) {
  •         $ipSeek = fread($fd, 3);
  •         if(strlen($ipSeek) < 3) {
  •             fclose($fd);
  •             return 'System Error';
  •         }
  •         $ipSeek = implode('', unpack('L', $ipSeek.chr(0)));
  •         fseek($fd, $ipSeek);
  •         $ipFlag = fread($fd, 1);
  •     }

  •     if($ipFlag == chr(2)) {
  •         $AddrSeek = fread($fd, 3);
  •         if(strlen($AddrSeek) < 3) {
  •             fclose($fd);
  •             return 'System Error';
  •         }
  •         $ipFlag = fread($fd, 1);
  •         if($ipFlag == chr(2)) {
  •             $AddrSeek2 = fread($fd, 3);
  •             if(strlen($AddrSeek2) < 3) {
  •                 fclose($fd);
  •                 return 'System Error';
  •             }
  •             $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
  •             fseek($fd, $AddrSeek2);
  •         } else {
  •             fseek($fd, -1, SEEK_CUR);
  •         }

  •         while(($char = fread($fd, 1)) != chr(0))
  •             $ipAddr2 .= $char;

  •         $AddrSeek = implode('', unpack('L', $AddrSeek.chr(0)));
  •         fseek($fd, $AddrSeek);

  •         while(($char = fread($fd, 1)) != chr(0))
  •             $ipAddr1 .= $char;
  •     } else {
  •         fseek($fd, -1, SEEK_CUR);
  •         while(($char = fread($fd, 1)) != chr(0))
  •             $ipAddr1 .= $char;

  •         $ipFlag = fread($fd, 1);
  •         if($ipFlag == chr(2)) {
  •             $AddrSeek2 = fread($fd, 3);
  •             if(strlen($AddrSeek2) < 3) {
  •                 fclose($fd);
  •                 return 'System Error';
  •             }
  •             $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
  •             fseek($fd, $AddrSeek2);
  •         } else {
  •             fseek($fd, -1, SEEK_CUR);
  •         }
  •         while(($char = fread($fd, 1)) != chr(0)){
  •             $ipAddr2 .= $char;
  •         }
  •     }
  •     fclose($fd);

  •     //最后做相应的替换操作后返回结果
  •     if(preg_match('/http/i', $ipAddr2)) {
  •         $ipAddr2 = '';
  •     }
  •     $ipaddr = &quot;$ipAddr1 $ipAddr2&quot;;
  •     $ipaddr = preg_replace('/CZ88.Net/is', '', $ipaddr);
  •     $ipaddr = preg_replace('/^s*/is', '', $ipaddr);
  •     $ipaddr = preg_replace('/s*$/is', '', $ipaddr);
  •     if(preg_match('/http/i', $ipaddr) || $ipaddr == '') {
  •         $ipaddr = 'Unknown';
  •     }
  •     $ipaddr = iconv('gbk', 'utf-8//IGNORE', $ipaddr); //转换编码,如果网页的gbk可以删除此行
  •     return $ipaddr;
  • }



2. 利用门户网站的接口

目前已知的有腾讯、新浪、网易、搜狐和Google提供IP地址查询API,但是找得到的只有腾讯、新浪和网易的,Google的貌似要用Google Maps所以没有研究。看了下国内的几个腾讯提供的是JavaScript的,网易提供的是XML,而新浪的有多种格式可以用,注意非XML的数据源都是GBK格式的,不管是JavaScript调用还是PHP调用都要转换一下编码,不然得到的是乱码。而更需要注意的是,如果一次性查询多个IP,使用门户网站的API来查询会非常缓慢,我大概写了个for循环试了下,不管是用PHP解析XML还是file_get_contents()函数获取内容,查询10次以上会变得非常缓慢,甚至可能超时。
腾讯的IP地址API接口地址:http://fw.qq.com/ipaddress,返回的是数据格式为:var IPData = new Array(&quot;123.124.2.85&quot;,&quot;&quot;,&quot;北京市&quot;,&quot;&quot;);,一个JavaScript的对象,目前还不知道如何输入IP查询。
新浪的IP地址查询接口:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js
新浪多地域测试方法:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=123.124.2.85
  网易有道的IP地址查询接口:http://www.youdao.com/smartresult-xml/search.s?type=ip&q=123.124.2.85

  腾讯的调用方法


  • //腾讯API的PHP调用方法
  • function getIpPlace(){
  • $ip=file_get_contents(&quot;http://fw.qq.com/ipaddress&quot;);
  • $ip=str_replace('&quot;',' ',$ip);
  • $ip2=explode(&quot;(&quot;,$ip);
  • $a=substr($ip2[1],0,-2);
  • $b=explode(&quot;,&quot;,$a);
  • return $b;
  • }
  • $ip=getIpPlace();
  • print_r($ip);



  网易有道的调用方法


  • //有道API的PHP调用方法
  • $url = &quot;http:www.youdao.com/smartresult-xml/search.s?type=ip&q=&quot;.$ip;
  • $doc = new DOMDocument();
  •    $doc->load($url);
  •    $smartresult = $doc->getElementsByTagName(&quot;product&quot;);
  •    foreach($smartresult as $product)
  •    {
  •       $locations = $product->getElementsByTagName(&quot;location&quot;);
  •       $location = $locations->item(0)->nodeValue;
  •    }
  •    if($location != &quot;&quot;)
  •    {
  •        echo $i.&quot;.&quot;.$ip;
  •        echo &quot;  来自&quot;.$location.&quot;的网友&quot;;
  •    }
  •    else
  •    {
  •        echo $i.&quot;.&quot;.$ip;
  •        echo &quot;  来自火星的网友&quot;;
  •    }

  新浪的调用方法


  • public function sinaIPApi($ip){
  •    $str = file_get_contents(&quot;http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=&quot;.$ip);
  •    $str = iconv(&quot;gbk&quot;, &quot;utf-8//IGNORE&quot;, $str);
  •    preg_match_all(&quot;/[\x{4e00}-\x{9fa5}]+/u&quot;,$str,$get);
  •    $add = implode('',$get[0]);
  •    return $add;
  • }
  • //$get是一个非常棒的二维数组

  
其中有道和新浪的是我自己写的,新浪API也可以像腾讯API那样用file_get_contents()函数获取完地址后使用一连串的字符串函数处理,我写的函数使用正则表达式从新浪的返回结果中提供包含中文的字符串,并且分段存入一个二维数组,这个可能只是针对新浪的API有用并且存在bug。举个例子查询学校分配给我的IP地址后var_dump()一下函数里面的$get变量得到以下结果: array(1) { [0]=> array(6) { [0]=> string(6) &quot;中国&quot; [1]=> string(6) &quot;北京&quot; [2]=> string(6) &quot;北京&quot; [3]=> string(9) &quot;教育网&quot; [4]=> string(6) &quot;学校&quot; [5]=> string(18) &quot;中国地质大学&quot; } },而函数输出的结果则是“中国北京北京教育网学校中国地质大学”,希望我的思路和方法能对别人有用。
最后再次提醒,如果是WordPress请使用第一种方法,否则使用API同时查询所有留言者的真实地址会让PHP超时的,希望各路大牛有更好的方法,至于限制显示和显示方式等神马的都是WordPress应用问题,同时对于Java和C#来说思路也是一样的,这些后续的问题等我考完试再细说。






运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-653333-1-1.html 上篇帖子: 实践基于REST风格的Webservice(PHP,C#) 下篇帖子: PHP Yii开源框架入门学习(一)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表