天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

珊瑚蟲IP庫淺析

這不是什么新鮮事情了,很早之前就已經有人做出來了。
就是使用php操作純真IP庫或珊瑚蟲IP庫,根據來訪者的IP得到所在的物理位置。

我先帖出代碼。然后再慢慢一步步淺析出來。希望對想了解這一塊的朋友們有幫助。

Only For php5的代碼。會繼續優化代碼的。

class IpLocation{
    private $fp;
    private $wrydat;
    private $wrydat_version;
    private $ipnumber;
    private $firstip;
    private $lastip;
    private $ip_range_begin;
    private $ip_range_end;
    private $country;
    private $area;
    const REDIRECT_MODE_0 = 0;
    const REDIRECT_MODE_1 = 1;
    const REDIRECT_MODE_2 = 2;
    function __construct(){
        $args = func_get_args();
        $this->wrydat = func_num_args()>0?$args[0]:'CoralWry.dat';
        $this->initialize();
    }
    function __destruct(){
        fclose($this->fp);
    }
    private function initialize(){
        if(file_exists($this->wrydat))
            $this->fp = fopen($this->wrydat,'rb');
        $this->getipnumber();
        $this->getwryversion();
    }
    public function get($str){
        return $this->$str;
    }
    public function set($str,$val){
        $this->$str = $val;
    }
    private function getbyte($length,$offset=null){
        if(!is_null($offset)){
            fseek($this->fp,$offset,SEEK_SET);
        }
        $b = fread($this->fp,$length);
        return $b;
    }
/**
* 把IP地址打包成二進制數據,以big endian(高位在前)格式打包
* 數據存儲格式為 little endian(低位在前) 如:
* 00 28 C6 DA    218.198.40.0    little endian
* 3F 28 C6 DA    218.198.40.0    little endian
* 這樣的數據無法作二分搜索查找的比較,所以必須先把獲得的IP數據使用strrev轉換為big endian
* @param $ip
* @return big endian格式的二進制數據
*/
    private function packip($ip){
        return pack( "N", intval( ip2long( $ip)));
    }

    private function getlong($length=4, $offset=null){
        $chr=null;
        for($c=0;$length%4!=0&&$c<(4-$length%4);$c++){
            $chr .= chr(0);
        }
        $var = unpack( "Vlong", $this->getbyte($length, $offset).$chr);
        return $var['long'];
    }

    private function getwryversion(){
        $length = preg_match("/coral/i",$this->wrydat)?26:30;
        $this->wrydat_version = $this->getbyte($length, $this->firstip-$length);
    }

    private function getipnumber(){
        $this->firstip = $this->getlong();
        $this->lastip = $this->getlong();
        $this->ipnumber = ($this->lastip-$this->firstip)/7+1;
    }

    private function getstring($data="",$offset=null){
        $char = $this->getbyte(1,$offset);
        while(ord($char) > 0){
            $data .= $char;
            $char = $this->getbyte(1);
        }
        return $data;
    }

    private function iplocaltion($ip){
        $ip = $this->packip($ip);
        $low = 0;
        $high = $this->ipnumber-1;
        $ipposition = $this->lastip;
        while($low <= $high){
            $t = floor(($low+$high)/2);
            if($ip < strrev($this->getbyte(4,$this->firstip+$t*7))){
                $high = $t - 1;
            } else {
                if($ip > strrev($this->getbyte(4,$this->getlong(3)))){
                    $low = $t + 1;
                }else{
                    $ipposition = $this->firstip+$t*7;
                    break;
                }
            }
        }
        return $ipposition;
    }
    private function getarea(){
        $b = $this->getbyte(1);
        switch(ord($b)){
            case self::REDIRECT_MODE_0 :
                return "未知";
                break;
            case self::REDIRECT_MODE_1:
            case self::REDIRECT_MODE_2:
                return $this->getstring("",$this->getlong(3));
                break;
            default:
                return $this->getstring($b);
                break;
        }
    }
    public function getiplocation($ip){
        $ippos = $this->iplocaltion($ip);
        $this->ip_range_begin = long2ip($this->getlong(4,$ippos));
        $this->ip_range_end = long2ip($this->getlong(4,$this->getlong(3)));
        $b = $this->getbyte(1);
        switch (ord($b)){
            case self::REDIRECT_MODE_1:
                $b = $this->getbyte(1,$this->getlong(3));
                if(ord($b) == REDIRECT_MODE_2){
                    $countryoffset = $this->getlong(3);
                    $this->area = $this->getarea();
                    $this->country = $this->getstring("",$countryoffset);
                }else{
                    $this->country = $this->getstring($b);
                    $this->area    = $this->getarea();
                }
                break;

            case self::REDIRECT_MODE_2:
                    $countryoffset = $this->getlong(3);
                    $this->area = $this->getarea();
                    $this->country = $this->getstring("",$countryoffset);
                break;

            default:
                $this->country = $this->getstring($b);
                $this->area    = $this->getarea();
                break;
        }
    }
}
/* */
echo microtime();
echo "/n";
$iploca = new IpLocation;
//$iploca = new IpLocation('QQWry.dat');
echo $iploca->get('wrydat_version');
echo "/n";
echo $iploca->get('ipnumber');
echo "/n";
$iploca->getiplocation('211.44.32.34');
/**/
echo $iploca->get('ip_range_begin');
echo "/n";
echo $iploca->get('ip_range_end');
echo "/n";
echo $iploca->get('country');
echo "/n";
echo $iploca->get('area');

