PHP转换IP地址到真实地址的方法详解_php技巧

想要把IPv4地址转为真实的地址,肯定要参考IP数据库,商业的IP数据库存储在关系型数据库中,查询和使用都非常方便,但是成本不是个人和小公 司愿意承受的,所以简单应用的思路就是利用一些免费的IP数据库或者一些大网站提供的查询API,他们的数据量足够我们使用了。
1. 利用纯真IP数据库
利用本地的QQWry.Dat文件,优点是查询速度非常快,缺点是数据库文件要放在自己的空间内并且要偶尔更新数据库。时间关系废话不多说,下面是 使用这个文件的函数,如果是在WordPress里面使用这个功能,把下面的代码写入主题下面的functions.php里面,然后在 comments-list的输出<?php echo convertip(get_comment_author_ip()); ?>即可;如果是其他程序引用,输入一个有效的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) {
        $Middle= intval(($EndNum + $BeginNum) / 2);
        //偏移指针到索引位置读取4个字节
        fseek($fd, $ipbegin + 7 * $Middle);
        $ipData1 = fread($fd, 4);
        if(strlen($ipData1) < 4) {
            fclose($fd);
            return 'System Error';
        }
        //提取出来的数据转换成长整形,如果数据是负数则加上2的32次幂
        $ip1num = implode('', unpack('L', $ipData1));
        if($ip1num < 0) $ip1num += pow(2, 32);
        //提取的长整型数大于我们IP地址则修改结束位置进行下一次循环
        if($ip1num > $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 = "$ipAddr1 $ipAddr2";
    $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("123.124.2.85","","北京市","");,一个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("http://fw.qq.com/ipaddress");
 $ip=str_replace('"',' ',$ip);
 $ip2=explode("(",$ip);
 $a=substr($ip2[1],0,-2);
 $b=explode(",",$a);
 return $b;
}
$ip=getIpPlace();
print_r($ip);

//有道API的PHP调用方法

复制代码 代码如下:

$url = "http:www.youdao.com/smartresult-xml/search.s?type=ip&q=".$ip;
$doc = new DOMDocument();
   $doc->load($url);
   $smartresult = $doc->getElementsByTagName("product");
   foreach($smartresult as $product)
   {
      $locations = $product->getElementsByTagName("location");
      $location = $locations->item(0)->nodeValue;
   }
   if($location != "")
   {
       echo $i.".".$ip;
       echo "  来自".$location."的网友";
   }
   else
   {
       echo $i.".".$ip;
       echo "  来自火星的网友";
   }
public function sinaIPApi($ip){
   $str = file_get_contents("http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=".$ip);
   $str = iconv("gbk", "utf-8//IGNORE", $str);
   preg_match_all("/[/x{4e00}-/x{9fa5}]+/u",$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) "中国" [1]=> string(6) "北京" [2]=> string(6) "北京" [3]=> string(9) "教育网" [4]=> string(6) "学校" [5]=> string(18) "中国地质大学" } },而函数输出的结果则是“中国北京北京教育网学校中国地质大学”,希望我的思路和方法能对别人有用。

最后再次提醒,如果是WordPress请使用第一种方法,否则使用API同时查询所有留言者的真实地址会让PHP超时的,希望各路大牛有更好的方 法,至于限制显示和显示方式等神马的都是WordPress应用问题,同时对于Java和C#来说思路也是一样的,这些后续的问题等我考完试再细说。

时间: 2024-11-08 22:11:43

PHP转换IP地址到真实地址的方法详解_php技巧的相关文章

使用javascript:将其它类型值转换成布尔类型值的解决方法详解_javascript技巧

1.利用Boolean对象进行转换 复制代码 代码如下: var num123 = 123, str = 'abc', o = {name:'test'}, num0 = 0; num123 = Boolean(num123); //true num0 = Boolean(num0); //false str = Boolean(str); //true o = Boolean(o); //true 2. 利用两个'!'运算符,第一个'!'将值转换成布尔值并取其值的非值,第二个'!'将其布尔值还

PHP中IP地址与整型数字互相转换详解_php技巧

