Discuz 5.0 中读取纯真IP数据库函数分析


Posted in PHP onMarch 16, 2007

Discuz  5.0 不在使用自己的IP数据,而是使用纯真IP的数据格式, 存取纯真IP数据库稍微有点麻烦,它的存储格式比较特殊也很有趣,具体的格式分析参考下面两个链接,其他语言实现参考文章末的链接。

《纯真IP数据库格式详解》
链接一:http://blog.csdn.net/heiyeshuwu/archive/2006/05/12/725675.aspx
链接二:http://lumaqq.linuxsir.org/article/qqwry_format_detail.html

纯真IP数据库官网:http://www.cz88.net/ip/
纯真IP数据库下载:http://update.cz88.net/soft/qqwry.rar

以下函数conrvertip()位于 Discuz!5_GBK/upload/include/misc.func.php 路径中,有兴趣可以具体去阅读分析。(下面代码我做了简单的修改,更便于阅读,核心没有修改)

<?
//===================================
//
// 功能:IP地址获取真实地址函数
// 参数:$ip - IP地址
// 作者:[Discuz!] (C) Comsenz Inc.
//
//===================================
function convertip($ip) {
   //IP数据文件路径
   $dat_path = 'QQWry.Dat';

   //检查IP地址
   if(!preg_match("/^d{1,3}.d{1,3}.d{1,3}.d{1,3}$/", $ip)) {
       return 'IP Address Error';
   }
   //打开IP数据文件
   if(!$fd = @fopen($dat_path, 'rb')){
       return 'IP date file not exists or access denied';
   }

   //分解IP进行运算,得出整形数
   $ip = explode('.', $ip);
   $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];

   //获取IP数据索引开始和结束位置
   $DataBegin = fread($fd, 4);
   $DataEnd = fread($fd, 4);
   $ipbegin = implode('', unpack('L', $DataBegin));
   if($ipbegin < 0) $ipbegin += pow(2, 32);
   $ipend = implode('', unpack('L', $DataEnd));
   if($ipend < 0) $ipend += pow(2, 32);
   $ipAllNum = ($ipend - $ipbegin) / 7 + 1;

   $BeginNum = 0;
   $EndNum = $ipAllNum;

   //使用二分查找法从索引记录中搜索匹配的IP记录
   while($ip1num>$ipNum || $ip2num<$ipNum) {
       $Middle= intval(($EndNum + $BeginNum) / 2);

       //偏移指针到索引位置读取4个字节
       fseek($fd, $ipbegin + 7 * $Middle);
       $ipData1 = fread($fd, 4);
       if(strlen($ipData1) < 4) {
           fclose($fd);
           return 'System Error';
       }
       //提取出来的数据转换成长整形,如果数据是负数则加上2的32次幂
       $ip1num = implode('', unpack('L', $ipData1));
       if($ip1num < 0) $ip1num += pow(2, 32);

       //提取的长整型数大于我们IP地址则修改结束位置进行下一次循环
       if($ip1num > $ipNum) {
           $EndNum = $Middle;
           continue;
       }

       //取完上一个索引后取下一个索引
       $DataSeek = fread($fd, 3);
       if(strlen($DataSeek) < 3) {
           fclose($fd);
           return 'System Error';
       }
       $DataSeek = implode('', unpack('L', $DataSeek.chr(0)));
       fseek($fd, $DataSeek);
       $ipData2 = fread($fd, 4);
       if(strlen($ipData2) < 4) {
           fclose($fd);
           return 'System Error';
       }
       $ip2num = implode('', unpack('L', $ipData2));
       if($ip2num < 0) $ip2num += pow(2, 32);

       //没找到提示未知
       if($ip2num < $ipNum) {
           if($Middle == $BeginNum) {
               fclose($fd);
               return 'Unknown';
           }
           $BeginNum = $Middle;
       }
   }

   //下面的代码读晕了,没读明白,有兴趣的慢慢读
   $ipFlag = fread($fd, 1);
   if($ipFlag == chr(1)) {
       $ipSeek = fread($fd, 3);
       if(strlen($ipSeek) < 3) {
           fclose($fd);
           return 'System Error';
       }
       $ipSeek = implode('', unpack('L', $ipSeek.chr(0)));
       fseek($fd, $ipSeek);
       $ipFlag = fread($fd, 1);
   }

   if($ipFlag == chr(2)) {
       $AddrSeek = fread($fd, 3);
       if(strlen($AddrSeek) < 3) {
           fclose($fd);
           return 'System Error';
       }
       $ipFlag = fread($fd, 1);
       if($ipFlag == chr(2)) {
           $AddrSeek2 = fread($fd, 3);
           if(strlen($AddrSeek2) < 3) {
               fclose($fd);
               return 'System Error';
           }
           $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
           fseek($fd, $AddrSeek2);
       } else {
           fseek($fd, -1, SEEK_CUR);
       }

       while(($char = fread($fd, 1)) != chr(0))
           $ipAddr2 .= $char;

       $AddrSeek = implode('', unpack('L', $AddrSeek.chr(0)));
       fseek($fd, $AddrSeek);

       while(($char = fread($fd, 1)) != chr(0))
           $ipAddr1 .= $char;
   } else {
       fseek($fd, -1, SEEK_CUR);
       while(($char = fread($fd, 1)) != chr(0))
           $ipAddr1 .= $char;

       $ipFlag = fread($fd, 1);
       if($ipFlag == chr(2)) {
           $AddrSeek2 = fread($fd, 3);
           if(strlen($AddrSeek2) < 3) {
               fclose($fd);
               return 'System Error';
           }
           $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
           fseek($fd, $AddrSeek2);
       } else {
           fseek($fd, -1, SEEK_CUR);
       }
       while(($char = fread($fd, 1)) != chr(0)){
           $ipAddr2 .= $char;
       }
   }
   fclose($fd);

   //最后做相应的替换操作后返回结果
   if(preg_match('/http/i', $ipAddr2)) {
       $ipAddr2 = '';
   }
   $ipaddr = "$ipAddr1 $ipAddr2";
   $ipaddr = preg_replace('/CZ88.NET/is', '', $ipaddr);
   $ipaddr = preg_replace('/^s*/is', '', $ipaddr);
   $ipaddr = preg_replace('/s*$/is', '', $ipaddr);
   if(preg_match('/http/i', $ipaddr) || $ipaddr == '') {
       $ipaddr = 'Unknown';
   }

   return $ipaddr;
}

