仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 776|回复: 19
打印 上一主题 下一主题

[学习教程] PHP教程之使用 QQWry.Dat 完成 IP 地址高效检索(...

[复制链接]
愤怒的大鸟 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-2-4 00:11:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
在一个团队之中或者说是在一个公司的工作岗位上,需要注重团队之间的交流合作;在学习或工作上都要端正自己的态度,要以认真的态度来对每件事,这样才能让自己更快的投入、更快的学习,而不至于浪费自己的时间。   依据 LumaQQ 开辟者文档中的纯挚 IP 数据库格局详解,我编写了一个 PHP 的查询 IP 地点区域信息的类。在编写过程当中发明纯挚 IP 数据库格局详解中关于纪录区的描写不是很周全,不外收支也不是很大,所以我没需要再写一份纯挚 IP 数据库的格局申明了,人人感乐趣的话,读一读上面的代码应当就可以看出来了。代码中加了很具体的正文,应当很轻易读懂的。
在创立这个类的一个实例后,实例中就保留了翻开的文件指针和一些查询需求的信息,每次查询时不需求从头翻开文件,直到页面履行停止后,翻开的文件才会主动封闭。如许。在一个页面内停止屡次查询时,效力是很高的。而且此类不但可以直接查询 IP,还可以主动将域名解析为 IP 停止查询。
上面是法式代码:
<?php
/**
* IP 地舆地位查询类
*
* @author 马秉尧
* @version 1.5
* @copyright 2005 CoolCode.CN
*/
class IpLocation {
    /**
     * QQWry.Dat文件指针
     *
     * @var resource
     */
    var $fp;

    /**
     * 第一条IP纪录的偏移地址
     *
     * @var int
     */
    var $firstip;

    /**
     * 最初一条IP纪录的偏移地址
     *
     * @var int
     */
    var $lastip;

    /**
     * IP纪录的总条数(不包括版本信息纪录)
     *
     * @var int
     */
    var $totalip;

    /**
     * 前往读取的长整型数
     *
     * @access private
     * @return int
     */
    function getlong() {
        //将读取的little-endian编码的4个字节转化为长整型数
        $result = unpack('Vlong', fread($this->fp, 4));
        return $result['long'];
    }

    /**
     * 前往读取的3个字节的长整型数
     *
     * @access private
     * @return int
     */
    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
     */
    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
     */
    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
     */
    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;
    }

    /**
     * 机关函数,翻开 QQWry.Dat 文件并初始化类中的信息
     *
     * @param string $filename
     * @return IpLocation
     */
    function IpLocation($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;
            //注册析构函数,使其在法式履行停止时履行
            register_shutdown_function(array(&$this, '_IpLocation'));
        }
    }

    /**
     * 析构函数,用于在页面履行停止后主动封闭翻开的文件。
     *
     */
    function _IpLocation() {
        if ($this->fp) {
            fclose($this->fp);
        }
        $this->fp = 0;
    }
}
?>