IP转换成整型存储是数据库优化一大趋势,不少人目前存储IP时还在使用字符串类型存储,字符串索引比整型索引消耗资源很多,特别是表中数据量大的时候,以及求查询某一个ip段的数据,今天说的ip是指ip4,ip6不在本文范围内. 系统函数ip2long与long2ipPHP中有内置函数ip2long可以将ip地址转换整型. 复制代码 代码如下: $ip = '210.110.11.49'; echo ip2long($ip); 输出: 复制代码 代码如下: -764540111 输出的整型有负号是因为我

php IP转换整形(ip2long)的详解_php技巧

如何将四个字段以点分开的IP网络址协议地址转换成整数呢?PHP里有这么一个函数ip2long.比如 复制代码 代码如下: <?phpecho ip2long("10.2.1.3");?> 我们将得到167903491 这是如何计算的,目前我知道有两个算法.其一 复制代码 代码如下: <?phpfunction ip2int($ip){   //我们先把ip分为四段,$ip1,$ip2,$ip3,$ip4   list($ip1,$ip2,$ip3,$ip4)=expl

3步搞定纯真IP数据导入到MySQL的方法详解_Mysql

前提: 你会用vi. 很明显,本文是在Linux下测试通过的.本文用的是MySQL命令行工具,如果你不会,用phpMyAdmin应该也可以. 第1步: 下载纯真IP数据,解压存成ip.txt. 详解:这一步不用详解了吧.如果你这一步都不会,下面就不用看了. 第2步: 用vi 编辑 ip.txt. # vi ip.txt 在vi界面下输入如下命令: :%s/\s\+/;/ 一共重复输入3次. 存盘退出: :wq 详解:ip.txt有4列.分别是起始ip,结束ip,地区,说明.列之间用不等数量的空格

php中邮箱地址正则表达式实现与详解_php技巧

首先附上代码 复制代码 代码如下: ^[_.0-9a-z-]+@([0-9a-z][0-9a-z-]+.)+[a-z]{2,3}$ 在这段正则表达式中,"+"表示前面的字符串连续出现一个或多个:"^"表示下一个字符串必须出现在开头,"$"表示前一个字符串必须出现在结尾: "."也就是".",这里""是转义符:"{2,3}"表示前面的字符串可以连续出现2-3次.&quo

php数组转换js数组操作及json_encode的用法详解_php实例

对于php,个人感觉能够熟练操作数组和字符串,基本上已经是入门了,php本身有很多操作数组和字符串的函数,今天在做一个功能时,需要用Js动态的创建门店信息,这些信息是要从后台添加的,想来想去,通过php读取数据库,得到数组,然后将数组转化成符合需求js数组,php数组形式为: 复制代码 代码如下: $newArray = array(array('地区'=>'北京地区','items'=>'10','detail'=>array(0=>array('店名'=>'旗舰店','u

ASP查找ip对应的真实地址

  ASP查找ip对应的真实地址的方法,我写了一个函数,用来检测用户真正的IP地址,自己亲测可用,希望有需要的可以尝试下.函数完整代码如下:   与下面可结合使用: 函数参数sip为你使用request获取到的常规IP地址.  

jquery分析文本里url或邮件地址为真实链接的方法

  本文实例讲述了jquery分析文本里url或邮件地址为真实链接的方法.分享给大家供大家参考.具体如下: 这段代码可以分析出文本里的所有超级链接,包含邮件.url.#链接等等,并分别输出为真实链接地址 ? 1 2 3 4 5 6 7 8 9 10 11 $.fn.tweetify = function() { this.each(function() { $(this).html( $(this).html() .replace(/((ftp|http|https)://(w+:{0,1}w*

jquery分析文本里url或邮件地址为真实链接的方法_jquery

本文实例讲述了jquery分析文本里url或邮件地址为真实链接的方法.分享给大家供大家参考.具体如下: 这段代码可以分析出文本里的所有超级链接,包含邮件.url.#链接等等,并分别输出为真实链接地址 $.fn.tweetify = function() { this.each(function() { $(this).html( $(this).html() .replace(/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/