文档章节

纯真IP地址库合并

心驰
 心驰
发布于 2017/09/06 17:19
字数 689
阅读 6
收藏 0
<?php
/**
 * @author( author = 'xbruce' )
 * @datetime( datetime = '2017年7月2日 下午3:29:44' )
 * @comment( comment='ip地址工具' )
 */
class IpUtils
{
    private static $_instance = null;

    private $_nredis = null;
    
    private $arrIpsTmp = array();
    
    const REDIS_SS_IPS = 'l_ss_ips';
    
    const GREP_IP = "/[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/";
    
    private function __construct( $redis = null )
    {
        if( $redis )
        {
            $this->_nredis = $redis;
        }

        assert( $redis, 'redis实例不能为空!' );
    }

    static public function getInstance( $redis = null )
    {
        assert( $redis, 'redis实例不能为空!' );
        
        if( !$redis )
        {
            echo 'redis实例不能为空!', PHP_EOL;
            return null;
        }
        
        if( is_null( self::$_instance ) )
        {
            self::$_instance = new IpUtils( $redis );
        }
        
        return self::$_instance;
    }
  
    /**
     * 
     * @author( author='xbruce' )
     * @date( date = '2017年7月2日' )
     * @comment( comment = '读文件到内存中以方便写查询缓存' )
     * @method( method = '' )
     * @op( op = '' )
     * @param string $strFileName
     * @return boolean
     */
    public function initIpLibFromFile( string $strFileName = null )
    {
        set_time_limit( 0 );
        ini_set( 'memory_limit', '1024M' );
        
        if( !file_exists( $strFileName ))
        {
            return false;
        }
        
//         $this->removeSetKeys();
        
        $fIp = fopen( $strFileName, 'r' );
        
        if( !$fIp )
        {
            return false;
        }
                
        echo '正在进行缓存请稍后...' . PHP_EOL;
        $ip = array();
        
        $iIndex = 0;
        while( ($line = trim( fgets( $fIp ))) != '' )
        {
            $line = mb_convert_encoding( $line, 'UTF8', 'GBK' );
            
            preg_match_all( "/[^\s]+/", $line, $arrMatches );
            
            if( count( $arrMatches[0] ) < 3 )
            {
                return false;
            }
            
            $arrIpInfo = $arrMatches[0];
            $ip['ip_begin'] = $this->ip2longCust( $arrIpInfo[0] );
            $ip['ip_end'] = $this->ip2longCust( $arrIpInfo[1] );
            
            $ip['info'] = '';
            $key = $arrIpInfo[2];
            $iInfoCnt = count( $arrIpInfo );
            for( $i = 2; $i < $iInfoCnt; ++$i )
            {
                $ip['info'] .= ' ' . $arrIpInfo[$i];
            }
            
            $strKey = md5( $key );
            
            $this->arrIpsTmp[ $strKey ][$ip['ip_begin']] = $ip;

            unset($ip);
        }
        
        fclose( $fIp );
        
        echo '写缓存结束!' . PHP_EOL;
        
        return true;
    }
    
    /**
     * 
     * @author( author='xbruce' )
     * @date( date = '2017年7月2日' )
     * @comment( comment = '' )
     * @method( method = '' )
     * @op( op = '' )
     */
    public function combineAdjacentIp()
    {
        ini_set( 'memory_limit', '1024M' );
        
        $arrDupIps = array();
        $arrKeys = $this->arrIpsTmp;
        
        $iIndex = 0;
        
        foreach( $arrKeys as $v )
        {     
            $arrIps = $v;
            foreach( $arrIps as $ip )
            {
                $arrDupIps[ $ip['ip_begin'] ] = $ip;
            }
            
            unset( $arrIps );
                        
            if( uksort( $arrDupIps, function( $left, $right ){
                if( $left < $right )
                {
                    return -1;
                }
                else if( $left == $right )
                {
                    return 0;
                }
                else 
                {
                    return 1;
                }
            }))
            {
                $iCnt = 0;
                
                $arrTemp = array();
                foreach( $arrDupIps as $key => $val )
                {
                    $arrTemp[$iCnt++] = $val;
                }
                unset( $arrDupIps );
                
                $iTargetIndex = 0;
                
                $curIp = $arrTemp[0];
                
                if( $iCnt > 1 )
                {
                    for( $i = 0; $i < $iCnt; ++$i )
                    {
                        if( $i + 1 < $iCnt && ( $curIp['ip_end'] + 1 == $arrTemp[ $i + 1 ]['ip_begin'] ))
                        {
                            $curIp['ip_end'] = $arrTemp[ $i + 1 ]['ip_end'];
                        }
                        else 
                        {
                            ++$iIndex;
                            $this->_nredis->zAdd( self::REDIS_SS_IPS, $curIp['ip_begin'], json_encode( $curIp ));
                            
                            if( $i + 1 < $iCnt )
                            {
                                $curIp = $arrTemp[$i+1];
                            }
                        }
                        
                    }
                }
                else if( 1 == $iCnt )
                {
                    $this->_nredis->zAdd( self::REDIS_SS_IPS, $curIp['ip_begin'], json_encode( $curIp ));
                    ++$iIndex;                    
                }

                unset( $arrTargets );
                unset( $arrTemp );
                
                echo '已处理到第', $iIndex, '个', PHP_EOL;
            }
            else
            {
                echo '排序失败,请检查错误原因!', PHP_EOL;
                exit();
            }
            
        }
        
        echo PHP_EOL, '成功精简IP地址库!', PHP_EOL;
    }
    
    
    /**
     * 
     * @author( author='xbruce' )
     * @date( date = '2017年7月2日' )
     * @comment( comment = '取IP地址相关信息' )
     * @method( method = '' )
     * @op( op = '' )
     * @param string $strIp
     */
    public function getIpLocation( string $strIp = null )
    {
        if( empty( $strIp ) || ( $strIp = trim( $strIp )) == '' )
        {
            return false;
        }

        $lIp = $this->ip2longCust( $strIp );

        $r = $this->_nredis->zRevRangeByScore( self::REDIS_SS_IPS, $lIp, -1, array( 'limit' => array( 0, 1 )));
        
        if( count( $r ) >= 1 )
        {
            $objIp = json_decode( $r[0] );
            if( $objIp->ip_begin <= $lIp && $lIp <= $objIp->ip_end )
            {
                return $objIp;
            }
            
            return false;
        }
        
        return false;
    }
    
    
    public function test()
    {
        return $this->getIpLocation( '8.8.8.8');
    }
    
