支付宝赞助帐号:service@kuitao8.com 

php QQWry获取ip接口 支持省 城市 完整版

Created2016-01-07   Views 3751    Author 懒人程序
  1. <?php 
  2.  
  3. /** php QQWry获取ip接口 支持省 城市  完整版 
  4.  *  IP 地理位置查询类 修改自 CoolCode.CN 
  5.  *  由于使用UTF8编码 如果使用纯真IP地址库的话 需要对返回结果进行编码转换 
  6.  * @author    liu21st <liu21st@gmail.com> 
  7.  */ 
  8. class IpLocation { 
  9.     /** 
  10.      * QQWry.Dat文件指针 
  11.      * 
  12.      * @var resource 
  13.      */ 
  14.     private $fp; 
  15.  
  16.     /** 
  17.      * 第一条IP记录的偏移地址 
  18.      * 
  19.      * @var int 
  20.      */ 
  21.     private $firstip; 
  22.  
  23.     /** 
  24.      * 最后一条IP记录的偏移地址 
  25.      * 
  26.      * @var int 
  27.      */ 
  28.     private $lastip; 
  29.  
  30.     /** 
  31.      * IP记录的总条数(不包含版本信息记录) 
  32.      * 
  33.      * @var int 
  34.      */ 
  35.     private $totalip; 
  36.  
  37.     /** 
  38.      * 构造函数,打开 QQWry.Dat 文件并初始化类中的信息 
  39.      * 
  40.      * @param string $filename 
  41.      * @return IpLocation 
  42.      */ 
  43.     public function __construct($filename = "UTFWry.dat") { 
  44.         $this->fp = 0; 
  45.         if (($this->fp      = fopen(dirname(__FILE__).'/'.$filename, 'rb')) !== false) { 
  46.             $this->firstip  = $this->getlong(); 
  47.             $this->lastip   = $this->getlong(); 
  48.             $this->totalip  = ($this->lastip - $this->firstip) / 7; 
  49.         } 
  50.     } 
  51.  
  52.     /** 
  53.      * 返回读取的长整型数 
  54.      * 
  55.      * @access private 
  56.      * @return int 
  57.      */ 
  58.     private function getlong() { 
  59.         //将读取的little-endian编码的4个字节转化为长整型数 
  60.         $result = unpack('Vlong', fread($this->fp, 4)); 
  61.         return $result['long']; 
  62.     } 
  63.  
  64.     /** 
  65.      * 返回读取的3个字节的长整型数 
  66.      * 
  67.      * @access private 
  68.      * @return int 
  69.      */ 
  70.     private function getlong3() { 
  71.         //将读取的little-endian编码的3个字节转化为长整型数 
  72.         $result = unpack('Vlong', fread($this->fp, 3).chr(0)); 
  73.         return $result['long']; 
  74.     } 
  75.  
  76.     /** 
  77.      * 返回压缩后可进行比较的IP地址 
  78.      * 
  79.      * @access private 
  80.      * @param string $ip 
  81.      * @return string 
  82.      */ 
  83.     private function packip($ip) { 
  84.         // 将IP地址转化为长整型数,如果在PHP5中,IP地址错误,则返回False, 
  85.         // 这时intval将Flase转化为整数-1,之后压缩成big-endian编码的字符串 
  86.         return pack('N', intval(ip2long($ip))); 
  87.     } 
  88.  
  89.     /** 
  90.      * 返回读取的字符串 
  91.      * 
  92.      * @access private 
  93.      * @param string $data 
  94.      * @return string 
  95.      */ 
  96.     private function getstring($data = "") { 
  97.         $char = fread($this->fp, 1); 
  98.         while (ord($char) > 0) {        // 字符串按照C格式保存,以\0结束 
  99.             $data  .= $char;             // 将读取的字符连接到给定字符串之后 
  100.             $char   = fread($this->fp, 1); 
  101.         } 
  102.         return $data; 
  103.     } 
  104.  
  105.     /** 
  106.      * 返回地区信息 
  107.      * 
  108.      * @access private 
  109.      * @return string 
  110.      */ 
  111.     private function getarea() { 
  112.         $byte = fread($this->fp, 1);    // 标志字节 
  113.         switch (ord($byte)) { 
  114.             case 0:                     // 没有区域信息 
  115.                 $area = ""
  116.                 break
  117.             case 1: 
  118.             case 2:                     // 标志字节为1或2,表示区域信息被重定向 
  119.                 fseek($this->fp, $this->getlong3()); 
  120.                 $area = $this->getstring(); 
  121.                 break
  122.             default:                    // 否则,表示区域信息没有被重定向 
  123.                 $area = $this->getstring($byte); 
  124.                 break
  125.         } 
  126.         return $area; 
  127.     } 
  128.     private $provinces = array("黑龙江省","辽宁省","吉林省","河北省","河南省","湖北省","湖南省","山东省","山西省","陕西省"
  129.                                   "安徽省","浙江省","江苏省","福建省","广东省","海南省","四川省","云南省","贵州省","青海省","甘肃省"
  130.                                   "江西省","台湾省","内蒙古","宁夏","新疆","西藏","广西","北京市","上海市","天津市","重庆市","香港","澳门"); 
  131.     /** 
  132.      * 根据所给 IP 地址或域名返回所在地区信息 
  133.      * 
  134.      * @access public 
  135.      * @param string $ip 
  136.      * @return array 
  137.      */ 
  138.     public function getlocation($ip='') { 
  139.         if (!$this->fp) return null;            // 如果数据文件没有被正确打开,则直接返回空 
  140.         if(empty($ip)) $ip = get_client_ip(); 
  141.         $location['ip'] = gethostbyname($ip);   // 将输入的域名转化为IP地址 
  142.         $ip = $this->packip($location['ip']);   // 将输入的IP地址转化为可比较的IP地址 
  143.                                                 // 不合法的IP地址会被转化为255.255.255.255 
  144.         // 对分搜索 
  145.         $l = 0;                         // 搜索的下边界 
  146.         $u = $this->totalip;            // 搜索的上边界 
  147.         $findip = $this->lastip;        // 如果没有找到就返回最后一条IP记录(QQWry.Dat的版本信息) 
  148.         while ($l <= $u) {              // 当上边界小于下边界时,查找失败 
  149.             $i = floor(($l + $u) / 2);  // 计算近似中间记录 
  150.             fseek($this->fp, $this->firstip + $i * 7); 
  151.             $beginip = strrev(fread($this->fp, 4));     // 获取中间记录的开始IP地址 
  152.             // strrev函数在这里的作用是将little-endian的压缩IP地址转化为big-endian的格式 
  153.             // 以便用于比较,后面相同。 
  154.             if ($ip < $beginip) {       // 用户的IP小于中间记录的开始IP地址时 
  155.                 $u = $i - 1;            // 将搜索的上边界修改为中间记录减一 
  156.             } 
  157.             else { 
  158.                 fseek($this->fp, $this->getlong3()); 
  159.                 $endip = strrev(fread($this->fp, 4));   // 获取中间记录的结束IP地址 
  160.                 if ($ip > $endip) {     // 用户的IP大于中间记录的结束IP地址时 
  161.                     $l = $i + 1;        // 将搜索的下边界修改为中间记录加一 
  162.                 } 
  163.                 else {                  // 用户的IP在中间记录的IP范围内时 
  164.                     $findip = $this->firstip + $i * 7; 
  165.                     break;              // 则表示找到结果,退出循环 
  166.                 } 
  167.             } 
  168.         } 
  169.  
  170.         //获取查找到的IP地理位置信息 
  171.         fseek($this->fp, $findip); 
  172.         $location['beginip'] = long2ip($this->getlong());   // 用户IP所在范围的开始地址 
  173.         $offset = $this->getlong3(); 
  174.         fseek($this->fp, $offset); 
  175.         $location['endip'] = long2ip($this->getlong());     // 用户IP所在范围的结束地址 
  176.         $byte = fread($this->fp, 1);    // 标志字节 
  177.         switch (ord($byte)) { 
  178.             case 1:                     // 标志字节为1,表示国家和区域信息都被同时重定向 
  179.                 $countryOffset = $this->getlong3();         // 重定向地址 
  180.                 fseek($this->fp, $countryOffset); 
  181.                 $byte = fread($this->fp, 1);    // 标志字节 
  182.                 switch (ord($byte)) { 
  183.                     case 2:             // 标志字节为2,表示国家信息又被重定向 
  184.                         fseek($this->fp, $this->getlong3()); 
  185.                         $location['country']    = $this->getstring(); 
  186.                         fseek($this->fp, $countryOffset + 4); 
  187.                         $location['area']       = $this->getarea(); 
  188.                         break
  189.                     default:            // 否则,表示国家信息没有被重定向 
  190.                         $location['country']    = $this->getstring($byte); 
  191.                         $location['area']       = $this->getarea(); 
  192.                         break
  193.                 } 
  194.                 break
  195.             case 2:                     // 标志字节为2,表示国家信息被重定向 
  196.                 fseek($this->fp, $this->getlong3()); 
  197.                 $location['country']    = $this->getstring(); 
  198.                 fseek($this->fp, $offset + 8); 
  199.                 $location['area']       = $this->getarea(); 
  200.                 break
  201.             default:                    // 否则,表示国家信息没有被重定向 
  202.                 $location['country']    = $this->getstring($byte); 
  203.                 $location['area']       = $this->getarea(); 
  204.                 break
  205.         } 
  206.         if (trim($location['country']) == 'CZ88.NET') {  // CZ88.NET表示没有有效信息 
  207.             $location['country'] = '未知'
  208.         } 
  209.         if (trim($location['area']) == 'CZ88.NET') { 
  210.             $location['area'] = ''
  211.         } 
  212.         $location['country'] = @iconv('gbk','utf-8',$location['country']); //转换格式,防止乱码 
  213.         $location['area'] = @iconv('gbk','utf-8',$location['area']); //转换格式,防止乱码 
  214.         foreach($this->provinces as $v) { 
  215.             if(strpos($location['country'],$v) === 0) { 
  216.                 $location['province'] = $v; 
  217.                 $location['city'] = str_replace($v,'',$location['country']); 
  218.                 break
  219.             } 
  220.         } 
  221.         if(empty($location['province'])) $location['province'] = $location['country']; 
  222.         if(empty($location['city'])) $location['city'] = $location['country']; 
  223.         return $location; 
  224.     } 
  225.  
  226.     /** 
  227.      * 析构函数,用于在页面执行结束后自动关闭打开的文件。 
  228.      * 
  229.      */ 
  230.     public function __destruct() { 
  231.         if ($this->fp) { 
  232.             fclose($this->fp); 
  233.         } 
  234.         $this->fp = 0; 
  235.     } 
  236.  
  237. $new = new IpLocation(); 
  238. $ip = $new->getlocation('1.86.10.173'); 
  239. print_r($ip); 
  240. /*
  241. Array
      (
      [ip] => 1.86.10.173
      [beginip] => 1.85.226.0
      [endip] => 1.86.15.255
      [country] => 陕西省西安市
      [area] => 电信
      [province] => 陕西省
      [city] => 西安市
      )
    */

下载源码
http://img.kuitao8.com/uploads/2016/0107/20160107023307245.rar


上一篇: php实现简单的上一页下一页
下一篇: php简单格式化json的方法
支持键盘 ← →

邮件订阅

订阅我们的精彩内容