http://blog.csdn.net/clin003/archive/2007/08/14/1743157.aspx
利用 QQWry.Dat 实现 IP 地址高效检索(PHP)
根据 LumaQQ 开发者文档中的纯真 IP 数据库格式详解,我编写了一个 PHP 的查询
IP 所在地区信息的类。在编写过程中发现纯真 IP 数据库格式详解中关于记录区的描述不是很全面,不过出入也不是很大,所以我没必要再写一份纯真 IP
数据库的格式说明了,大家感兴趣的话,读一读下面的代码应该就能看出来了。代码中加了很详细的注释,应该很容易读懂的。
在创建这个类的一个实例后,实例中就保存了打开的文件指针和一些查询需要的信息,每次查询时不需要重新打开文件,直到页面执行结束后,打开的文件才会自动关闭。这样。在一个页面内进行多次查询时,效率是很高的。并且此类不仅可以直接查询
IP,还可以自动将域名解析为 IP 进行查询。
下面是程序代码:
- <?php
- class IpLocation {
-
- var $fp;
-
-
- var $firstip;
-
-
- var $lastip;
-
-
- var $totalip;
-
-
- function getlong() {
-
- $result = unpack(‘Vlong‘, fread($this->fp, 4));
- return $result[‘long‘];
- }
-
-
- function getlong3() {
-
- $result = unpack(‘Vlong‘, fread($this->fp, 3).chr(0));
- return $result[‘long‘];
- }
-
-
- function packip($ip) {
-
-
- return pack(‘N‘, intval(ip2long($ip)));
- }
-
-
- function getstring($data = "") {
- $char = fread($this->fp, 1);
- while (ord($char) > 0) {
- $data .= $char;
- $char = fread($this->fp, 1);
- }
- return $data;
- }
-
-
- function getarea() {
- $byte = fread($this->fp, 1);
- switch (ord($byte)) {
- case 0:
- $area = "";
- break;
- case 1:
- case 2:
- fseek($this->fp, $this->getlong3());
- $area = $this->getstring();
- break;
- default:
- $area = $this->getstring($byte);
- break;
- }
- return $area;
- }
-
-
- function getlocation($ip) {
- if (!$this->fp) return null;
- $location[‘ip‘] = gethostbyname($ip);
- $ip = $this->packip($location[‘ip‘]);
-
-
- $l = 0;
- $u = $this->totalip;
- $findip = $this->lastip;
- while ($l <= $u) {
- $i = floor(($l + $u) / 2);
- fseek($this->fp, $this->firstip + $i * 7);
- $beginip = strrev(fread($this->fp, 4));
-
-
- if ($ip < $beginip) {
- $u = $i - 1;
- }
- else {
- fseek($this->fp, $this->getlong3());
- $endip = strrev(fread($this->fp, 4));
- if ($ip > $endip) {
- $l = $i + 1;
- }
- else {
- $findip = $this->firstip + $i * 7;
- break;
- }
- }
- }
-
-
- fseek($this->fp, $findip);
- $location[‘beginip‘] = long2ip($this->getlong());
- $offset = $this->getlong3();
- fseek($this->fp, $offset);
- $location[‘endip‘] = long2ip($this->getlong());
- $byte = fread($this->fp, 1);
- switch (ord($byte)) {
- case 1:
- $countryOffset = $this->getlong3();
- fseek($this->fp, $countryOffset);
- $byte = fread($this->fp, 1);
- switch (ord($byte)) {
- case 2:
- fseek($this->fp, $this->getlong3());
- $location[‘country‘] = $this->getstring();
- fseek($this->fp, $countryOffset + 4);
- $location[‘area‘] = $this->getarea();
- break;
- default:
- $location[‘country‘] = $this->getstring($byte);
- $location[‘area‘] = $this->getarea();
- break;
- }
- break;
- case 2:
- fseek($this->fp, $this->getlong3());
- $location[‘country‘] = $this->getstring();
- fseek($this->fp, $offset + 8);
- $location[‘area‘] = $this->getarea();
- break;
- default:
- $location[‘country‘] = $this->getstring($byte);
- $location[‘area‘] = $this->getarea();
- break;
- }
- if ($location[‘country‘] == " CZ88.NET") {
- $location[‘country‘] = "未知";
- }
- if ($location[‘area‘] == " CZ88.NET") {
- $location[‘area‘] = "";
- }
- return $location;
- }
-
-
- function IpLocation($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_shutdown_function(array(&$this, ‘_IpLocation‘));
- }
- }
-
-
- function _IpLocation() {
- if ($this->fp) {
- fclose($this->fp);
- }
- $this->fp = 0;
- }
- }
- ?>
- Discuz 5.0 不在使用自己的IP数据,而是使用纯真IP的数据格式, 存取纯真IP数据库稍微有点麻烦,它的存储格式比较特殊也很有趣,具体的格式分析参考下面两个链接,其他语言实现参考文章末的链接。
-
- 《纯真IP数据库格式详解》
- 链接一:http:
- 链接二:http:
-
- 纯真IP数据库官网:http:
- 纯真IP数据库下载:http:
-
-
-
- 以下函数conrvertip()位于 Discuz!5_GBK/upload/include/misc.func.Php 路径中,有兴趣可以具体去阅读分析。(下面代码我做了简单的修改,更便于阅读,核心没有修改)
-
-
- <?
- function convertip($ip) {
-
- $dat_path = ‘QQWry.Dat‘;
-
-
- if(!preg_match("/^d{1,3}.d{1,3}.d{1,3}.d{1,3}$/", $ip)) {
- return ‘IP Address Error‘;
- }
-
- if(!$fd = @fopen($dat_path, ‘rb‘)){
- return ‘IP date file not exists or access denied‘;
- }
-
-
- $ip = explode(‘.‘, $ip);
- $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];
-
-
- $DataBegin = fread($fd, 4);
- $DataEnd = fread($fd, 4);
- $ipbegin = implode(‘‘, unpack(‘L‘, $DataBegin));
- if($ipbegin < 0) $ipbegin += pow(2, 32);
- $ipend = implode(‘‘, unpack(‘L‘, $DataEnd));
- if($ipend < 0) $ipend += pow(2, 32);
- $ipAllNum = ($ipend - $ipbegin) / 7 + 1;
-
- $BeginNum = 0;
- $EndNum = $ipAllNum;
-
-
- while($ip1num>$ipNum || $ip2num<$ipNum) {
- $Middle= intval(($EndNum + $BeginNum) / 2);
-
-
- fseek($fd, $ipbegin + 7 * $Middle);
- $ipData1 = fread($fd, 4);
- if(strlen($ipData1) < 4) {
- fclose($fd);
- return ‘System Error‘;
- }
-
- $ip1num = implode(‘‘, unpack(‘L‘, $ipData1));
- if($ip1num < 0) $ip1num += pow(2, 32);
-
-
- if($ip1num > $ipNum) {
- $EndNum = $Middle;
- continue;
- }
-
-
- $DataSeek = fread($fd, 3);
- if(strlen($DataSeek) < 3) {
- fclose($fd);
- return ‘System Error‘;
- }
- $DataSeek = implode(‘‘, unpack(‘L‘, $DataSeek.chr(0)));
- fseek($fd, $DataSeek);
- $ipData2 = fread($fd, 4);
- if(strlen($ipData2) < 4) {
- fclose($fd);
- return ‘System Error‘;
- }
- $ip2num = implode(‘‘, unpack(‘L‘, $ipData2));
- if($ip2num < 0) $ip2num += pow(2, 32);
-
-
- if($ip2num < $ipNum) {
- if($Middle == $BeginNum) {
- fclose($fd);
- return ‘Unknown‘;
- }
- $BeginNum = $Middle;
- }
- }
-
-
- $ipFlag = fread($fd, 1);
- if($ipFlag == chr(1)) {
- $ipSeek = fread($fd, 3);
- if(strlen($ipSeek) < 3) {
- fclose($fd);
- return ‘System Error‘;
- }
- $ipSeek = implode(‘‘, unpack(‘L‘, $ipSeek.chr(0)));
- fseek($fd, $ipSeek);
- $ipFlag = fread($fd, 1);
- }
-
- if($ipFlag == chr(2)) {
- $AddrSeek = fread($fd, 3);
- if(strlen($AddrSeek) < 3) {
- fclose($fd);
- return ‘System Error‘;
- }
- $ipFlag = fread($fd, 1);
- if($ipFlag == chr(2)) {
- $AddrSeek2 = fread($fd, 3);
- if(strlen($AddrSeek2) < 3) {
- fclose($fd);
- return ‘System Error‘;
- }
- $AddrSeek2 = implode(‘‘, unpack(‘L‘, $AddrSeek2.chr(0)));
- fseek($fd, $AddrSeek2);
- } else {
- fseek($fd, -1, SEEK_CUR);
- }
-
- while(($char = fread($fd, 1)) != chr(0))
- $ipAddr2 .= $char;
-
- $AddrSeek = implode(‘‘, unpack(‘L‘, $AddrSeek.chr(0)));
- fseek($fd, $AddrSeek);
-
- while(($char = fread($fd, 1)) != chr(0))
- $ipAddr1 .= $char;
- } else {
- fseek($fd, -1, SEEK_CUR);
- while(($char = fread($fd, 1)) != chr(0))
- $ipAddr1 .= $char;
-
- $ipFlag = fread($fd, 1);
- if($ipFlag == chr(2)) {
- $AddrSeek2 = fread($fd, 3);
- if(strlen($AddrSeek2) < 3) {
- fclose($fd);
- return ‘System Error‘;
- }
- $AddrSeek2 = implode(‘‘, unpack(‘L‘, $AddrSeek2.chr(0)));
- fseek($fd, $AddrSeek2);
- } else {
- fseek($fd, -1, SEEK_CUR);
- }
- while(($char = fread($fd, 1)) != chr(0)){
- $ipAddr2 .= $char;
- }
- }
- fclose($fd);
-
-
- if(preg_match(‘/http/i‘, $ipAddr2)) {
- $ipAddr2 = ‘‘;
- }
- $ipaddr = "$ipAddr1 $ipAddr2";
- $ipaddr = preg_replace(‘/CZ88.Net/is‘, ‘‘, $ipaddr);
- $ipaddr = preg_replace(‘/^s*/is‘, ‘‘, $ipaddr);
- $ipaddr = preg_replace(‘/s*$/is‘, ‘‘, $ipaddr);
- if(preg_match(‘/http/i‘, $ipaddr) || $ipaddr == ‘‘) {
- $ipaddr = ‘Unknown‘;
- }
-
- return $ipaddr;
- }
-
-
-
- echo convertip(‘219.238.235.10‘);
-
- echo convertip(‘23.56.82.12‘);
-
- echo convertip(‘250.69.52.0‘);
-
- echo convertip(‘238.69.52.0‘);
-
- echo convertip(‘192.168.0.1‘);
-
- echo convertip(‘255.255.255.255‘);
-
- ?>
附:(相应其他实现程序)
Php)
"
href=
"
http
:
//
www.coolcode.cn/?p=16" rel=bookmark>利用 QQWry.Dat 实现 IP 地址高效检索(Php)(作者: andot)
数据库(QQWry
.
Dat)查询 C源码
"
href=
"
http
:
//
www.douzi.org/wp/index.Php/articles/71" rel=bookmark>纯真IP数据库(QQWry.Dat)查询 C源码 (作者:Windix)
转载纯真ip库
原文:http://www.cnblogs.com/Yi-yang/p/4651974.html