Discuz 5.0 中读取纯真IP数据库函数分析
Discuz 5.0 中读取纯真IP数据库函数分析
发布时间:2016-12-29 来源:查字典编辑
摘要:Discuz5.0不在使用自己的IP数据,而是使用纯真IP的数据格式,存取纯真IP数据库稍微有点麻烦,它的存储格式比较特殊也很有趣,具体的格...

Discuz5.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)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)){

return'IPAddressError';

}

//打开IP数据文件

if(!$fd=@fopen($dat_path,'rb')){

return'IPdatefilenotexistsoraccessdenied';

}

//分解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'SystemError';

}

//提取出来的数据转换成长整形,如果数据是负数则加上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'SystemError';

}

$DataSeek=implode('',unpack('L',$DataSeek.chr(0)));

fseek($fd,$DataSeek);

$ipData2=fread($fd,4);

if(strlen($ipData2)<4){

fclose($fd);

return'SystemError';

}

$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'SystemError';

}

$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'SystemError';

}

$ipFlag=fread($fd,1);

if($ipFlag==chr(2)){

$AddrSeek2=fread($fd,3);

if(strlen($AddrSeek2)<3){

fclose($fd);

return'SystemError';

}

$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'SystemError';

}

$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;

}

//========================

//

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

//

//========================

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数据

?>

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新php教程学习
热门php教程学习
编程开发子分类