QQWRY.DAT format analysis and query PHP programs for IP location
By strongc http://strongc.51.net/d2x/
Don't remove my name and my homepage when reprint, thank you!
The previous pursuit database is too big, and it has not been updated for a long time.
So I think of using qqwry.dat this file query IP location, QQWRy.dat can be found in many places, generally see the QQ compression package of the IP address.
But there is no relevant format information.
I analyzed the format of this file, and the following conclusions are hereby conclusions:
The format is as follows:
A. File head, a total of 8 bytes
B. End address of several records country and region
C. Several start address end address offset, fixed length, 7 bytes of start addresses from small to large arrangements
D. All IPs are recorded with 4 bytes integers and follow the intel order, the high is behind, the low position is before.
E. All offsets are absolutely offset, which is calculated from the beginning of the file.
F. In addition to the file header uses two 4-byte offset, the remaining offsets are 3 bytes.
G. All offsets are also low in front, high behind
H. Some string compression technology
1. File head, a total of 8 bytes
FirstStartipoffset: 4 absolute offset of the first start IP
LastStartipoffset: 4 absolute offset of the last start IP
2. Start Address End Address Offset Recorder
Each record is recorded, according to the start address from small to large
Startip: 4 start address, integer form of IP
Endipoffset: 3 End Address absolute offset
3. End Address Country Region Record Area
ENDIP: 4
Country Region Record: Unordered
4. Country regional record, there are several forms
4.1.
Country string, end with 0x0
Regional string, end with 0x0
4.2.
FLAG: 1 Identification value: 0x1, there is no local record
0x2, there is also a local record
ScountryOffset: 3 The actual string should go to this offset location to find
LocalRec: Not set, optional according to the value of FLAG. This record is similar to Country, which may be compressed
4.3 LocalRec structure
Flag: 1 is not very understanding this Flag meaning, value 0x1 or 0x2
SlocalOffset: 3
4.4 LocalRec structure
SLOCAL: Unordered long C-style string
Note: The location of ScountryOffset points may still be 4.2 format, do not know why this is designed.
When Flag takes 0x1, the position of ScountryOffset points to the FLAG is 0x2. At this time, LocalRec is also looking for.
I don't understand what is the logo of 0x2 when the location of the record.
In qqwry.dat, there seems to have some errors.
Individual records Local will be written as:
0x2,0x0,0x0,0x0
According to the rules, you should go to the file to find the most, but the most out of the file is clearly not recorded.
I learned PHP soon, you don't want to laugh, you have to improve it, remember to give me a copy.
I will refer to some online found code, I will not write it.
To be old truth, I have a headache PHP that I can't clearly specify the type of variable.
For example, I want some number to be unsigned shaping, it is very unbursed, I have to take a negative, I have to try all possible ways ........
How do you deal with similar things?
Define ('qqwry', $ qwry_root_path. 'QQWRY.DAT'); Function Iptoint ($ IP) {
$ array = expedition ('.', $ 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; // Identify Country Location
// 0x01, then 3 bytes of country shift, no local
// 0x02, then 3 bytes of country shift, then Local
// Others, Country, Local, Local have similar compression. Maybe multiple references.
VAR $ fp;
Var $ firststostartip = 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) ($ 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) ($ 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-> firststostartip = ORD ($ BUF [0]) (ord ($ BUF [1]) * 256) ($ BUF [2]) * 256 * 256) (ORD ($ BUF [3 ]) * 256 * 256 * 256); $ this-> laststartip = ORD ($ BUF [4]) (ORD ($ BUF [5]) * 256) ($ BUF [6]) * 256 * 256) (ORD ($ BUF [7]) * 256 * 256 * 256);
$ RecordCount = Floor ($ this-> Laststartip - $ this-> firststartip) / 7);
IF ($ RecordCount <= 1) {
$ this-> country = "fasdatarror";
Fclose ($ THIS-> FP);
Return 2;
}
$ RANGB = 0;
$ RANGE = $ RecordCount;
// match ...
While ($ RANGB <$ RANGE-1)
{
$ Recno = floor ($ RANGB $ RANGE) / 2);
$ this-> getStartip ($ Recno);
IF ($ i == $ this-> start)
{
$ Rangb = $ Recno;
Break;
}
IF ($ IP> $ THIS-> STARTIP)
$ Rangb = $ Recno;
Else
$ RANGE = $ Recno;
}
$ this-> getStartip ($ RANGB);
$ this-> getendip ();
IF ($ this-> startip <= $ p) && ($ this-> endip> = $ ip)) {
$ nret = 0;
$ this-> getCountry ();
// This is not very good ............ So ..........
$ this-> local = str_replace ("(we must liberate Taiwan !!!)", "", $ this-> local);
} else {
$ nret = 3;
$ this-> country = 'unknown';
$ this-> local = '';
}
Fclose ($ THIS-> FP);
Return $ nret;
}
}
Function IP2Location ($ IP)
{
$ wry = new tqqwry;
$ nret = $ wry-> QQWRY ($ IP);
// You can use $ nret to do something, I let him automatically record the IP to a table, the code is not written.
Return $ WRY-> Country. $ wry-> local;
}