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 ;
}
QQwry.dat格式分析和查詢IP位置的PHP程序
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.