QQwry.dat格式分析和查詢IP位置的PHP程式

來源:互聯網
上載者:User
程式 QQwry.dat格式分析和查詢IP位置的PHP程式

By Strongc http://strongc.51.net/d2x/
轉載時不要去掉我的名字和我的首頁連結,謝謝!

以前的追捕資料庫太大,而且很久沒有更新了。
所以我想到利用QQwry.dat這個檔案查詢IP所在位置,QQwry.dat 在很多地方都能找到,一般看IP地址的QQ壓縮包中都有。

但是沒有任何相關格式資料。

我分析了這個檔案的格式,目前如下結論:

格式如下:

A。檔案頭,共8位元組
B。若干條記錄的結束位址+國家和地區
C。按照從小到大排列的若干條起始地址+結束位址位移,定長,7位元組
D。所有的IP都是用4位元組整數記錄的,並且遵照Intel次序,高位在後,低位在前。
E。所有位移量都是絕對位移,就是從檔案最開頭計算。
F。除了檔案頭用了兩個4位元組位移,其餘位移量都用3位元組。
G。所有的位移量也是低位在前,高位在後
H。採用了一些字串壓縮技術

1。檔案頭,共8位元組
FirstStartIpOffset:4 第一個起始IP的絕對位移
LastStartIpOffset:4 最後一個起始IP的絕對位移

2。起始地址+結束位址位移記錄區
每條記錄7位元組,按照起始地址從小到大排列

StartIp:4 起始地址,整數形式的IP
EndIpOffset:3 結束位址絕對位移

3。結束位址+國家+地區記錄區

EndIP:4
國家+地區記錄:不定長

4。國家+地區記錄,有幾種形式
4.1。
國家字串,以 0x0 結束
地區字串,以 0x0 結束

4.2。
Flag:1 標識取值: 0x1,後面沒有Local記錄
0x2,後面還有Local記錄
sCountryOffset:3 實際的字串要去這個位移位置去找
LocalRec:不定長,可選 根據Flag取值而定。這個記錄也類似Country,可能採用壓縮

4.3 LocalRec結構一
flag:1 還不是十分瞭解這個flag含義,取值 0x1 or 0x2
sLocalOffset:3

4.4 LocalRec結構二
sLocal:不定長 普通的C風格字串

注意:sCountryOffset指向的位置可能依然是4.2格式的,不知道為什麼這樣設計。


Flag取0x1時,sCountryOffset指向的位置可能是Flag為0x2,這時,LocalRec也在這裡尋找。

現在不明白當記錄Local的位置遇到0x2的標誌意味著什麼。

在qqwry.dat中,似乎存在一些錯誤。
個別的記錄Local會被寫為:
0x2,0x0,0x0,0x0
根據規則,應該到檔案最開頭去尋找,可是,檔案最開頭顯然不是記錄這些的。

我才學PHP不久,各位不要笑,你要能改進當然好,記得給我一份。
我參考了一些網上找到的代碼,就不一一寫出出處了。

說老實話,我很頭疼PHP無法明確指定變數的類型。
比如,我想讓某個數是無符號的整形,它很不聽話,非要是帶個負號,我只好嘗試各種可能的寫法..........
各位都是怎麼處理類似的事情?




define('QQWRY' , $qqwry_root_path . 'QQwry.dat' ) ;

function IpToInt($Ip) {
    $array=explode('.',$Ip);
    $Int=($array[0] * 256*256*256) + ($array[1]*256*256) + ($array[2]*256) + $array[3];
    return $Int;
}

function IntToIp($Int) {
    $b1=($Int & 0xff000000)>>24;
    if ($b1<0) $b1+=0x100;
    $b2=($Int & 0x00ff0000)>>16;
    if ($b2<0) $b2+=0x100;
    $b3=($Int & 0x0000ff00)>>8;
    if ($b3<0) $b3+=0x100;
    $b4= $Int & 0x000000ff;
    if ($b4<0) $b4+=0x100;
    $Ip=$b1.'.'.$b2.'.'.$b3.'.'.$b4;
    return $Ip;
}


class TQQwry
{
    var $StartIP = 0;
    var $EndIP   = 0;
    var $Country = '';
    var $Local   = '';

    var $CountryFlag = 0; // 標識 Country位置
                          // 0x01,隨後3位元組為Country位移,沒有Local
                          // 0x02,隨後3位元組為Country位移,接著是Local
                          // 其他,Country,Local,Local有類似的壓縮。可能多重引用。
    var $fp;

    var $FirstStartIp = 0;
    var $LastStartIp = 0;
    var $EndIpOff = 0 ;

