It's not a novelty, it's already been done by someone early on.
is to use PHP to operate the pure IP library or coral IP library, according to the caller's IP to get the physical location.
I'll post the code first. And then step by step to analyze it slowly. Hope to be helpful to the friends who want to know this piece.
Only for PHP5 code. will continue to optimize the code.
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;
}
/**
* Package the IP address into binary data and pack it in the big endian (high front) format
* Data storage format is little endian (low front) such as:
* C6 DA 218.198.40.0 Little Endian
* 3F C6 DA 218.198.40.0 Little Endian
* Such data cannot be compared for binary search lookups, so the IP data obtained must first be converted to big endian using Strrev.
* @param $ip
* @return The binary data in the big endian format
*/
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 "Unknown";
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);
Reference: Lumaqq of pure IP database format detailed
The CoralWry.dat file structure is divided into 3 regions:
- File header [fixed 8 bytes]
- Data area [fixed length, record IP address information]
- Index area [size determined by file header]
The file data is stored in the following way: Little endian.
Here's a reference to the difference between little endian and big endian in Unicode coding
Reference :
The big endian and little endian are different ways the CPU handles multibyte numbers. For example, the Unicode encoding of the word "Han" is 6c49. So when you write to a file, do you write 6C in front of it or write 49 in front? If you write 6C in front, it's big endian. Or the 49 written in front, is little endian.
The word "endian" is derived from Gulliver's Travels. Lilliput's civil war stems from eating eggs from the big Head (Big-endian) knock Open or from the beginning (Little-endian) knock Open, which has occurred six times, one of the Emperor gave life, the other lost the throne.
We generally translate endian into "byte order", the big endian and little endian called "large tail" and "small tail".
File header:
The red box is the file header, the first 4 bytes are the starting address of the index area, and the last 4 bytes are the ending address of the index area.
As shown in the following illustration:
Click to enlarge
Since the database is using the little endian byte library, we need to turn it upside down.
Read the 0-3 bytes of the file header and use the unpack function to convert the binary data to the unsigned integral type in the big endian format.
After processing, the index area's start address position is: 00077450; the end address location of the index area is: 000ce17c.
If you have ultraedit software on hand, you can open the CoralWry.dat file and look for the location of the address: 00077450, which is the beginning of the IP address index area.
As shown in the following illustration:
Click to enlarge
The red box is where the index area begins.