IP地理位置查询类(纯真IP地址库) 发表于 2018-02-01 | 分类于 PHP 由于使用UTF8编码,如果使用纯真IP地址库的话,需要对返回结果进行编码转换纯真IP地址库 http://www.cz88.net/ 安装完成后,到安装目录把 qqwry.dat 拷贝出来 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323<?php/** * IP 地理位置查询类 */class IpLocation{ private $_provinces = ['黑龙江省', '辽宁省', '吉林省', '河北省', '河南省', '湖北省', '湖南省', '山东省', '山西省', '陕西省', '安徽省', '浙江省', '江苏省', '福建省', '广东省', '海南省', '四川省', '云南省', '贵州省', '青海省', '甘肃省', '江西省', '台湾省', '内蒙古', '宁夏', '新疆', '西藏', '广西', '北京市', '上海市', '天津市', '重庆市', '香港', '澳门']; private $_filterCity = ['北京市', '上海市', '天津市', '重庆市']; /** * qqwry.dat文件指针 * * @var resource */ private $fp; /** * 第一条IP记录的偏移地址 * * @var int */ private $firstip; /** * 最后一条IP记录的偏移地址 * * @var int */ private $lastip; /** * IP记录的总条数(不包含版本信息记录) * * @var int */ private $totalip; /** * 构造函数,打开 qqwry.dat 文件并初始化类中的信息 * * @param string $filename * @return IpLocation */ public function __construct($filename = 'qqwry.dat') { $this->fp = 0; if (($this->fp = fopen(dirname(__FILE__) . '/' . $filename, 'rb')) !== false) { $this->firstip = $this->getlong(); $this->lastip = $this->getlong(); $this->totalip = ($this->lastip - $this->firstip) / 7; // 注册析构函数,使其在程序执行结束时执行 register_shutdown_function(array(&$this, '__destruct')); } } /** * 返回读取的长整型数 * * @access private * @return int */ private function getlong() { // 将读取的little-endian编码的4个字节转化为长整型数 $result = unpack('Vlong', fread($this->fp, 4)); return $result['long']; } /** * 返回读取的3个字节的长整型数 * * @access private * @return int */ private function getlong3() { // 将读取的little-endian编码的3个字节转化为长整型数 $result = unpack('Vlong', fread($this->fp, 3) . chr(0)); return $result['long']; } /** * 返回压缩后可进行比较的IP地址 * * @access private * @param string $ip * @return string */ private function packip($ip) { // 将IP地址转化为长整型数,如果在PHP5中,IP地址错误,则返回False // 这时intval将Flase转化为整数-1,之后压缩成big-endian编码的字符串 return pack('N', intval(ip2long($ip))); } /** * 返回读取的字符串 * * @access private * @param string $data * @return string */ private function getstring($data = '') { $char = fread($this->fp, 1); while (ord($char) > 0) { // 字符串按照C格式保存,以\0结束 $data .= $char; // 将读取的字符连接到给定字符串之后 $char = fread($this->fp, 1); } return $data; } /** * 返回地区信息 * * @access private * @return string */ private function getarea() { $byte = fread($this->fp, 1); // 标志字节 switch (ord($byte)) { case 0: // 没有区域信息 $area = ''; break; case 1: case 2: // 标志字节为1或2,表示区域信息被重定向 fseek($this->fp, $this->getlong3()); $area = $this->getstring(); break; default: // 否则,表示区域信息没有被重定向 $area = $this->getstring($byte); break; } return $area; } /** * 根据所给 IP 地址或域名返回所在地区信息 * * @access public * @param string $ip * @return array */ public function getlocation($ip, $convert_utf8 = true) { if (!$this->fp) return null; // 如果数据文件没有被正确打开,则直接返回空 $location['ip'] = gethostbyname($ip); // 将输入的域名转化为IP地址 $ip = $this->packip($location['ip']); // 将输入的IP地址转化为可比较的IP地址,不合法的IP地址会被转化为255.255.255.255 // 对分搜索 $l = 0; // 搜索的下边界 $u = $this->totalip; // 搜索的上边界 $findip = $this->lastip; // 如果没有找到就返回最后一条IP记录(qqwry.Dat的版本信息) while ($l <= $u) { // 当上边界小于下边界时,查找失败 $i = floor(($l + $u) / 2); // 计算近似中间记录 fseek($this->fp, $this->firstip + $i * 7); $beginip = strrev(fread($this->fp, 4)); // 获取中间记录的开始IP地址,strrev函数在这里的作用是将little-endian的压缩IP地址转化为big-endian的格式,以便用于比较,后面相同 if ($ip < $beginip) { // 用户的IP小于中间记录的开始IP地址时 $u = $i - 1; // 将搜索的上边界修改为中间记录减一 } else { fseek($this->fp, $this->getlong3()); $endip = strrev(fread($this->fp, 4)); // 获取中间记录的结束IP地址 if ($ip > $endip) { // 用户的IP大于中间记录的结束IP地址时 $l = $i + 1; // 将搜索的下边界修改为中间记录加一 } else { // 用户的IP在中间记录的IP范围内时 $findip = $this->firstip + $i * 7; break; // 则表示找到结果,退出循环 } } } // 获取查找到的IP地理位置信息 fseek($this->fp, $findip); $location['beginip'] = long2ip($this->getlong()); // 用户IP所在范围的开始地址 $offset = $this->getlong3(); fseek($this->fp, $offset); $location['endip'] = long2ip($this->getlong()); // 用户IP所在范围的结束地址 $byte = fread($this->fp, 1); // 标志字节 switch (ord($byte)) { case 1: // 标志字节为1,表示国家和区域信息都被同时重定向 $countryOffset = $this->getlong3(); // 重定向地址 fseek($this->fp, $countryOffset); $byte = fread($this->fp, 1); // 标志字节 switch (ord($byte)) { case 2: // 标志字节为2,表示国家信息又被重定向 fseek($this->fp, $this->getlong3()); $location['country'] = $this->getstring(); fseek($this->fp, $countryOffset + 4); $location['area'] = $this->getarea(); break; default: // 否则,表示国家信息没有被重定向 $location['country'] = $this->getstring($byte); $location['area'] = $this->getarea(); break; } break; case 2: // 标志字节为2,表示国家信息被重定向 fseek($this->fp, $this->getlong3()); $location['country'] = $this->getstring(); fseek($this->fp, $offset + 8); $location['area'] = $this->getarea(); break; default: // 否则,表示国家信息没有被重定向 $location['country'] = $this->getstring($byte); $location['area'] = $this->getarea(); break; } if (trim($location['country']) == 'CZ88.NET') { // CZ88.NET表示没有有效信息 $location['country'] = '未知'; } if (trim($location['area']) == 'CZ88.NET') { $location['area'] = ''; } if ($convert_utf8) { $location['country'] = iconv('GB2312', 'UTF-8//IGNORE', $location['country']); $location['area'] = iconv('GB2312', 'UTF-8//IGNORE', $location['area']); } foreach($this->_provinces as $province) { if (strpos($location['country'], $province) === 0) { $location['province'] = $province; if (in_array($province, $this->_filterCity)) { $location['city'] = $province; } else { $location['city'] = str_replace($province, '', $location['country']); } empty($location['city']) && $location['city'] = $province; break; } } // country 错误值:[未知,局域网,IANA] return $location; } /** * 析构函数,用于在页面执行结束后自动关闭打开的文件 */ public function __destruct() { if ($this->fp) { fclose($this->fp); } $this->fp = 0; }}$ip_location_obj = new IpLocation();echo '<pre>';$address = $ip_location_obj->getlocation('127.0.0.1');print_r($address);$address = $ip_location_obj->getlocation('10.10.0.0');print_r($address);$address = $ip_location_obj->getlocation('123.164.3.9');print_r($address);$address = $ip_location_obj->getlocation('175.160.104.123');print_r($address);$address = $ip_location_obj->getlocation('122.136.104.123');print_r($address);$address = $ip_location_obj->getlocation('106.112.104.123');print_r($address);$address = $ip_location_obj->getlocation('123.8.104.123');print_r($address);$address = $ip_location_obj->getlocation('58.48.104.123');print_r($address);$address = $ip_location_obj->getlocation('222.240.104.123');print_r($address);$address = $ip_location_obj->getlocation('182.32.104.123');print_r($address);$address = $ip_location_obj->getlocation('118.72.104.123');print_r($address);$address = $ip_location_obj->getlocation('202.200.104.123');print_r($address);$address = $ip_location_obj->getlocation('60.168.104.123');print_r($address);$address = $ip_location_obj->getlocation('115.224.104.123');print_r($address);$address = $ip_location_obj->getlocation('117.80.104.123');print_r($address);$address = $ip_location_obj->getlocation('120.32.104.123');print_r($address);$address = $ip_location_obj->getlocation('113.96.104.123');print_r($address);$address = $ip_location_obj->getlocation('223.198.104.123');print_r($address);$address = $ip_location_obj->getlocation('182.128.104.123');print_r($address);$address = $ip_location_obj->getlocation('182.240.104.123');print_r($address);$address = $ip_location_obj->getlocation('114.138.104.123');print_r($address);$address = $ip_location_obj->getlocation('223.220.104.123');print_r($address);$address = $ip_location_obj->getlocation('42.88.104.123');print_r($address);$address = $ip_location_obj->getlocation('115.148.104.123');print_r($address);$address = $ip_location_obj->getlocation('61.57.155.236');print_r($address);$address = $ip_location_obj->getlocation('123.178.104.123');print_r($address);$address = $ip_location_obj->getlocation('124.224.104.123');print_r($address);$address = $ip_location_obj->getlocation('49.112.104.123');print_r($address);$address = $ip_location_obj->getlocation('27.98.224.123');print_r($address);$address = $ip_location_obj->getlocation('222.216.104.123');print_r($address);$address = $ip_location_obj->getlocation('58.31.104.123');print_r($address);$address = $ip_location_obj->getlocation('124.76.104.123');print_r($address);$address = $ip_location_obj->getlocation('221.196.104.123');print_r($address);$address = $ip_location_obj->getlocation('125.80.104.123');print_r($address);$address = $ip_location_obj->getlocation('202.97.96.123');print_r($address);$address = $ip_location_obj->getlocation('202.175.34.123');print_r($address); 本文作者:Mr 本文链接: http://sevming.github.io/PHP/ip-location-cz.html 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!