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

2024-02-29 18:32

本文主要是介绍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)

 

这篇关于PHP读取纯真IP数据库的函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/759667

相关文章

数据库oracle用户密码过期查询及解决方案

《数据库oracle用户密码过期查询及解决方案》:本文主要介绍如何处理ORACLE数据库用户密码过期和修改密码期限的问题,包括创建用户、赋予权限、修改密码、解锁用户和设置密码期限,文中通过代码介绍... 目录前言一、创建用户、赋予权限、修改密码、解锁用户和设置期限二、查询用户密码期限和过期后的修改1.查询用

mysql数据库分区的使用

《mysql数据库分区的使用》MySQL分区技术通过将大表分割成多个较小片段,提高查询性能、管理效率和数据存储效率,本文就来介绍一下mysql数据库分区的使用,感兴趣的可以了解一下... 目录【一】分区的基本概念【1】物理存储与逻辑分割【2】查询性能提升【3】数据管理与维护【4】扩展性与并行处理【二】分区的

IDEA如何切换数据库版本mysql5或mysql8

《IDEA如何切换数据库版本mysql5或mysql8》本文介绍了如何将IntelliJIDEA从MySQL5切换到MySQL8的详细步骤,包括下载MySQL8、安装、配置、停止旧服务、启动新服务以及... 目录问题描述解决方案第一步第二步第三步第四步第五步总结问题描述最近想开发一个新应用,想使用mysq

Oracle数据库使用 listagg去重删除重复数据的方法汇总

《Oracle数据库使用listagg去重删除重复数据的方法汇总》文章介绍了在Oracle数据库中使用LISTAGG和XMLAGG函数进行字符串聚合并去重的方法,包括去重聚合、使用XML解析和CLO... 目录案例表第一种:使用wm_concat() + distinct去重聚合第二种:使用listagg,

shell脚本快速检查192.168.1网段ip是否在用的方法

《shell脚本快速检查192.168.1网段ip是否在用的方法》该Shell脚本通过并发ping命令检查192.168.1网段中哪些IP地址正在使用,脚本定义了网络段、超时时间和并行扫描数量,并使用... 目录脚本:检查 192.168.1 网段 IP 是否在用脚本说明使用方法示例输出优化建议总结检查 1

Java读取InfluxDB数据库的方法详解

《Java读取InfluxDB数据库的方法详解》本文介绍基于Java语言,读取InfluxDB数据库的方法,包括读取InfluxDB的所有数据库,以及指定数据库中的measurement、field、... 首先,创建一个Java项目,用于撰写代码。接下来,配置所需要的依赖;这里我们就选择可用于与Infl

Oracle的to_date()函数详解

《Oracle的to_date()函数详解》Oracle的to_date()函数用于日期格式转换,需要注意Oracle中不区分大小写的MM和mm格式代码,应使用mi代替分钟,此外,Oracle还支持毫... 目录oracle的to_date()函数一.在使用Oracle的to_date函数来做日期转换二.日

C#读取本地网络配置信息全攻略分享

《C#读取本地网络配置信息全攻略分享》在当今数字化时代,网络已深度融入我们生活与工作的方方面面,对于软件开发而言,掌握本地计算机的网络配置信息显得尤为关键,而在C#编程的世界里,我们又该如何巧妙地读取... 目录一、引言二、C# 读取本地网络配置信息的基础准备2.1 引入关键命名空间2.2 理解核心类与方法

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二