IPV4_AREA_ERROR_SUCCESS,
'encoding'=>null,
'num_items'=>0,
'index_pos'=>0,
'data_pos'=>0,
'fp'=>null,
'index_read_parts'=>$index_read_parts,
'each_read_item'=>0,
'each_read_byte'=>0,
'last_part_data'=>null
);
$obj['fp']=@fopen($filename,"r");
if(!$obj['fp']){
$obj['status']=IPV4_AREA_ERROR_OPENFILE;
return $obj;
}
$meta=fread($obj['fp'],20);
$magic=$meta[0].$meta[1].$meta[2];
if($magic!='IPT'){
$obj['status']=IPV4_AREA_ERROR_FORMAT;
return $obj;
}
if($meta[3]=='u'){
$obj['encoding']='UTF-8';
}
else if($meta[3]=='g'){
$obj['encoding']='GBK';
}
$file_size=filesize($filename);
$a=unpack('N',substr($meta,4,4));
if($a[1]!=$file_size){
$obj['status']=IPV4_AREA_ERROR_FORMAT;
return $obj;
}
$a=unpack('N',substr($meta,8,4));
$obj['num_items']=$a[1];
$a=unpack('N',substr($meta,12,4));
$obj['index_pos']=$a[1];
$a=unpack('N',substr($meta,16,4));
$obj['data_pos']=$a[1];
$obj['each_read_item']=ceil($obj['num_items']/$index_read_parts);
$obj['each_read_byte']=$obj['each_read_item']*12;
if($index_read_parts==1){
$obj['last_part_data']='';
$pos=0;
fseek($obj['fp'],$obj['index_pos'],SEEK_SET);
while($pos<$obj['each_read_byte']){
if($obj['each_read_byte']-$pos>4096) $len=4096;
else $len=$obj['each_read_byte']-$pos;
$obj['last_part_data'].=fread($obj['fp'],$len);
$pos+=$len;
}
}
return $obj;
}
/**
* IP址所在地查询
* @param $obj 数据库对象
* @param $ip IP地址,可以为'XXX.XXX.XXX.XXX'格式
* @return 归属地名称
*/
function ipv4_area_search($obj,$ip){
$ret='';
if(!is_numeric($ip)){
$ip=ipv4_atol($ip);
}
$current_left_part=0;
$current_right_part=$obj['index_read_parts'];
while($current_left_part<$current_right_part){
$current_process_part=floor(($current_left_part+$current_right_part)/2);
if($obj['index_read_parts']==1){
$data=$obj['last_part_data'];
$read_items=$obj['each_read_item'];
$read_bytes=$obj['each_read_byte'];
}
else{
$read_bytes=$obj['num_items']*12-$obj['each_read_byte']*$current_process_part;
if($read_bytes>$obj['each_read_byte']){
$read_bytes=$obj['each_read_byte'];
}
$off=$obj['index_pos']+$obj['each_read_byte']*$current_process_part;
fseek($obj['fp'],$off,SEEK_SET);
$data='';
$pos=0;
while($pos<$read_bytes){
if($read_bytes-$pos>4096) $len=4096;
else $len=$read_bytes-$pos;
$data.=fread($obj['fp'],$len);
$pos+=$len;
}
$read_items=floor($read_bytes/12);
}
$head=unpack('N*',substr($data,0,12));
$tail=unpack('N*',substr($data,$read_bytes-12,12));
$head[1]=ipv4_signed_to_unsigned($head[1]);
$head[2]=ipv4_signed_to_unsigned($head[2]);
$tail[1]=ipv4_signed_to_unsigned($tail[1]);
$tail[2]=ipv4_signed_to_unsigned($tail[2]);
if($head[1]>$ip){
if($current_right_part==$current_process_part) break;
$current_right_part=$current_process_part;
}
else if($tail[2]<$ip){
if($current_left_part==$current_process_part) break;
$current_left_part=$current_process_part;
}
else if($head[2]<$ip && $tail[1]>$ip){
$inner_left=0;
$inner_right=$read_items;
while($inner_left<$inner_right){
$inner_current=floor(($inner_left+$inner_right)/2);
$node=unpack('N*',substr($data,$inner_current*12,12));
$node[1]=ipv4_signed_to_unsigned($node[1]);
$node[2]=ipv4_signed_to_unsigned($node[2]);
if($node[1]>$ip){
if($inner_right==$inner_current) break;
$inner_right=$inner_current;
}
else if($node[2]<$ip){
if($inner_left==$inner_current) break;
$inner_left=$inner_current;
}
else{
$ret=ipv4_area_get_area_string($obj,$node[3]);
break;
}
}
break;
}
else if($head[1]<=$ip && $head[2]>=$ip){
$ret=ipv4_area_get_area_string($obj,$head[3]);
break;
}
else if($tail[1]<=$ip && $tail[2]>=$ip){
$ret=ipv4_area_get_area_string($obj,$tail[3]);
break;
}
}
return $ret;
}
/**
* 释放IP数据库
* @param $object 由函数ipv4_area_create返回的表对象
*/
function ipv4_area_free($object){
if($object['fp']) fclose($object['fp']);
}
/*
include('./ips.php'); //包含测试数组$test_ips,包含1760个需要查询所在地的IP地址
$s=microtime(true);
$object=ipv4_area_create('./ip_utf8.dat');//初始化数据库
if($object['status']==IPV4_AREA_ERROR_SUCCESS){
foreach($test_ips as $ip){ //循环查询每一个IP的所在地
$area=ipv4_area_search($object,$ip);
echo "IP:{$ip}
AREA:{$area}
\n";
}
}
ipv4_area_free($object); //释放对象
echo microtime(true)-$s; //当创建时参数index_read_parts=1时,查询1760条IP所在地仅需3.68秒(上网本)
*/
?>