    /**
     * @author( author='xbruce' )
     * @date( date = '2017年7月2日' )
     * @comment( comment = '解决因ip2long bug而引起的bug' )
     * @method( method = '' )
     * @op( op = '' )
     * @param string $strIp
     */
    private function ip2longCust( string $strIp )
    {
        if( preg_match( self::GREP_IP, $strIp ) && is_string( $strIp ) )
        {
            $arrIps = explode( '.', $strIp );
            $strIpTmp = '';
            foreach( $arrIps as $k => $v )
            {
                $strIpTmp .= intval( $v ) . '.';
            }
    
            $strIpTmp = rtrim( $strIpTmp, '\.' );
    
            return ip2long( $strIpTmp );
    
        }
    
        return false;
    }
    
}

// $redis = new Redis();

$redis = new Redis();
$redis->connect( '127.0.0.1', 6379 );
$redis->auth( 'pass' );//redis requirepass
// $redis->select( 0 );

$iu = IpUtils::getInstance( $redis );
// var_dump( $iu->initIpLibFromFile( '/git/phcms/czip.txt' ) );//初始化文件到临时文件
// $iu->combineAdjacentIp();//合并同一地的相邻IP

$t = microtime( true );
for( $i = 0; $i < 100000; ++$i )
{
    $objRes = $iu->test();
}

echo microtime( true ) - $t;
//在我的配置很低小本子上可以达到15190QPS以上

本文转载自:https://my.oschina.net/u/1584951/blog/1114029

共有 人打赏支持
心驰
粉丝 0
博文 21
码字总数 1050
作品 0
武汉
程序员
私信 提问
Java解析归属地,以前用纯真库,现在需要兼容ipv6

之前项目用纯真的ip库,然后写的Java代码查询纯真库中相应ip的归属地,现在项目需要支持ipv6的ip地址,所以归属地查询就是问题,首先 纯真的ipv6版本的数据库去哪里下载? 其次 查询该ipv6的...

bluysky
2013/08/15
372
0
国内常用ip地址库

腾讯腾讯IP分享计划IP分享 新浪http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=js 百度Web服务Geocoding API-百度地图 淘宝淘宝IP地址库 geoip MaxMind - IP地理定位...

沉淀岁月
2016/07/19
117
0
C# 调用IP库(QQWry.Dat)查询IP位置及自动升级IP库方法(附IP库下载地址及相关dll下载)

前言 C# 用IP地址(123.125.114.144)查询位置(北京市百度公司)的东西,非常好用也非常方便,可手动升级刷新IP库,一次编码永久收益,可支持winform、asp.net等程序。 本文使用的IP库为, ...

王磊的博客
2012/06/01
0
0
高效查询纯真IP库 --lib-qqwry

lib-qqwry是一个高效查询纯真 IP 库(qqwry.dat)的模块。它是用 NodeJS 解析纯真 IP 库(QQwry.dat) ,支持 IP 段查询。为更好的字符转化效率,未使用iconv模块,直接使用gbk编码表文件。经过不...

含浪
2015/05/22
759
0
关于ip识别的问题和ip存储的问题

在登录网站的时间,一些可以直接通过识别ip来显示相应位置的信息。 ip信息在数据库里面是怎么存储的,我看纯真ip库有四十多万的ip地址信息。如果放在一个表里面去匹配的话时间应该会很长,但...

mrmusic
2015/09/25
199
5

没有更多内容

加载失败,请刷新页面

加载更多

微服务分布式事务实现

https://www.processon.com/view/link/5b2144d7e4b001a14d3d2d30

WALK_MAN
今天
2
0
《大漠烟尘》读书笔记及读后感文章3700字

《大漠烟尘》读书笔记及读后感文章3700字: 在这个浮躁的社会里,你有多久没有好好读完一本书了? 我们总觉得自己和别人不一样,所以当看到别人身上的问题时,很少有“反求诸己”,反思自己。...

原创小博客
今天
3
0
大数据教程(9.5)用MR实现sql中的jion逻辑

上一篇博客讲解了使用jar -jar的方式来运行提交MR程序,以及通过修改YarnRunner的源码来实现MR的windows开发环境提交到集群的方式。本篇博主将分享sql中常见的join操作。 一、需求 订单数据表...

em_aaron
今天
3
0
十万个为什么之什么是resultful规范

起源 越来越多的人开始意识到,网站即软件,而且是一种新型的软件。这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency)、高并发等特点...

尾生
今天
3
0
Terraform配置文件(Terraform configuration)

Terraform配置文件 翻译自Terraform Configuration Terraform用文本文件来描述设备、设置变量。这些文件被称为Terraform配置文件,以.tf结尾。这一部分将讲述Terraform配置文件的加载与格式。...

buddie
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部