纯真IP库PHP查询

class IP{

	private $fh;       // IP数据库文件句柄
	private $first;    // 第一条索引
	private $last;     // 最后一条索引
	private $total;    // 索引总数

	public function __construct(){
		$this->fh = fopen('qqwry.dat', 'rb');            // 读取数据文件
		$this->first = $this->getLong4();
    	$this->last = $this->getLong4();
    	$this->total = ($this->last - $this->first) / 7; //每条索引7字节
	}

	/* 检查IP的合法性 */
	public function checkIP($ip){
		$ipArr = explode('.',$ip);
		if(count($ipArr) < 4) return false;
		foreach ($ipArr as $key => $value) {
			if($value < 0 || $value > 255){
				return false;
			}
		}
		return true;
	}

	/* 读取little-endian编码的4个字节转化为长整型数 */
	public function getLong4() {
		$result = unpack('Vlong', fread($this->fh, 4));
		return $result['long'];
	}

	/* 读取little-endian编码的3个字节转化为长整型数 */
	public function getLong3() {
		$result = unpack('Vlong', fread($this->fh, 3).chr(0));
		return $result['long'];
	}

	/* 获取位置信息 */
	public function getInfo($data = "") {
		$char = fread($this->fh, 1);
		while (ord($char) != 0) { //国家地区信息以0结束
			$data .= $char;
			$char = fread($this->fh, 1);
		}
		return $data;
	}

	/* 获取所属地区 */
	public function getArea() {
		$byte = fread($this->fh, 1); //标志字节
		switch (ord($byte)) {
			case 0: $area = ''; break; //没有地区信息
			case 1: //地区被重定向
			fseek($this->fh, $this->getLong3());
			$area = $this->getInfo(); break;
			case 2: //地区被重定向
			fseek($this->fh, $this->getLong3());
			$area = $this->getInfo(); break;
			default: $area = $this->getInfo($byte);  break; //地区没有被重定向
		}
		return $area;
	}

	/* 获取地址 */
	public function ip2addr($ip) {
		if(!$this -> checkIp($ip)){
			return false;
		}
  		$ip = pack('N', intval(ip2long($ip)));
		//二分查找
		$l = 0;
		$r = $this->total;
		while($l <= $r) {
			$m = floor(($l + $r) / 2); //计算中间索引
			fseek($this->fh, $this->first + $m * 7);
			$beginip = strrev(fread($this->fh, 4)); //中间索引的开始IP地址
			fseek($this->fh, $this->getLong3());
			$endip = strrev(fread($this->fh, 4)); //中间索引的结束IP地址
			if ($ip < $beginip){ //用户的IP小于中间索引的开始IP地址时
				$r = $m - 1;
			}else{
				if ($ip > $endip) { //用户的IP大于中间索引的结束IP地址时
					$l = $m + 1;
				}else{ //用户IP在中间索引的IP范围内时
					$findip = $this->first + $m * 7;
					break;
				}
			}
		}

		//查询国家地区信息
		fseek($this->fh, $findip);
		$location['beginip'] = long2ip($this->getLong4()); //用户IP所在范围的开始地址
		$offset = $this->getlong3();
		fseek($this->fh, $offset);
		$location['endip'] = long2ip($this->getLong4()); //用户IP所在范围的结束地址
		$byte = fread($this->fh, 1); //标志字节
		switch (ord($byte)) {
			case 1:  //国家和区域信息都被重定向
				$countryOffset = $this->getLong3(); //重定向地址
				fseek($this->fh, $countryOffset);
				$byte = fread($this->fh, 1); //标志字节
				switch (ord($byte)) {
					case 2: //国家信息被二次重定向
						fseek($this->fh, $this->getLong3());
						$location['country'] = $this->getInfo();
						fseek($this->fh, $countryOffset + 4);
						$location['area'] = $this->getArea();
						break;
					default: //国家信息没有被二次重定向
						$location['country'] = $this->getInfo($byte);
						$location['area'] = $this->getArea();
						break;
				}
				break;
			case 2: //国家信息被重定向
				fseek($this->fh, $this->getLong3());
				$location['country'] = $this->getInfo();
				fseek($this->fh, $offset + 8);
				$location['area'] = $this->getArea();
				break;
			default: //国家信息没有被重定向
				$location['country'] = $this->getInfo($byte);
				$location['area'] = $this->getArea();
				break;
		}
 		//gb2312 to utf-8(去除无信息时显示的CZ88.NET)
		foreach ($location as $k => $v) {
			$location[$k] = str_replace('CZ88.NET','',iconv('gb2312', 'utf-8', $v));
		}
		return $location;
	}

	//析构函数
	function __destruct() {
		fclose($this->fh);
	}

}



/* 调用实例 */
$ip = new ip();
$addr = $ip -> ip2addr('117.136.30.178');
print_r($addr);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值