/*
二分法,查询IP文件
本文目的在于学习到fseek的使用方法和二分法原理
ip.csv文件格式
16908288,16908799,中国,福建省,未知
16908800,16909055,中国,北京市,北京市
16909312,16910335,中国,福建省,未知
1,2,3,4,5,6,7,8,9,10,11,12,13,14
3
mid = mid/2 = 7
$mid = $mid/2 = 4;
$mid = $mid/2 = 2;
$mid =
要求该文件,必须数字从小到大排列,否则无法采用二分法。
原理
1.得到文件大小703
2.折半对比IP数字大小,小于的,向前折半,大于的向后折半查找
header('Content-Type: text/html; charset=gbk');
$stime = time();
$ip = "124.58.180.5";
$address = readip($ip);
echo $address;
function readip($ip){
$ip_num = $ip_n = bindec(decbin(ip2long($ip)));
echo $ip_num;
$fname = 'ipfull.csv';
$fd = @fopen($fname, 'rb');
$size = filesize($fname);//得到文件大小,才好采用二分法
echo ' - size is : ';
echo $size;
echo '';
$len = $size;
$adress = '';
$sm = 0;
$em = $size;
$mid = ceil(($em - $sm)/2);
$b = true;
$ci = 0; //走的次数
while($b){
echo "$sm , $em , ".$mid.' - ';
fseek($fd,$mid);
$line = fread($fd, 80);
$x = explode("\n",$line);
$qline = $line;
$line = '';
foreach($x as $k=>$v){
if(preg_match("/^\\d+,\\d+,.*?,.*?,.*?$/",$v)){
$line = $v;
}
}
if($line==''){//最后的处理,直接命中
fseek($fd,$sm);
$line = fread($fd,$size-$mid);
$x = explode("\n",$line);
foreach($x as $k=>$v){
if(preg_match("/^\\d{8,10},\\d{8,10},.*?,.*?,.*?/",$v)){
$line = $v;
$arr = explode(',',$line);
$start = intval($arr[0]);
$end = intval($arr[1]);
if($ip_num >= $start && $ip_num <= $end){
echo '命中'.$line;
$address = $arr[2].$arr[3].$arr[4];
return $address;
$b = false;
break;
}
}
}
break;
}
$arr = explode(',',$line);
$start = $arr[0];
$end = $arr[1];
if($ip_num < $start ){
echo '向前走';
$em = $mid;
$mid = $sm + ceil(($em - $sm)/2);
}
if( $ip_num > $end){
echo '向后走'." # $start @ $end #";
$sm = $mid;
$mid = $mid + ceil(($em - $sm)/2);
}
if($ip_num >= $start && $ip_num <= $end){
echo '命中';
$address = $arr[2].$arr[3].$arr[4];
$b = false;
}
echo ' -- ';
echo $line;
echo '
';
if($mid<2)$b = false;
if($ci>100) $b = false;//说明没有找到
$ci++;
}
$etime = time();
$utime = $etime - $stime;
echo $address;
echo 'use time.'.$utime;
return $address;
}
经过测试这个方法,只需要1毫秒,即可查找到对应的IP地理位置
首发于
http://java-er.com/blog/php-ip-address/
阅读(256) | 评论(0) | 转发(0) |