//========================
//
//  调用举例(速度很快)
//
//========================

echo convertip('219.238.235.10');
//输出: 北京市 电信通

echo convertip('23.56.82.12');
//输出:IANA

echo convertip('250.69.52.0');
//输出:IANA保留地址

echo convertip('238.69.52.0');
//输出:IANA保留地址 用于多点传送

echo convertip('192.168.0.1');
//输出:局域网 对方和您在同一内部网

echo convertip('255.255.255.255');
//输出:纯真网络 2006年11月20日IP数据

?>

PHP 相关文章推荐
在字符串中把网址改成超级链接
Oct 09 PHP
PHP中的MYSQL常用函数(php下操作数据库必备)
Sep 12 PHP
php异常处理使用示例
Feb 25 PHP
Smarty中调用FCKeditor的方法
Oct 27 PHP
Java和PHP在Web开发方面对比分析
Mar 01 PHP
PHP封装的Twitter访问类实例
Jul 18 PHP
php编程中echo用逗号和用点号连接的区别
Mar 26 PHP
PHP框架性能测试报告
May 08 PHP
PHP生成图像验证码的方法小结(2种方法)
Jul 18 PHP
PHP new static 和 new self详解
Feb 19 PHP
PHP中-&gt;和=&gt;的含义及使用示例解析
Aug 06 PHP
详细分析PHP7与PHP5区别
Jun 26 PHP
初级的用php写的采集程序
Mar 16 #PHP
php下使用无限生命期Session的方法
Mar 16 #PHP
随时给自己贴的图片加文字的php水印
Mar 16 #PHP
php的一个登录的类 [推荐]
Mar 16 #PHP
对Session和Cookie的区分与解释
Mar 16 #PHP
PHP中cookies使用指南
Mar 16 #PHP
PHP学习资料汇总与网址
Mar 16 #PHP
You might like
Centos下升级php5.2到php5.4全记录(编译安装)
2015/04/03 PHP
PHP中Http协议post请求参数
2015/11/02 PHP
PHP表单数据写入MySQL数据库的代码
2016/05/31 PHP
PHP多维数组指定多字段排序的示例代码
2018/05/16 PHP
Nigma vs Alliance BO5 第五场2.14
2021/03/10 DOTA
jquery.jstree 增加节点的双击事件代码
2010/07/27 Javascript
jquery ajax提交整个表单元素的快捷办法
2013/03/27 Javascript
javascript解决innerText浏览器兼容问题思路代码
2013/05/17 Javascript
jquery设置控件位置的方法
2013/08/21 Javascript
JSON传递bool类型数据的处理方式介绍
2013/09/18 Javascript
jQuery表格排序组件-tablesorter使用示例
2014/05/26 Javascript
每天一篇javascript学习小结(Array数组)
2015/11/11 Javascript
深入探究AngularJS框架中Scope对象的超级教程
2016/01/04 Javascript
node.js连接mongoDB数据库 快速搭建自己的web服务
2016/04/17 Javascript
JS动态插入并立即执行回调函数的方法
2016/04/21 Javascript
怎么限制input的text里输入的值只能是数字(正则、js)
2016/05/16 Javascript
jqPlot jQuery绘图插件的使用
2016/06/18 Javascript
jQuery表格(Table)基本操作实例分析
2017/03/10 Javascript
微信小程序封装自定义弹窗的实现代码
2019/05/08 Javascript
微信小程序绘制图片发送朋友圈
2019/07/25 Javascript
解决layer弹出层msg的文字不显示的问题
2019/09/11 Javascript
关于numpy中np.nonzero()函数用法的详解
2017/02/07 Python
Python 使用PIL numpy 实现拼接图片的示例
2018/05/08 Python
python使用turtle库绘制树
2018/06/25 Python
python实现旋转和水平翻转的方法
2018/10/25 Python
Django基础知识 web框架的本质详解
2019/07/18 Python
python 标准差计算的实现(std)
2019/07/29 Python
统计每一学生的平均成绩
2014/06/06 面试题
优秀学生自我鉴定范例
2013/12/18 职场文书
公司培训心得体会
2014/01/03 职场文书
机械专业求职信范文
2014/07/15 职场文书
中小学校园安全广播稿
2014/09/29 职场文书
2014年节能工作总结
2014/12/18 职场文书
2019新员工试用期转正工作总结范文
2019/08/21 职场文书
Python正则表达式中flags参数的实例详解
2022/04/01 Python
SpringBoot前端后端分离之Nginx服务器下载安装过程
2022/08/14 Servers