当前位置:首页> PHP教程> PHP代码
关键字
文章内容
利用纯真QQIP数据库做快速IP归属地查询
 
 
修改时间:[2012/07/02 10:05]    阅读次数:[1801]    发表者:[起缘]
 

利用纯真版IP数据文件,优化查询方法,提高格式转换效率,减少读取文件的次数,达到快速在线查询IP的目的。大幅度减少文件读取次数,对保护服务器硬盘应该有一定的好处。并增加一个数据库浏览器,可以浏览纯真版QQIP数据文件。

1.用ip2long()做IP校验
2.用sprintf做强制转换
3.用unpack分析二进制数据,减少了 文件读取次数
4.substr strpos分析字符串,这也减少了文件读取次数

<form name="ipform" method="get" action="">
<br/>IP Address:<input type="text" name="ip"/>
<br/><a href="javascript:document.ipform.submit();">Submit</a>
<br/>
</form> 
 
<?php 
define('IPDATA','ipdata.db'); 
//get ip 
$ip = isset($_GET['ip'])?$_GET['ip']:getenv("REMOTE_ADDR"); 
echo "IP: ARIN"; 
if (-1 === ($ip = ip2long($ip)))  die("Invalid IP"); 
$ip = sprintf("%u",$ip); 
$country = $city = ''; 
echo " 
Record No:".Whois($ip,$country,$city); 
echo " 
Location:  []"; 
 
function Whois($ip,&$country,&$city) 
{ 
  //open ip-database 
  if (NULL == ($fp = fopen(IPDATA, "rb"))) die("cannot open dbfile."); 
  //get data section offset 
  $offset = unpack("Vbegin/Vend", fread($fp, 8)); 
  $begin = 0;$end = ($offset['end'] - $offset['begin']) / 7; 
  //seek index 
  while ($begin < $end - 1) { 
    $num = ($begin + $end) >> 1; 
    fseek ($fp , ($offset['begin'] + $num * 7) , SEEK_SET ) ; 
    $record = unpack("Vip", fread($fp, 4)); 
    $record['ip'] = sprintf("%u",$record['ip']); 
    if ($ip == $record['ip']) { $begin = $num; break;} 
    if ($ip > $record['ip'])    $begin = $num; 
    else                        $end = $num;     
  } 
  //read index 
  $record = unpack("Vbeginip/Vloc", ReadBinary($fp,$offset['begin']+$begin*7) ); 
  $locoff =($record['loc'] & 0x00FFFFFF); 
  $info = unpack("Vendip/Vloc",ReadBinary($fp,$locoff)) ; 
  $info['endip'] = sprintf("%u",$info['endip']); 
  if($info['endip'] < $ip)  die(" [unkown location]"); 
  //get GEO 
  $countryoff = (($info['loc'] & 0x000000FF)== 1)?($info['loc'] >> 8):($locoff+4); 
  $country = ReadGEOStr($fp,$countryoff); 
  $city = ReadGEOStr($fp,$countryoff); 
  return $begin; 
}   
 
function ReadGEOStr($fp,&$offset) 
{ 
  $binarydata = ReadBinary($fp,$offset); 
  $info = unpack("Vloc",$binarydata); 
  if( ($info['loc'] & 0x000000FF) == 2 ) { 
    $GeoStr = ReadBinary($fp,$info['loc'] >> 8 ); 
    $GeoStr = substr($GeoStr,0,strpos($GeoStr, 0)); 
    $offset += 4; 
  }else { 
    $len = strpos($binarydata, 0); 
    $GeoStr = substr($binarydata,0,$len); 
    $offset += $len + 1; 
  } 
  return $GeoStr; 
}   
 
function ReadBinary($fp,$positionz) 
{ 
  fseek ( $fp , $positionz , SEEK_SET ) ; 
  return fread ( $fp , 32 ) ; 
} 
?> 
 
<form action="" method="get" name="ipform"> 
IP Address:<input name="ip" type="text"> 
<a href="javascript:document.ipform.submit();">Submit</a> 
</form> 
 
<form action="" method="get" name="record"> 
Start<input name="s" type="text"> 
Count<input name="c" type="text"> 
<a href="javascript:document.record.submit();">Submit</a> 
</form> 
 
<?php 
define('IPDATA','ipdata.db'); 
 
