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

2018-09-07 12:46

阅读:682

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

《纯真IP数据库格式详解》
链接一:
链接二:

纯真IP数据库官网:
纯真IP数据库下载:


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


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

//检查IP地址
if(!preg_match(/^d{1,3}.d{1,3}.d{1,3}.d{1,3}$/,$ip)){
returnIPAddressError;
}
//打开IP数据文件
if(!$fd=@fopen($dat_path,rb)){
returnIPdatefilenotexistsoraccessdenied;
}

//分解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);
returnSystemError;
}
//提取出来的数据转换成长整形,如果数据是负数则加上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);
returnSystemError;
}
$DataSeek=implode(,unpack(L,$DataSeek.chr(0)));
fseek($fd,$DataSeek);
$ipData2=fread($fd,4);
if(strlen($ipData2)<4){
fclose($fd);
returnSystemError;
}
$ip2num=implode(,unpack(L,$ipData2));
if($ip2num<0)$ip2num+=pow(2,32);

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

//下面的代码读晕了,没读明白,有兴趣的慢慢读
$ipFlag=fread($fd,1);
if($ipFlag==chr(1)){
$ipSeek=fread($fd,3);
if(strlen($ipSeek)<3){
fclose($fd);
returnSystemError;
}
$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);
returnSystemError;
}
$ipFlag=fread($fd,1);
if($ipFlag==chr(2)){
$AddrSeek2=fread($fd,3);
if(strlen($AddrSeek2)<3){
fclose($fd);
returnSystemError;
}
$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);
returnSystemError;
}
$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(/^s*/is,,$ipaddr);
$ipaddr=preg_replace(/s*$/is,,$ipaddr);
if(preg_match(/http/i,$ipaddr)$ipaddr==){
$ipaddr=Unknown;
}

return$ipaddr;
}


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

echoconvertip(219.238.235.10);
//输出:北京市电信通

echoconvertip(23.56.82.12);
//输出:IANA

echoconvertip(250.69.52.0);
//输出:IANA保留地址

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

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

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

?>


评论


亲,登录后才可以留言!