Use QQWry. Dat for efficient IP address retrieval

Source: Internet
Author: User
According to the detailed description of the pure IP database format in LumaQQ developer documentation, I have compiled a PHP class for querying IP address region information. During the compilation process, I found that the description of the record area in the explanation of Pure IP database format is not comprehensive, but the description of the record area is not very large, so I [note] this type of efficiency is very high.

1. the constructor in the original class has been converted to PHP5 _ construct, and the destructor has also been replaced.

2. call:

$ Ip = '65. 55.109.119 ';
$ IdADDR = new IpLocation ();
Print_r ($ idADDR-> getlocation ($ ip ));

Returned results:

/* Getlocation ($ ip) returns an ARRAY as follows:
Array
(
[Ip] => 65.55.109.119 // enter the IP address
[Beginip] => 65.52.0.0
[Endip] => 65.55.0000255
[Country] => USA
[Area] => Microsoft
)
*/

According to the detailed description of the pure IP database format in LumaQQ developer documentation, I have compiled a PHP class for querying IP address region information. During the compilation process, we found that the description of the record area in the explanation of the pure IP database format was not comprehensive, but it was not very large, so I didn't need to write a description of the pure IP database format, if you are interested, you can read the following code. The code contains detailed comments, which can be easily understood.

After creating an instance of this class, the instance stores the opened file pointer and some information required for query. you do not need to re-open the file during each query until the execution of the page ends, the opened file will be closed automatically. In this way. When performing multiple queries on a page, the efficiency is very high. In addition, this type can not only directly query IP addresses, but also automatically resolve domain names to IP addresses for query.

The following is the program code:


/**
* IP location query
*
* @ Author Ma Bingyao
* @ Version 1.5
* @ Copyright 2005 CoolCode. CN
*/
Class IpLocation {
/**
* QQWry. Dat file pointer
* @ Var resource
*/
Var $ fp;

/**
* Offset address of the first IP record
* @ Var int
*/
Var $ firstip;

/**
* Offset address of the last IP record
* @ Var int
*/
Var $ lastip;

/**
* Total number of IP records (excluding version Records)
* @ Var int
*/
Var $ totalip;

/**
* Constructor: Open the QQWry. Dat file and initialize information in the class.
* @ Param string $ filename
* @ Return IpLocation
*/
Function _ construct ($ filename = "QQWry. Dat "){
$ This-> fp = 0;
If ($ this-> fp = @ fopen ($ filename, 'RB '))! = False ){
$ This-> firstip = $ this-> getlong ();
$ This-> lastip = $ this-> getlong ();
$ This-> totalip = ($ this-> lastip-$ this-> firstip)/7;
// Register the destructor so that it can be executed at the end of program execution
Register_shutdown_function (array (& $ this, '_ construct '));
}
}

/**
* Returns the number of long integers read.
* @ Access private
* @ Return int
*/
Function getlong (){
// Convert the 4 bytes of the read little-endian encoding to the long integer
$ Result = unpack ('vlong', fread ($ this-> fp, 4 ));
Return $ result ['long'];
}

/**
* Returns the number of long integers read in three bytes.
*
* @ Access private
* @ Return int
*/
Function getlong3 (){
// Convert the three bytes of the read little-endian encoding into a long integer.
$ Result = unpack ('vlong', fread ($ this-> fp, 3). chr (0 ));
Return $ result ['long'];
}

/**
* Return the IP addresses that can be compared after compression.
*
* @ Access private
* @ Param string $ ip
* @ Return string
*/
Function packip ($ ip ){
// Convert the IP address to a long integer. if the IP address is incorrect in PHP5, False is returned,
// At this time, intval converts Flase to an integer-1, and then compresses it into a string encoded by big-endian.
Return pack ('N', intval (ip2long ($ ip )));
}

/**
* Returns the read string.
*
* @ Access private
* @ Param string $ data
* @ Return string
*/
Function getstring ($ data = ""){
$ Char = fread ($ this-> fp, 1 );
While (ord ($ char)> 0) {// string is saved in C format and ended with \ 0
$ Data. = $ char; // after connecting the read characters to the given string
$ Char = fread ($ this-> fp, 1 );
}
Return $ data;
}

/**
* Returned region information
*
* @ Access private
* @ Return string
*/
Function getarea (){
$ Byte = fread ($ this-> fp, 1); // flag byte
Switch (ord ($ byte )){
Case 0: // no region information
$ Area = "";
Break;
Case 1:
Case 2: // indicates that the region information is redirected when the byte is 1 or 2.
Fseek ($ this-> fp, $ this-> getlong3 ());
$ Area = $ this-> getstring ();
Break;
Default: // otherwise, the region information is not redirected.
$ Area = $ this-> getstring ($ byte );
Break;
}
Return $ area;
}

