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 相关文章推荐
?算你??的 PHP 程式大小
Dec 06 PHP
PHP 中的批处理的实现
Jun 14 PHP
PHP读取网页文件内容的实现代码(fopen,curl等)
Jun 23 PHP
php ctype函数中文翻译和示例
Mar 21 PHP
php画图实例
Nov 05 PHP
yii中widget的用法
Dec 03 PHP
PHP+MYSQL实现用户的增删改查
Mar 24 PHP
PHP技术开发微信公众平台
Jul 22 PHP
yii2分页之实现跳转到具体某页的实例代码
Jun 02 PHP
Yii核心验证器api详解
Nov 23 PHP
如何打开php的gd2库
Feb 09 PHP
laravel 实现划分admin和home 模块分组
Oct 15 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
php allow_url_include的应用和解释
2010/04/22 PHP
php 函数中使用static的说明
2012/06/01 PHP
探讨各种PHP字符串函数的总结分析
2013/06/05 PHP
支持中文和其他编码的php截取字符串函数分享(截取中文字符串)
2014/03/13 PHP
php实现获取农历(阴历)、节日、节气的类与用法示例
2017/11/20 PHP
浅谈PHP进程管理
2019/03/08 PHP
php判断某个方法是否存在函数function_exists (),method_exists()与is_callable()区别与用法解析
2020/04/20 PHP
Gambit vs ForZe BO3 第一场 2.13
2021/03/10 DOTA
jquery中实现标签切换效果的代码
2011/03/01 Javascript
基于jQuery的让非HTML5浏览器支持placeholder属性的代码
2011/05/24 Javascript
jQuery功能函数详解
2015/02/01 Javascript
基于html5和nodejs相结合实现websocket即使通讯
2015/11/19 NodeJs
javascript html实现网页版日历代码
2016/03/08 Javascript
基于JavaScript实现拖动滑块效果
2017/02/16 Javascript
详解如何用webpack打包一个网站应用项目
2017/07/12 Javascript
webpack4 CSS Tree Shaking的使用
2018/09/03 Javascript
JavaScript对象的特性与实践应用深入详解
2018/12/30 Javascript
解决layui弹框失效的问题
2019/09/09 Javascript
python实现爬虫下载漫画示例
2014/02/16 Python
python列表操作实例
2015/01/14 Python
Python 删除整个文本中的空格,并实现按行显示
2018/07/24 Python
使用pycharm在本地开发并实时同步到服务器
2019/08/02 Python
Django 实现前端图片压缩功能的方法
2019/08/07 Python
浅谈Python3实现两个矩形的交并比(IoU)
2020/01/18 Python
python3中sorted函数里cmp参数改变详解
2020/03/12 Python
Python读写操作csv和excle文件代码实例
2020/03/16 Python
皮尔·卡丹巴西官方商店:Pierre Cardin
2017/07/21 全球购物
Ariat英国官网:为世界顶级马术运动员制造最优质的鞋类和服装
2020/02/14 全球购物
解决方案设计综合面试题
2015/08/31 面试题
库房管理员岗位职责
2014/03/09 职场文书
学生社团文化节开幕式主持词
2014/03/28 职场文书
英语感谢信范文
2015/01/20 职场文书
会计求职简历自我评价
2015/03/10 职场文书
2015学校师德师风工作总结
2015/04/22 职场文书
医院感染管理制度
2015/08/05 职场文书
JS精髓原型链继承及构造函数继承问题纠正
2022/06/16 Javascript