日期:2013-11-23  浏览次数:20543 次

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 = fr