PHP读取纯真IP数据库的函数

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)" href="http://www.coolcode.cn/?p=16" rel=bookmark>利用 QQWry.Dat 实现 IP 地址高效检索(Php)(作者: andot)

数据库(QQWry.Dat)查询 C源码" href="http://www.douzi.org/wp/index.Php/articles/71" rel=bookmark>纯真IP数据库(QQWry.Dat)查询 C源码 (作者:Windix)

 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值