愤怒的大鸟 发表于 2015-2-4 00:11:06

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

在一个团队之中或者说是在一个公司的工作岗位上,需要注重团队之间的交流合作;在学习或工作上都要端正自己的态度,要以认真的态度来对每件事,这样才能让自己更快的投入、更快的学习,而不至于浪费自己的时间。   依据 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支持的不是很好,所以能少用还是少用的好。

再见西城 发表于 2015-3-7 04:09:43

我还是推荐用firefox ,配上firebug 插件调试js能省下不受时间。谷歌的浏览器最好也不少用,因为谷歌的大侠们实在是太天才啦,把一些原来的js代码加了一些特效。

小魔女 发表于 2015-3-8 00:21:29

遇到出错的时候,我经常把错误信息直接复制到 google的搜索栏,一般情况都是能搜到结果的,不过有时候会搜出来一大片英文的出来,这时候就得过滤一下,吧中文的弄出来,挨着式方法。

柔情似水 发表于 2015-3-10 23:26:08

php是动态网站开发的优秀语言,在学习的时候万万不能冒进。在系统的学习前,我认为不应该只是追求实现某种效果,因为即使你复制他人的代码调试成功,实现了你所期望的效果,你也不了解其中的原理。

小女巫 发表于 2015-3-17 00:10:36

曾经犯过一个很低级的错误,我在文件命名的时候用了一个横线\\\\\\\'-\\\\\\\' 号,结果找了好几个小时的错误,事实是命名的时候 是不能用横线 \\\\\\\'-\\\\\\\' 的,应该用的是下划线\\\\\\\'_\\\\\\\' ;

深爱那片海 发表于 2015-3-17 08:48:00

多看优秀程序员编写的代码,仔细理解他们解决问题的方法,对自身有很大的帮助。

活着的死人 发表于 2015-3-17 12:09:47

有位前辈曾经跟我说过,phper 至少要掌握200个函数 编起程序来才能顺畅点,那些不熟悉的函数记不住也要一拿手册就能找到。所以建议新手们没事就看看php的手册(至少array函数和string函数是要记牢的)。

谁可相欹 发表于 2015-3-22 05:06:58

兴趣是最好的老师,百度是最好的词典。

灵魂腐蚀 发表于 2015-3-29 12:54:30

首先声明:我是一个菜鸟,是一个初学者。学习了一段php后总是感觉自己没有提高,无奈。经过反思我认为我学习过程中存在很多问题,我改变了学习方法后自我感觉有了明显的进步。

山那边是海 发表于 2015-4-10 09:51:10

其实也不算什么什么心得,在各位大侠算是小巫见大巫了吧,望大家不要见笑,若其中有错误的地方请各位大虾斧正。

老尸 发表于 2015-4-11 09:13:51

如果你可以写完像留言板这样的程序,那么你可以去一些别人的代码了,

简单生活 发表于 2015-4-12 14:29:52

要进行开发,搭建环境是首先需要做的事,windows下面我习惯把环境那个安装在C盘下面,因为我配的环境经常出现诡异事件,什么事都没做环境有的时候就不能用啦。

只想知道 发表于 2015-4-13 10:42:18

我还是推荐用firefox ,配上firebug 插件调试js能省下不受时间。谷歌的浏览器最好也不少用,因为谷歌的大侠们实在是太天才啦,把一些原来的js代码加了一些特效。

爱飞 发表于 2015-4-18 20:12:50

建数据库表的时候,int型要输入长度的,其实是个摆设的输入几位都没影响的,只要大于4就行,囧。

海妖 发表于 2015-4-22 17:10:51

使用 jquery 等js框架的时候,要随时注意浏览器的更新情况,不然很容易发生框架不能使用。

变相怪杰 发表于 2015-4-25 11:22:02

首推的搜索引擎当然是Google大神,其次我比较喜欢 百度知道。不过搜出来的结果往往都是 大家copy来copy去的,运气的的概率很大。

愤怒的大鸟 发表于 2015-4-28 01:54:10

爱上php,他也会爱上你。
页: [1]
查看完整版本: PHP教程之使用 QQWry.Dat 完成 IP 地址高效检索(...