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 面向对象 final类与final方法
May 05 PHP
在php中判断一个请求是ajax请求还是普通请求的方法
Jun 28 PHP
php 模拟get_headers函数的代码示例
Apr 27 PHP
php设计模式之命令模式的应用详解
May 21 PHP
discuz免激活同步登入代码修改方法(discuz同步登录)
Dec 24 PHP
linux下安装php的memcached客户端
Aug 03 PHP
php中数据库连接方式pdo和mysqli对比分析
Feb 25 PHP
php实现用于删除整个目录的递归函数
Mar 16 PHP
微信自定义菜单的处理开发示例
Apr 16 PHP
smarty中常用方法实例总结
Aug 07 PHP
php随机生成验证码,php随机生成数字,php随机生成数字加字母!
Apr 01 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项目开发中最常用的自定义函数整理
2010/12/02 PHP
PHP实现把数字ID转字母ID
2013/08/12 PHP
laravel实现按时间日期进行分组统计方法示例
2019/03/23 PHP
ThinkPHP5.1框架页面跳转及修改跳转页面模版示例
2019/05/06 PHP
PHP中关于php.ini参数优化详解
2020/02/28 PHP
IE图片缓存document.execCommand(&quot;BackgroundImageCache&quot;,false,true)
2011/03/01 Javascript
jQuery实现 注册时选择阅读条款 左右移动
2013/04/11 Javascript
node.js中的fs.futimesSync方法使用说明
2014/12/17 Javascript
24款热门实用的jQuery插件推荐
2014/12/24 Javascript
ECMAScript 6即将带给我们新的数组操作方法前瞻
2015/01/06 Javascript
jQuery处理图片加载失败的常用方法
2015/06/08 Javascript
jQuery实现TAB风格的全国省份城市滑动切换效果代码
2015/08/24 Javascript
完美实现js选项卡切换效果(二)
2017/03/08 Javascript
nodejs和C语言插入mysql数据库乱码问题的解决方法
2017/04/14 NodeJs
jQuery实现菜单栏导航效果
2017/08/15 jQuery
在Vue项目中使用d3.js的实例代码
2018/05/01 Javascript
JS非行间样式获取函数的实例代码
2018/06/05 Javascript
Vue props用法详解(小结)
2018/07/03 Javascript
ES6使用新特性Proxy实现的数据绑定功能实例
2020/05/11 Javascript
[46:23]OG vs EG 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
Python2.x中str与unicode相关问题的解决方法
2015/03/30 Python
Linux下Pycharm、Anaconda环境配置及使用踩坑
2018/12/19 Python
50行Python代码实现视频中物体颜色识别和跟踪(必须以红色为例)
2019/11/20 Python
Python实现结构体代码实例
2020/02/10 Python
Python logging日志库空间不足问题解决
2020/09/14 Python
python 服务器运行代码报错ModuleNotFoundError的解决办法
2020/09/16 Python
全球知名巧克力品牌:Godiva
2016/07/22 全球购物
6号汽车旅馆预订:Motel 6
2018/02/11 全球购物
十岁生日父母答谢词
2014/01/18 职场文书
国际商务英语专业求职信
2014/07/08 职场文书
党支部活动策划方案
2014/08/18 职场文书
创先争优活动个人总结
2015/03/04 职场文书
婚宴父亲致辞
2015/07/27 职场文书
预备党员的思想汇报,你真的会写吗?
2019/06/28 职场文书
小学四年级作文之人物作文
2019/11/06 职场文书
JavaScript的Set数据结构详解
2022/02/18 Javascript