php根据ip查询所在地区(非常有用,赶集网就用到)

dat文件,关于ip对应地区的信息文件

qqwry.dat文件

网上自己下载

 

class类文件,解析qqwry.data文件的

IpLocation.php文件

  1. <?php  
  2. class IpLocation {  
  3.     /** 
  4.     * @var resource 指针 
  5.     */  
  6.     private $fp;  
  7.   
  8.     /** 
  9.     * 第一条IP记录的偏移地址 
  10.     * @var int 
  11.     */  
  12.     private $firstip;  
  13.   
  14.     /** 
  15.     * 最后一条IP记录的偏移地址 
  16.     * @var int 
  17.     */  
  18.     private $lastip;  
  19.   
  20.     /** 
  21.     * IP记录的总条数(不包含版本信息记录) 
  22.     * @var int 
  23.     */  
  24.     private $totalip;  
  25.   
  26.     /** 
  27.     * 构造函数,打开 QQWry.Dat 文件并初始化类中的信息 
  28.     * @param string $filename 
  29.     * @return IpLocation 
  30.     */  
  31.     public function __construct($filename = "qqwry.dat") {  
  32.         $this->fp = 0;  
  33.         if (($this->fp = @fopen($filename'rb')) !== false) {  
  34.             $this->firstip = $this->getlong();  
  35.             $this->lastip = $this->getlong();  
  36.             $this->totalip = ($this->lastip - $this->firstip) / 7;  
  37.         }  
  38.     }  
  39.   
  40.     /** 
  41.     * 返回读取的长整型数 
  42.     * @access private 
  43.     * @return int 
  44.     */  
  45.     public function getlong() {  
  46.         //将读取的little-endian编码的4个字节转化为长整型数  
  47.         $result = unpack('Vlong'fread($this->fp, 4));  
  48.         return $result['long'];  
  49.     }  
  50.   
  51.     /** 
  52.     * 返回读取的3个字节的长整型数 
  53.     * 
  54.     * @access private 
  55.     * @return int 
  56.     */  
  57.     public function getlong3() {  
  58.         //将读取的little-endian编码的3个字节转化为长整型数  
  59.         $result = unpack('Vlong'fread($this->fp, 3).chr(0));  
  60.         return $result['long'];  
  61.     }  
  62.   
  63.     /** 
  64.     * 返回压缩后可进行比较的IP地址 
  65.     * 
  66.     * @access private 
  67.     * @param string $ip 
  68.     * @return string 
  69.     */  
  70.     public function packip($ip) {  
  71.         // 将IP地址转化为长整型数,如果在PHP5中,IP地址错误,则返回False,  
  72.         // 这时intval将Flase转化为整数-1,之后压缩成big-endian编码的字符串  
  73.         return pack('N'intval(ip2long($ip)));  
  74.     }  
  75.   
  76.     /** 
  77.     * 返回读取的字符串 
  78.     * 
  79.     * @access private 
  80.     * @param string $data 
  81.     * @return string 
  82.     */  
  83.     public function getstring($data = "") {  
  84.         $char = fread($this->fp, 1);  
  85.         while (ord($char) > 0) { // 字符串按照C格式保存,以\0结束  
  86.             $data .= $char// 将读取的字符连接到给定字符串之后  
  87.             $char = fread($this->fp, 1);  
  88.         }  
  89.         return mb_convert_encoding($data'utf-8''gb2312');  
  90.     }  
  91.   
  92.     /** 
  93.     * 返回地区信息 
  94.     * 
  95.     * @access private 
  96.     * @return string 
  97.     */  
  98.     public function getarea() {  
  99.         $byte = fread($this->fp, 1); // 标志字节  
  100.         switch (ord($byte)) {  
  101.             case 0: // 没有区域信息  
  102.                 $area = "";  
  103.             break;  
  104.             case 1:  
  105.             case 2: // 标志字节为1或2,表示区域信息被重定向  
  106.                 fseek($this->fp, $this->getlong3());  
  107.                 $area = $this->getstring();  
  108.             break;  
  109.             default// 否则,表示区域信息没有被重定向  
  110.                 $area = $this->getstring($byte);  
  111.             break;  
  112.         }  
  113.         return $area;  
  114.     }  
  115.   
  116.     /** 
  117.     * 根据所给 IP 地址或域名返回所在地区信息 
  118.     * @access public 
  119.     * @param string $ip 
  120.     * @return array 
  121.     */  
  122.     function getlocation($ip) {  
  123.         if (!$this->fp) return null; // 如果数据文件没有被正确打开,则直接返回空  
  124.         $location['ip'] = gethostbyname($ip); // 将输入的域名转化为IP地址  
  125.         $ip = $this->packip($location['ip']); // 将输入的IP地址转化为可比较的IP地址  
  126.         // 不合法的IP地址会被转化为255.255.255.255  
  127.         // 对分搜索  
  128.         $l = 0; // 搜索的下边界  
  129.         $u = $this->totalip; // 搜索的上边界  
  130.         $findip = $this->lastip; // 如果没有找到就返回最后一条IP记录(QQWry.Dat的版本信息)  
  131.         while ($l <= $u) { // 当上边界小于下边界时,查找失败  
  132.             $i = floor(($l + $u) / 2); // 计算近似中间记录  
  133.             fseek($this->fp, $this->firstip + $i * 7);  
  134.             $beginip = strrev(fread($this->fp, 4)); // 获取中间记录的开始IP地址  
  135.             // strrev函数在这里的作用是将little-endian的压缩IP地址转化为big-endian的格式  
  136.             // 以便用于比较,后面相同。  
  137.             if ($ip < $beginip) { // 用户的IP小于中间记录的开始IP地址时  
  138.                 $u = $i - 1; // 将搜索的上边界修改为中间记录减一  
  139.             }else{  
  140.                 fseek($this->fp, $this->getlong3());  
  141.                 $endip = strrev(fread($this->fp, 4)); // 获取中间记录的结束IP地址  
  142.                 if ($ip > $endip) { // 用户的IP大于中间记录的结束IP地址时  
  143.                     $l = $i + 1; // 将搜索的下边界修改为中间记录加一  
  144.                 }else// 用户的IP在中间记录的IP范围内时  
  145.                     $findip = $this->firstip + $i * 7;  
  146.                     break// 则表示找到结果,退出循环  
  147.                 }  
  148.             }  
  149.         }  
  150.   
  151.         //获取查找到的IP地理位置信息  
  152.         fseek($this->fp, $findip);  
  153.         $location['beginip'] = long2ip($this->getlong()); // 用户IP所在范围的开始地址  
  154.         $offset = $this->getlong3();  
  155.         fseek($this->fp, $offset);  
  156.         $location['endip'] = long2ip($this->getlong()); // 用户IP所在范围的结束地址  
  157.         $byte = fread($this->fp, 1); // 标志字节  
  158.   
  159.         switch (ord($byte)) {  
  160.             case 1: // 标志字节为1,表示国家和区域信息都被同时重定向  
  161.                 $countryOffset = $this->getlong3(); // 重定向地址  
  162.                 fseek($this->fp, $countryOffset);  
  163.                 $byte = fread($this->fp, 1); // 标志字节  
  164.                 switch (ord($byte)) {  
  165.                     case 2: // 标志字节为2,表示国家信息又被重定向  
  166.                         fseek($this->fp, $this->getlong3());  
  167.                         $location['country'] = $this->getstring();  
  168.                         fseek($this->fp, $countryOffset + 4);  
  169.                         $location['area'] = $this->getarea();  
  170.                         break;  
  171.                     default// 否则,表示国家信息没有被重定向  
  172.                         $location['country'] = $this->getstring($byte);  
  173.                         $location['area'] = $this->getarea();  
  174.                         break;  
  175.                 }  
  176.                 break;  
  177.             case 2: // 标志字节为2,表示国家信息被重定向  
  178.                 fseek($this->fp, $this->getlong3());  
  179.                 $location['country'] = $this->getstring();  
  180.                 fseek($this->fp, $offset + 8);  
  181.                 $location['area'] = $this->getarea();  
  182.                 break;  
  183.             default// 否则,表示国家信息没有被重定向  
  184.                 $location['country'] = $this->getstring($byte);  
  185.                 $location['area'] = $this->getarea();  
  186.                 break;  
  187.         }  
  188.         if ($location['country'] == " CZ88.NET") { // CZ88.NET表示没有有效信息  
  189.             $location['country'] = "未知";  
  190.         }  
  191.         if ($location['area'] == " CZ88.NET") {  
  192.             $location['area'] = "";  
  193.         }  
  194.         return $location;  
  195.     }  
  196.   
  197.       
  198.     /** 
  199.     * 析构函数,用于在页面执行结束后自动关闭打开的文件。 
  200.     * 
  201.     */  
  202.     function __desctruct() {  
  203.         if ($this->fp) {  
  204.             fclose($this->fp);  
  205.         }  
  206.         $this->fp = 0;  
  207.     }  
  208. }  
  209. ?>   

这个也可以网上下载,也可以copy这里的,这里的也是很全的。

 

执行文件,我这里叫ip_location.php文件

    1. <?php   
    2. function getIpPlace(){  
    3.     require_once("IpLocation.php")//加载类文件IpLocation.php  
    4.     $ipfile = "qqwry.dat";      //获取ip对应地区的信息文件  
    5.     $iplocation = new IpLocation($ipfile);  //new IpLocation($ipfile) $ipfile ip对应地区信息文件  
    6.     $ipresult = $iplocation->getlocation("ip地址"); //根据ip地址获得地区 getlocation("ip地区")  
    7.     return $ipresult;  
    8. }  
    9. print_r($getIpPlace()); //调用方法  
    10. ?> 
http://blog.csdn.net/motian06/article/details/7919675

posted on 2013-03-07 15:45  senly  阅读(3298)  评论(0编辑  收藏  举报

导航