一起学习网 一起学习网

根据IP地址得到国家地区 php

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) "中国地质大学" } },而函数输出的结果则是“中国北京北京教育网学校中国地质大学”,希望我的思路和方法能对别人有用。