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


Posted in PHP onJuly 01, 2013

dat文件,关于ip对应地区的信息文件
qqwry.dat文件
网上自己下载

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

<?php
class IpLocation {
    /**
    * @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($filename, 'rb')) !== false) {
            $this->firstip = $this->getlong();
            $this->lastip = $this->getlong();
            $this->totalip = ($this->lastip - $this->firstip) / 7;
        }
    }
    /**
    * 返回读取的长整型数
    * @access private
    * @return int
    */
    public function getlong() {
        //将读取的little-endian编码的4个字节转化为长整型数
        $result = unpack('Vlong', fread($this->fp, 4));
        return $result['long'];
    }
    /**
    * 返回读取的3个字节的长整型数
    *
    * @access private
    * @return int
    */
    public 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
    */
    public 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
    */
    public function getstring($data = "") {
        $char = fread($this->fp, 1);
        while (ord($char) > 0) { // 字符串按照C格式保存,以\0结束
            $data .= $char; // 将读取的字符连接到给定字符串之后
            $char = fread($this->fp, 1);
        }
        return mb_convert_encoding($data, 'utf-8', 'gb2312');
    }
    /**
    * 返回地区信息
    *
    * @access private
    * @return string
    */
    public 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
    */
    function getlocation($ip) {
        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 ($location['country'] == " CZ88.NET") { // CZ88.NET表示没有有效信息
            $location['country'] = "未知";
        }
        if ($location['area'] == " CZ88.NET") {
            $location['area'] = "";
        }
        return $location;
    }    /**
    * 析构函数,用于在页面执行结束后自动关闭打开的文件。
    *
    */
    function __desctruct() {
        if ($this->fp) {
            fclose($this->fp);
        }
        $this->fp = 0;
    }
}
?>

这个也可以网上下载,也可以copy这里的,这里的也是很全的。
执行文件,我这里叫ip_location.php文件
<?php 
function getIpPlace(){
 require_once("IpLocation.php")//加载类文件IpLocation.php
 $ipfile = "qqwry.dat";  //获取ip对应地区的信息文件
 $iplocation = new IpLocation($ipfile); //new IpLocation($ipfile) $ipfile ip对应地区信息文件
 $ipresult = $iplocation->getlocation("ip地址"); //根据ip地址获得地区 getlocation("ip地区")
 return $ipresult;
}
print_r($getIpPlace()); //调用方法
?>

PHP 相关文章推荐
PHP.MVC的模板标签系统(五)
Sep 05 PHP
PHP的历史和优缺点
Oct 09 PHP
判断Keep-Alive模式的HTTP请求的结束的实现代码
Aug 06 PHP
PHP fopen 读取带中文URL地址的一点见解
Sep 25 PHP
关于PHP堆栈与列队的学习
Jun 21 PHP
php实现按文件名搜索文件的远程文件查找器
May 10 PHP
PHP字符串word末字符实现大小写互换的方法
Nov 10 PHP
php使用MySQL保存session会话的方法
Jun 18 PHP
PHP在innodb引擎下快速代建全文搜索功能简明教程【基于xunsearch】
Oct 14 PHP
PHP编程中的Session阻塞问题与解决方法分析
Aug 07 PHP
PHP chr()函数讲解
Feb 11 PHP
Yii 使用intervention/image拓展实现图像处理功能
Jun 22 PHP
浅析php插件 HTMLPurifier HTML解析器
Jul 01 #PHP
浅析php插件 Simple HTML DOM 用DOM方式处理HTML
Jul 01 #PHP
php curl选项列表(超详细)
Jul 01 #PHP
基于simple_html_dom的使用小结
Jul 01 #PHP
解析php php_openssl.dll的作用
Jul 01 #PHP
关于php 接口问题(php接口主要也就是运用curl,curl函数)
Jul 01 #PHP
浅析PKI加密解密 OpenSSL
Jul 01 #PHP
You might like
浅析php中jsonp的跨域实例
2013/06/21 PHP
php+mongodb判断坐标是否在指定多边形区域内的实例
2016/10/28 PHP
飞鱼(shqlsl) javascript作品集
2006/12/16 Javascript
浅析showModalDialog数据缓存问题(用禁止浏览器缓存解决)
2013/07/09 Javascript
js实现弹出窗口、页面变成灰色并不可操作的例子分享
2014/05/10 Javascript
《JavaScript DOM 编程艺术》读书笔记之JavaScript 简史
2015/01/09 Javascript
javascript框架设计之种子模块
2015/06/23 Javascript
JavaScript弹出对话框的三种方式
2016/03/23 Javascript
AngularJS使用ng-Cloak阻止初始化闪烁问题的方法
2016/11/03 Javascript
jQuery实现对象转为url参数的方法
2017/01/11 Javascript
vuejs父子组件通信的问题
2017/01/11 Javascript
JavaScript中transform实现数字翻页效果
2017/03/08 Javascript
浅谈关于axios和session的一些事
2017/07/13 Javascript
jQuery实现腾讯信用界面(自制刻度尺)样式
2017/08/15 jQuery
vuejs选中当前样式active的实例
2018/08/22 Javascript
js限制输入框只能输入数字(onkeyup触发)
2018/09/28 Javascript
微信小程序使用map组件实现解析经纬度功能示例
2019/01/22 Javascript
[59:32]Liquid vs Fnatic 2019国际邀请赛淘汰赛败者组BO1 8.20.mp4
2020/07/19 DOTA
Python实现的几个常用排序算法实例
2014/06/16 Python
python多重继承实例
2014/10/11 Python
使用Python中的tkinter模块作图的方法
2017/02/07 Python
Python语言生成水仙花数代码示例
2017/12/18 Python
python 对key为时间的dict排序方法
2018/10/17 Python
对python读取zip压缩文件里面的csv数据实例详解
2019/02/08 Python
Python3内置模块pprint让打印比print更美观详解
2019/06/02 Python
python的pip有什么用
2020/06/17 Python
html5简介_动力节点Java学院整理
2017/07/07 HTML / CSS
html5借用repeating-linear-gradient实现一把刻度尺(ruler)
2019/09/09 HTML / CSS
研发工程师的岗位职责
2013/11/18 职场文书
广告学专业推荐信范文
2013/11/23 职场文书
数学系个人求职信范文
2014/01/30 职场文书
团队激励口号
2014/06/06 职场文书
2014年安全员工作总结
2014/11/13 职场文书
员工离职感谢信
2015/01/22 职场文书
go语言中切片与内存复制 memcpy 的实现操作
2021/04/27 Golang
jackson json序列化实现首字母大写,第二个字母需小写
2021/06/29 Java/Android