$fp = NULL; 
if( isset($_GET['ip']) ) 
{ 
  $ipx = $_GET['ip']; 
  if (-1 === ($ip = ip2long($ipx)))  die("Invalid IP"); 
  echo "IP: <a href=\"whoisip.php?ip=\">ARIN</a>"; 
  $ip = sprintf("%u",$ip); 
  $ippostion = ''; 
  $start_time=get_time(); 
  echo "<br>Record No:".Whois($ippostion); 
  $end_time=get_time(); 
  echo "<br>Location:"; 
  echo "<br>Process Time:".round($end_time-$start_time,3)."seconds"; 
} 
else if ( isset($_GET['s']) ) 
{ 
  $first = $_GET['s']; 
  $rcount = $_GET['c']; 
  $startoff = $end = 0; 
  GetSection($startoff,$end); 
      
  if( ($i = $first+$rcount)>$end  || $first<0) 
    die ("count overflow"); 
  else
  { 
    $j = $first-$rcount; 
    echo "<a href='?s=$j&c=$rcount'>Prev</a>:::"; 
    $j = $first+$rcount; 
    echo "<a href='?s=$j&c=$rcount'>Next</a><br>"; 
  } 
      
  while( $first < $i) 
  { 
    echo ReadRecord($startoff,$first,$startip,$endip); 
    $startip = long2ip($startip); 
    $endip = long2ip($endip); 
    echo "&nbsp;:--<br>"; 
    $first ++; 
  } 
  fclose($fp); 
} 
else
{ 
   echo "Powered by <a href='http://www.eoncn.com'>www.eoncn.com</a>"; 
}   
 
 
 
function Whois(&$country) 
{ 
  global $ip,$fp; 
 
  $startoff = $begin = $end = 0; 
  GetSection($startoff,$end); 
  //seek index 
  while ($begin < $end - 1) { 
    $num = ($begin + $end) >> 1; 
    fseek ($fp , $startoff + $num * 7 , SEEK_SET ) ; 
    $record = unpack("Vip", fread($fp, 4)); 
    $record['ip'] = sprintf("%u",$record['ip']); 
    if ($ip == $record['ip']) { $begin = $num; break;} 
    if ($ip > $record['ip'])    $begin = $num; 
    else                        $end = $num;     
  } 
  //read index 
  $startip = $endip = 0; 
  $country = ReadRecord($startoff,$begin,$startip,$endip); 
  fclose($fp); 
  return $begin; 
}   
 
function GetSection(&$startoff,&$total) 
{ 
  global $fp; 
  //open ip-database 
  if (NULL == ($fp = fopen(IPDATA, "rb"))) die("cannot open dbfile."); 
  //get data section offset 
  $offset = unpack("Vbegin/Vend", fread($fp, 8)); 
  $total = ($offset['end'] - $offset['begin']) / 7; 
  $startoff = $offset['begin']; 
} 
 
function ReadRecord($startoff,$number,&$startip,&$endip) 
{ 
  global $ip; 
  $record = unpack("Vbeginip/Vloc", ReadBinary($startoff+$number*7) ); 
  $startip = $record['beginip']; 
  $locoff =($record['loc'] & 0x00FFFFFF); 
  $info = unpack("Vendip/Vloc",ReadBinary($locoff)) ; 
  $endip = $info['endip']; 
  $info['endip'] = sprintf("%u",$info['endip']); 
  if($info['endip'] < $ip)  die(" [unkown location]"); 
  //get GEO 
  $countryoff = (($info['loc'] & 0x000000FF)== 1)?($info['loc'] >> 8):($locoff+4); 
  return ReadGEOStr($countryoff)."->".ReadGEOStr($countryoff);     
} 
 
function ReadGEOStr(&$offset) 
{ 
  $binarydata = ReadBinary($offset); 
  $info = unpack("Vloc",$binarydata); 
  if( ($info['loc'] & 0x000000FF) == 2 ) { 
    $GeoStr = ReadBinary($info['loc'] >> 8 ); 
    $GeoStr = substr($GeoStr,0,strpos($GeoStr, 0)); 
    $offset += 4; 
  }else { 
    $len = strpos($binarydata, 0); 
    $GeoStr = substr($binarydata,0,$len); 
    $offset += $len + 1; 
  } 
  return $GeoStr; 
}   
 
function ReadBinary($positionz) 
{ 
  global $fp; 
  fseek ( $fp , $positionz , SEEK_SET ) ; 
  return fread ( $fp , 32 ) ; 
} 
 
function get_time() { 
  $mtime=microtime(); 
  $mtime=explode(" ",$mtime); 
  $mtime=$mtime[1]+$mtime[0]; 
  return($mtime); 
} 
?>

总结:完成此功能最好将数据导入到数据库,用数据库查询,才能达到最快的速度。

参考数据库查询效果:http://www.eoncn.com首页的IP地址查询。