An analysis of _php example of polyp IP library

Source: Internet
Author: User
Tags ord unpack
It's not a novelty, it's already been done a long time ago.
is to use PHP to operate a pure IP library or polyp IP library, based on the IP of the visitors to get the physical location.

I'll post the code first. And then step by step analysis out. Hope to be helpful to the friends who want to know this piece.

Only the code for PHP5. 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 IP address into binary data, packed in big endian (high in front) format
* Data storage format is little endian (low in 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, so the acquired IP data must first be converted to big endian using Strrev
* @param $ip
* @return binary data in 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's pure IP database format detailed

The CoralWry.dat file structure is divided into 3 regions:

    • File header [fixed 8 bytes]
    • Data area [not 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 quote on the difference between little endian and big endian in Unicode encoding

References :

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, or write 49 in front? If 6C is written in front, it is big endian. or write 49 in front, is little endian.

The word "endian" is derived from Gulliver's Travels. The civil war in the small country stems from eating eggs is whether from the Big Head (Big-endian) or from the head (Little-endian) knocked Open, which has happened six times rebellion, one of the Emperor sent life, the other lost the throne.

We generally translate endian into "byte order", the big endian and little endian are called "large tail" and "small tail".

File header:
The red box is the file header, the first 4 bytes is the start address of the index area, and the last 4 bytes is the end address of the index area.

As shown in the following:


Click to enlarge

Since the database is a byte library using the little endian, we need to turn it upside down.
Read the 0-3 bytes of the file header, and then use the unpack function to convert the binary data to the unsigned integer in the big endian format.
After processing, the start address location of the index area 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 find the location of the address: 00077450, which is the beginning of the IP address index area.
As shown in the following:


Click to enlarge

The red box is where the index area begins.

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    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.