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 相关文章推荐
基于qmail的完整WEBMAIL解决方案安装详解
Oct 09 PHP
PHP下用rmdir实现删除目录的三种方法小结
Apr 20 PHP
关于PHP结束标签的使用细节探讨及联想
Mar 04 PHP
PHP防止注入攻击实例分析
Nov 03 PHP
php实现根据词频生成tag云的方法
Apr 17 PHP
10款实用的PHP开源工具
Oct 23 PHP
实现WordPress主题侧边栏切换功能的PHP脚本详解
Dec 14 PHP
yii分页组件用法实例分析
Dec 28 PHP
制作个性化的WordPress登陆界面的实例教程
May 21 PHP
Yii针对添加行的增删改查操作示例
Oct 18 PHP
PHP迭代与递归实现无限级分类
Aug 28 PHP
laravel数据库查询结果自动转数组修改实例
Feb 27 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
example1.php
2006/10/09 PHP
php使用反射插入对象示例分享
2014/03/11 PHP
PHP中捕获超时事件的方法实例
2015/02/12 PHP
CodeIgniter开发实现支付宝接口调用的方法示例
2016/11/14 PHP
PHP5.5新特性之yield理解与用法实例分析
2019/01/11 PHP
仿163填写邮件地址自动显示下拉(无优化)
2008/11/05 Javascript
ExtJS GTGrid 简单用户管理
2009/07/01 Javascript
javascript document.execCommand() 常用解析
2009/12/14 Javascript
javascript右下角弹层及自动隐藏(自己编写)
2013/11/20 Javascript
jquery easyui使用心得
2014/07/07 Javascript
node.js中的fs.utimes方法使用说明
2014/12/15 Javascript
js表头排序实现方法
2015/01/16 Javascript
js实现使用鼠标拖拽切换图片的方法
2015/05/04 Javascript
详解Bootstrap创建表单的三种格式(一)
2016/01/04 Javascript
Javascript的表单验证长度
2016/03/16 Javascript
详解vuejs之v-for列表渲染
2017/06/22 Javascript
Vue.js + Nuxt.js 项目中使用 Vee-validate 表单校验
2019/04/22 Javascript
js设置默认时间跨度过程详解
2019/07/17 Javascript
基于vue、react实现倒计时效果
2019/08/26 Javascript
jstree中的checkbox默认选中和隐藏示例代码
2019/12/29 Javascript
jquery css实现流程进度条
2020/03/26 jQuery
js实现拖拽元素选择和删除
2020/08/25 Javascript
详解Python2.x中对Unicode编码的使用
2015/04/03 Python
使用相同的Apache实例来运行Django和Media文件
2015/07/22 Python
Python读取图片属性信息的实现方法
2016/09/11 Python
python虚拟环境virualenv的安装与使用
2016/12/18 Python
代码详解django中数据库设置
2019/01/28 Python
解析python的局部变量和全局变量
2019/08/15 Python
python对常见数据类型的遍历解析
2019/08/27 Python
Python实现井字棋小游戏
2020/03/09 Python
Python第三方库的几种安装方式(小结)
2020/04/03 Python
欧洲著名的二手奢侈品网站:Vestiaire Collective
2020/03/07 全球购物
公司道歉信范文
2014/01/09 职场文书
公司年会主持词
2014/03/22 职场文书
保护环境倡议书100字
2014/05/19 职场文书
Python Django搭建文件下载服务器的实现
2021/05/10 Python