应该大致熟悉了一些学习过程,也许我的过程和你的有些出路,但是不管怎么样是殊途同归,我写这么多,也只是给大家一个借鉴的机会,至于好与不好,默默不敢打包票^0^
若相依 该用户已被删除
沙发
发表于 2015-2-7 19:41:55 | 只看该作者
微软最近出的新字体“微软雅黑”,虽然是挺漂亮的,不过firefox  支持的不是很好,所以能少用还是少用的好。
精灵巫婆 该用户已被删除
板凳
发表于 2015-2-13 21:20:45 | 只看该作者
多看优秀程序员编写的代码,仔细理解他们解决问题的方法,对自身有很大的帮助。
莫相离 该用户已被删除
地板
发表于 2015-2-23 02:59:00 | 只看该作者
微软最近出的新字体“微软雅黑”,虽然是挺漂亮的,不过firefox  支持的不是很好,所以能少用还是少用的好。
再见西城 该用户已被删除
5#
发表于 2015-3-7 04:09:43 | 只看该作者
我还是推荐用firefox ,配上firebug 插件调试js能省下不受时间。谷歌的浏览器最好也不少用,因为谷歌的大侠们实在是太天才啦,把一些原来的js代码加了一些特效。
小魔女 该用户已被删除
6#
发表于 2015-3-8 00:21:29 | 只看该作者
遇到出错的时候,我经常把错误信息直接复制到 google的搜索栏,一般情况都是能搜到结果的,不过有时候会搜出来一大片英文的出来,这时候就得过滤一下,吧中文的弄出来,挨着式方法。
柔情似水 该用户已被删除
7#
发表于 2015-3-10 23:26:08 | 只看该作者
php是动态网站开发的优秀语言,在学习的时候万万不能冒进。在系统的学习前,我认为不应该只是追求实现某种效果,因为即使你复制他人的代码调试成功,实现了你所期望的效果,你也不了解其中的原理。
小女巫 该用户已被删除
8#
发表于 2015-3-17 00:10:36 | 只看该作者
曾经犯过一个很低级的错误,我在文件命名的时候用了一个横线\\\\\\\'-\\\\\\\' 号,结果找了好几个小时的错误,事实是命名的时候 是不能用横线 \\\\\\\'-\\\\\\\' 的,应该用的是下划线  \\\\\\\'_\\\\\\\' ;
深爱那片海 该用户已被删除
9#
发表于 2015-3-17 08:48:00 | 只看该作者
多看优秀程序员编写的代码,仔细理解他们解决问题的方法,对自身有很大的帮助。
活着的死人 该用户已被删除
10#
发表于 2015-3-17 12:09:47 | 只看该作者
有位前辈曾经跟我说过,phper 至少要掌握200个函数 编起程序来才能顺畅点,那些不熟悉的函数记不住也要一拿手册就能找到。所以建议新手们没事就看看php的手册(至少array函数和string函数是要记牢的)。
谁可相欹 该用户已被删除
11#
发表于 2015-3-22 05:06:58 | 只看该作者
兴趣是最好的老师,百度是最好的词典。
灵魂腐蚀 该用户已被删除
12#
发表于 2015-3-29 12:54:30 | 只看该作者
首先声明:我是一个菜鸟,是一个初学者。学习了一段php后总是感觉自己没有提高,无奈。经过反思我认为我学习过程中存在很多问题,我改变了学习方法后自我感觉有了明显的进步。
山那边是海 该用户已被删除
13#
发表于 2015-4-10 09:51:10 | 只看该作者
其实也不算什么什么心得,在各位大侠算是小巫见大巫了吧,望大家不要见笑,若其中有错误的地方请各位大虾斧正。
老尸 该用户已被删除
14#
发表于 2015-4-11 09:13:51 | 只看该作者
如果你可以写完像留言板这样的程序,那么你可以去一些别人的代码了,
简单生活 该用户已被删除
15#
发表于 2015-4-12 14:29:52 | 只看该作者
要进行开发,搭建环境是首先需要做的事,windows下面我习惯把环境那个安装在C盘下面,因为我配的环境经常出现诡异事件,什么事都没做环境有的时候就不能用啦。
只想知道 该用户已被删除
16#
发表于 2015-4-13 10:42:18 | 只看该作者
我还是推荐用firefox ,配上firebug 插件调试js能省下不受时间。谷歌的浏览器最好也不少用,因为谷歌的大侠们实在是太天才啦,把一些原来的js代码加了一些特效。
爱飞 该用户已被删除
17#
发表于 2015-4-18 20:12:50 | 只看该作者
建数据库表的时候,int型要输入长度的,其实是个摆设的输入几位都没影响的,只要大于4就行,囧。
海妖 该用户已被删除
18#
发表于 2015-4-22 17:10:51 | 只看该作者
使用 jquery 等js框架的时候,要随时注意浏览器的更新情况,不然很容易发生框架不能使用。
变相怪杰 该用户已被删除
19#
发表于 2015-4-25 11:22:02 | 只看该作者
首推的搜索引擎当然是Google大神,其次我比较喜欢 百度知道。不过搜出来的结果往往都是 大家copy来copy去的,运气的的概率很大。
愤怒的大鸟 该用户已被删除
20#
 楼主| 发表于 2015-4-28 01:54:10 | 只看该作者
爱上php,他也会爱上你。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-9-20 17:35

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表