/**
* Return region information based on the given IP address or domain name
* @ Access public
* @ Param string $ ip
* @ Return array
*/
Function getlocation ($ ip ){
If (! $ This-> fp) return null; // if the data file is not properly opened, null is returned directly.
$ Location ['IP'] = gethostbyname ($ ip); // Convert the entered domain name to an ip address
$ Ip = $ this-> packip ($ location ['IP']); // convert the input ip address to a comparable ip address.
// Invalid IP address will be converted to 255.255.255.255
// Split Search
$ L = 0; // bottom boundary of the search
$ U = $ this-> totalip; // The upper boundary of the search
$ Findip = $ this-> lastip; // if not found, the last IP record is returned (QQWry. Dat version information)
While ($ l <= $ u) {// when the boundary is smaller than the bottom boundary, the search fails.
$ I = floor ($ l + $ u)/2); // calculate the approximate intermediate record
Fseek ($ this-> fp, $ this-> firstip + $ I * 7 );
$ Beginip = strrev (fread ($ this-> fp, 4); // Obtain the starting IP address of the intermediate record
// The strrev function is used to convert the compressed IP address of little-endian to the big-endian format.
// Used for comparison.
If ($ ip <$ beginip) {// when the user's IP address is smaller than the starting ip address of the intermediate record
$ U = $ I-1; // change the upper boundary of the search to minus one for the intermediate record
}
Else {
Fseek ($ this-> fp, $ this-> getlong3 ());
$ Endip = strrev (fread ($ this-> fp, 4); // Obtain the end IP address of the intermediate record
If ($ ip> $ endip) {// when the user's IP address is greater than the end ip address of the intermediate record
$ L = $ I + 1; // change the bottom boundary of the search to an intermediate record plus one
}
Else {// when the user's IP address is within the IP address range recorded in the middle
$ Findip = $ this-> firstip + $ I * 7;
Break; // indicates that the result is found and the loop is exited.
}
}
}

// Obtain the IP address location information.
Fseek ($ this-> fp, $ findip );
$ Location ['ininip'] = long2ip ($ this-> getlong (); // start address of the user's IP address range
$ Offset = $ this-> getlong3 ();
Fseek ($ this-> fp, $ offset );
$ Location ['enabled'] = long2ip ($ this-> getlong (); // end address of the user's IP address range
$ Byte = fread ($ this-> fp, 1); // flag byte
Switch (ord ($ byte )){
Case 1: // The flag byte is 1, indicating that both the country and region information are redirected at the same time.
$ CountryOffset = $ this-> getlong3 (); // redirect address
Fseek ($ this-> fp, $ countryOffset );
$ Byte = fread ($ this-> fp, 1); // flag byte
Switch (ord ($ byte )){
Case 2: // The flag byte is 2, indicating that the country information is redirected.
Fseek ($ this-> fp, $ this-> getlong3 ());
$ Location ['country'] = $ this-> getstring ();
Fseek ($ this-> fp, $ countryOffset + 4 );
$ Location ['region'] = $ this-> getarea ();
Break;
Default: // otherwise, the country information is not redirected.
$ Location ['country'] = $ this-> getstring ($ byte );
$ Location ['region'] = $ this-> getarea ();
Break;
}
Break;
Case 2: // The flag byte is 2, indicating that the country information is redirected.
Fseek ($ this-> fp, $ this-> getlong3 ());
$ Location ['country'] = $ this-> getstring ();
Fseek ($ this-> fp, $ offset + 8 );
$ Location ['region'] = $ this-> getarea ();
Break;
Default: // otherwise, the country information is not redirected.
$ Location ['country'] = $ this-> getstring ($ byte );
$ Location ['region'] = $ this-> getarea ();
Break;
}
If ($ location ['country'] = "CZ88.NET") {// CZ88.NET indicates no valid information
$ Location ['country'] = "unknown ";
}
If ($ location ['region'] = "CZ88.NET "){
$ Location ['region'] = "";
}
Return $ location;
}

/**
* Destructor used to automatically close opened files after Page execution.
*
*/
Function _ desctruct (){
If ($ this-> fp ){
Fclose ($ this-> fp );
}
$ This-> fp = 0;
}
}
?>
Related Article

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.