解析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,不用COM,生成excel文件
Oct 09 PHP
php数组函数序列之asort() - 对数组的元素值进行升序排序,保持索引关系
Nov 02 PHP
PHP中4个加速、缓存扩展的区别和选用建议
Mar 12 PHP
PHP简单获取及判断提交来源的方法
Apr 22 PHP
详解PHP中array_rand函数的使用方法
Sep 11 PHP
php实现跨域提交form表单的方法【2种方法】
Oct 17 PHP
php7安装mongoDB扩展的方法分析
Aug 02 PHP
PHP开发之归档格式phar文件概念与用法详解【创建,使用,解包还原提取】
Nov 17 PHP
PHP实现浏览器格式化显示XML的方法示例
Jan 22 PHP
php的命名空间与自动加载实现方法
Aug 25 PHP
PHP日期和时间函数的使用示例详解
Aug 06 PHP
基于PHP实现发微博动态代码实例
Dec 11 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
德生S2000南麂列岛台湾FM收听记录
2021/03/02 无线电
smarty中post用法实例
2014/11/28 PHP
thinkphp5.1 框架钩子和行为用法实例分析
2020/05/25 PHP
HTML TO JavaScript 转换
2006/06/26 Javascript
Mootools 1.2教程 函数
2009/09/15 Javascript
模拟用户点击弹出新页面不会被浏览器拦截
2014/04/08 Javascript
jquery获取select选中值的方法分析
2015/12/22 Javascript
JavaScript实现时间倒计时跳转(推荐)
2016/06/28 Javascript
JS实现显示带倒影的图片横排居中放大展示特效实例【测试可用】
2016/08/23 Javascript
JS中BOM相关知识点总结(必看篇)
2016/11/22 Javascript
jquery select2的使用心得(推荐)
2016/12/04 Javascript
easyui简介_动力节点Java学院整理
2017/07/14 Javascript
Angularjs的$http异步删除数据详解及实例
2017/07/27 Javascript
VSCode中如何利用d.ts文件进行js智能提示
2018/04/13 Javascript
使用vue打包进行云服务器上传的问题
2020/03/02 Javascript
js实现简单放大镜效果
2020/03/07 Javascript
JavaScript实现拖拽效果
2020/03/16 Javascript
解决vant框架做H5时踩过的坑(下拉刷新、上拉加载等)
2020/11/11 Javascript
在vue中通过render函数给子组件设置ref操作
2020/11/17 Vue.js
python中验证码连通域分割的方法详解
2018/06/04 Python
修复 Django migration 时遇到的问题解决
2018/06/14 Python
python 实现对数据集的归一化的方法(0-1之间)
2018/07/17 Python
pytorch方法测试——激活函数(ReLU)详解
2020/01/15 Python
使用tensorflow框架在Colab上跑通猫狗识别代码
2020/04/26 Python
Python应用实现处理excel数据过程解析
2020/06/19 Python
Pytest测试框架基本使用方法详解
2020/11/25 Python
美国男士内衣品牌:Tommy John
2017/12/22 全球购物
英国领先的瓷砖专家:Walls and Floors
2018/04/27 全球购物
一套中级Java程序员笔试题
2015/01/14 面试题
畜牧兽医本科生个人的自我评价
2013/10/11 职场文书
致跳远运动员加油稿
2014/02/11 职场文书
大学生在校学习的自我评价
2014/02/18 职场文书
2014年两会学习心得范例
2014/03/17 职场文书
大二学生自我检讨书
2014/10/23 职场文书
忠诚教育学习心得体会
2016/01/23 职场文书
微信小程序基础教程之echart的使用
2021/06/01 Javascript