珊瑚虫IP库PHP操作类
< ?php |
class IpLocation{ |
private $fp; |
private $wrydat; |
private $wrydat_version; |
private $ipnumber; |
private $firstip; |
private $lastip; |
private $ip_range_begin; |
private $ip_range_end; |
private $country; |
private $area; |
const REDIRECT_MODE_0 = 0; |
const REDIRECT_MODE_1 = 1; |
const REDIRECT_MODE_2 = 2; |
function __construct(){ |
$args = func_get_args(); |
$this->wrydat = func_num_args()>0?$args[0]:'CoralWry.dat'; |
$this->initialize(); |
} |
function __destruct(){ |
fclose($this->fp); |
} |
private function initialize(){ |
if(file_exists($this->wrydat)) |
$this->fp = fopen($this->wrydat,'rb'); |
$this->getipnumber(); |
$this->getwryversion(); |
} |
public function get($str){ |
return $this->$str; |
} |
public function set($str,$val){ |
$this->$str = $val; |
} |
private function getbyte($length,$offset=null){ |
if(!is_null($offset)){ |
fseek($this->fp,$offset,SEEK_SET); |
} |
$b = fread($this->fp,$length); |
return $b; |
} |
/** |
* 把IP地址打包成二进制数据,以big endian(高位在前)格式打包 |
* 数据存储格式为 little endian(低位在前) 如: |
* 00 28 C6 DA 218.198.40.0 little endian |
* 3F 28 C6 DA 218.198.40.0 little endian |
* 这样的数据无法作二分搜索查找的比较,所以必须先把获得的IP数据使用strrev转换为big endian |
* @param $ip |
* @return big endian格式的二进制数据 |
*/ |
private function packip($ip){ |
return pack( "N", intval( ip2long( $ip))); |
} |
private function getlong($length=4, $offset=null){ |
$chr=null; |
for($c=0;$length%4!=0&&$c< (4-$length%4);$c++){ |
$chr .= chr(0); |
} |
$var = unpack( "Vlong", $this->getbyte($length, $offset).$chr); |
return $var['long']; |
} |
private function getwryversion(){ |
$length = preg_match("/coral/i",$this->wrydat)?26:30; |
$this->wrydat_version = $this->getbyte($length, $this->firstip-$length); |
} |
private function getipnumber(){ |
$this->firstip = $this->getlong(); |
$this->lastip = $this->getlong(); |
$this->ipnumber = ($this->lastip-$this->firstip)/7+1; |
} |
private function getstring($data="",$offset=null){ |
$char = $this->getbyte(1,$offset); |
while(ord($char) > 0){ |
$data .= $char; |
$char = $this->getbyte(1); |
} |
return $data; |
} |
private function iplocaltion($ip){ |
$ip = $this->packip($ip); |
$low = 0; |
$high = $this->ipnumber-1; |
$ipposition = $this->lastip; |
while($low < = $high){ |
$t = floor(($low+$high)/2); |
if($ip < strrev($this->getbyte(4,$this->firstip+$t*7))){ |
$high = $t - 1; |
} else { |
if($ip > strrev($this->getbyte(4,$this->getlong(3)))){ |
$low = $t + 1; |
}else{ |
$ipposition = $this->firstip+$t*7; |
break; |
} |
} |
} |
return $ipposition; |
} |
private function getarea(){ |
$b = $this->getbyte(1); |
switch(ord($b)){ |
case self::REDIRECT_MODE_0 : |
return "未知"; |
break; |
case self::REDIRECT_MODE_1: |
case self::REDIRECT_MODE_2: |
return $this->getstring("",$this->getlong(3)); |
break; |
default: |
return $this->getstring($b); |
break; |
} |
} |
public function getiplocation($ip){ |
$ippos = $this->iplocaltion($ip); |
$this->ip_range_begin = long2ip($this->getlong(4,$ippos)); |
$this->ip_range_end = long2ip($this->getlong(4,$this->getlong(3))); |
$b = $this->getbyte(1); |
switch (ord($b)){ |
case self::REDIRECT_MODE_1: |
$b = $this->getbyte(1,$this->getlong(3)); |
if(ord($b) == REDIRECT_MODE_2){ |
$countryoffset = $this->getlong(3); |
$this->area = $this->getarea(); |
$this->country = $this->getstring("",$countryoffset); |
}else{ |
$this->country = $this->getstring($b); |
$this->area = $this->getarea(); |
} |
break; |
case self::REDIRECT_MODE_2: |
$countryoffset = $this->getlong(3); |
$this->area = $this->getarea(); |
$this->country = $this->getstring("",$countryoffset); |
break; |
default: |
$this->country = $this->getstring($b); |
$this->area = $this->getarea(); |
break; |
} |
} |
} |
/* */ |
echo microtime(); |
echo "\n"; |
$iploca = new IpLocation; |
//$iploca = new IpLocation('QQWry.dat'); |
echo $iploca->get('wrydat_version'); |
echo "\n"; |
echo $iploca->get('ipnumber'); |
echo "\n"; |
$iploca->getiplocation('211.44.32.34'); |
/**/ |
echo $iploca->get('ip_range_begin'); |
echo "\n"; |
echo $iploca->get('ip_range_end'); |
echo "\n"; |
echo $iploca->get('country'); |
echo "\n"; |
echo $iploca->get('area'); |
echo "\n"; |
echo $iploca->get('lastip'); |
echo "\n"; |
echo microtime(); |
echo "\n"; |
unset($iploca); |
?> |
你好,很感谢你的内容,感觉很好.学习了下.
地方郭德纲