    function getStartIp ( $RecNo ) {
        $offset = $this->FirstStartIp + $RecNo * 7 ;
        @fseek ( $this->fp , $offset , SEEK_SET ) ;
        $buf = fread ( $this->fp , 7 ) ;
        $this->EndIpOff = ord($buf[4]) + (ord($buf[5])*256) + (ord($buf[6])* 256*256);
        $this->StartIp = ord($buf[0]) + (ord($buf[1])*256) + (ord($buf[2])*256*256) + (ord($buf[3])*256*256*256);
        return $this->StartIp ;
    }

    function getEndIp ( ) {
        @fseek ( $this->fp , $this->EndIpOff , SEEK_SET ) ;
        $buf = fread ( $this->fp , 5 ) ;
        $this->EndIp = ord($buf[0]) + (ord($buf[1])*256) + (ord($buf[2])*256*256) + (ord($buf[3])*256*256*256);
        $this->CountryFlag = ord ( $buf[4] ) ;
        return $this->EndIp ;
    }

    function getCountry ( ) {

        switch ( $this->CountryFlag ) {
            case 1:
            case 2:
                $this->Country = $this->getFlagStr ( $this->EndIpOff+4) ;
                //echo sprintf('EndIpOffset=(%x)',$this->EndIpOff );
                $this->Local = ( 1 == $this->CountryFlag )? '' : $this->getFlagStr ( $this->EndIpOff+8);
                break ;
            default :
                $this->Country = $this->getFlagStr ($this->EndIpOff+4) ;
                $this->Local =   $this->getFlagStr ( ftell ( $this->fp )) ;

        }
    }


    function getFlagStr ( $offset )
    {

        $flag = 0 ;
        while ( 1 ){
            @fseek ( $this->fp , $offset , SEEK_SET ) ;
            $flag = ord ( fgetc ( $this->fp ) ) ;
            if ( $flag == 1 || $flag == 2 ) {
                $buf = fread ($this->fp , 3 ) ;
                if ($flag == 2 ){
                    $this->CountryFlag = 2 ;
                    $this->EndIpOff = $offset - 4 ;
                }
                $offset = ord($buf[0]) + (ord($buf[1])*256) + (ord($buf[2])* 256*256);
            }else{
                break ;
            }

        }
        if ( $offset < 12 )
            return '';
        @fseek($this->fp , $offset , SEEK_SET ) ;
        return $this->getStr();
    }
    function getStr ( )
    {
        $str = '' ;
        while ( 1 ) {
            $c = fgetc ( $this->fp ) ;
            if ( ord ( $c[0] ) == 0  )
               break ;
            $str .= $c ;
        }
        return $str ;
    }


    function qqwry ($dotip) {

        $nRet;
        $ip = IpToInt ( $dotip );

        $this->fp= @fopen(QQWRY, "rb");
        if ($this->fp == NULL) {
              $szLocal= "OpenFileError";
            return 1;

          }
          @fseek ( $this->fp , 0 , SEEK_SET ) ;
        $buf = fread ( $this->fp , 8 ) ;
        $this->FirstStartIp = ord($buf[0]) + (ord($buf[1])*256) + (ord($buf[2])*256*256) + (ord($buf[3])*256*256*256);
        $this->LastStartIp  = ord($buf[4]) + (ord($buf[5])*256) + (ord($buf[6])*256*256) + (ord($buf[7])*256*256*256);

        $RecordCount= floor( ( $this->LastStartIp - $this->FirstStartIp ) / 7);
        if ($RecordCount <= 1){
            $this->Country = "FileDataError";
            fclose ( $this->fp ) ;
            return 2 ;
        }

          $RangB= 0;
        $RangE= $RecordCount;
        // Match ...
        while ($RangB < $RangE-1)
        {
          $RecNo= floor(($RangB + $RangE) / 2);
          $this->getStartIp ( $RecNo ) ;

            if ( $ip == $this->StartIp )
            {
                $RangB = $RecNo ;
                break ;
            }
          if ( $ip > $this->StartIp)
            $RangB= $RecNo;
          else
            $RangE= $RecNo;
        }
        $this->getStartIp ( $RangB ) ;
        $this->getEndIp ( ) ;

        if ( ( $this->StartIp  <= $ip ) && ( $this->EndIp >= $ip ) ){
            $nRet = 0 ;
            $this->getCountry ( ) ;
            //這樣不太好..............所以..........
            $this->Local = str_replace("(我們一定要解放台灣!!!)", "", $this->Local);

        }else {
            $nRet = 3 ;
            $this->Country = '未知' ;
            $this->Local = '' ;
        }
        fclose ( $this->fp ) ;
        return $nRet ;
    }
}


function ip2location ( $ip )
{
    $wry = new TQQwry ;
    $nRet = $wry->qqwry ( $ip );
    //可以利用 $nRet做一些事情,我是讓他自動記錄未知IP到一個表,代碼就不寫了。
  return $wry->Country.$wry->Local ;
}




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.