echo "/n";
echo $iploca->get('lastip');
echo "/n";
echo microtime();
echo "/n";
unset($iploca);

參考資料:LumaQQ的 純真IP數據庫格式詳解

CoralWry.dat文件結構上分為3個區域:

  • 文件頭[固定8個字節]
  • 數據區[不固定長度,記錄IP的地址信息]
  • 索引區[大小由文件頭決定]

該文件數據的存儲方式是:little endian。
在這里引用了談談Unicode編碼里的關于little endian 與 big endian的區別

引用

big endian和little endian是CPU處理多字節數的不同方式。例如“漢”字的Unicode編碼是6C49。那么寫到文件里時,究竟是將6C寫在前面,還是將49寫在前面?如果將6C寫在前面,就是big endian。還是將49寫在前面,就是little endian。

  “endian”這個詞出自《格列佛游記》。小人國的內戰就源于吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開,由此曾發生過六次叛亂,其中一個皇帝送了命,另一個丟了王位。

  我們一般將endian翻譯成“字節序”,將big endian和little endian稱作“大尾”和“小尾”。

文件頭:
紅色框框里的就是文件頭,前4個字節是索引區的開始地址,后4個字節是索引區的結束地址。

如下圖所示:


點擊放大

由于數據庫是使用了little endian的字節庫,所以我們需要把它倒過來。
把文件頭的0-3的字節讀取出來,再使用 unpack 函數把二進制數據轉換為big endian格式的無符號整型。
處理后,索引區的開始地址位置是:00077450 ;索引區的結束地址位置是:000CE17C。
如果你手頭上有UltraEdit的軟件,可以打開CoralWry.dat文件,查找地址為:00077450 的位置,那就是IP地址索引區的開始。
如下圖所示:


點擊放大

紅色框框住那就是索引區的開始位置。

php技術珊瑚蟲IP庫淺析,轉載需保留來源!

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

主站蜘蛛池模板: s8sp视频高清在线播放 | 求个av网站 | 7m凹凸国产刺激在线视频 | 韩国黄色影院 | 亚洲一区国产 | 男人和女人全黄一级毛片 | 男女啪啪抽搐呻吟高潮动态图 | 日本69色视频在线观看 | 精品手机在线1卡二卡3卡四卡 | 婷婷射精AV这里只有精品 | 久久青青草原精品国产软件 | 人妻少妇偷人精品无码洋洋AV | 狼人大香伊蕉国产WWW亚洲 | 国产免费不卡 | 99久免费精品视频在线观看2 | 午夜国产羞羞视频免费网站 | 久久久久久久久女黄9999 | 老湿影院色情a | 4虎影院午夜在线观看 | 4k岛国精品午夜高清在线观看 | 毛片内射久久久一区 | 亚洲 欧美 另类 中文 在线 | 久久综合久综合久久鬼色 | 亚洲欧美国产双大乳头 | 色多多污版app下载网站 | 99热这里只有的精品 | 国产成人精品免费青青草原app | 性色爽爱性色爽爱网站 | 午夜影院视费x看 | 收集最新中文国产中文字幕 | 秀婷程仪公欲息肉婷在线观看 | 欧美白人战黑吊 | 国产精品高清在线观看地址 | 两性午夜刺激爽爽视频 | 日本视频中文字幕一区二区 | 久草在线精彩免费视频 | 妈妈的朋友5在线观看免费完整版中文 | 少女free大陆 | 擼擼擼麻豆密臀AV | 亚洲AV午夜福利精品香蕉麻豆 | 二级特黄绝大片免费视频大片 |