fp = fopen($fileName, 'rb'); $metaSize = unpack('N', fread($this->fp, 4))[1]; // 获取元数据长度 $this->meta = json_decode(fread($this->fp, $metaSize), 1); // 读取元数据信息 $this->nodeCount = $this->meta['node_count']; $this->nodeOffset = 4 + $metaSize; } public function __destruct() { // 析构函数 if ($this->fp) { fclose($this->fp); } } public function getVersion() { // 获取版本信息 return date("Ymd", $this->meta['build']); } public function getDistrict($ip) { // 获取地区信息 $node = $this->getNode($ip); if ($node <= 0) { return NULL; } $data = explode("\t", $this->getData($node)); foreach ($data as &$field) { $field = trim($field); } if ($data[1] === '中国' && $data[2] === '中国') { $data[1] = $data[2] = ''; } return $data; } private function getNode($ip) { // 获取节点编号 $node = 0; $binary = inet_pton($ip); for ($i = 0; $i < 96 && $node < $this->nodeCount; $i++) { if ($i >= 80) { $node = $this->readNode($node, 1); } else { $node = $this->readNode($node, 0); } if ($node > $this->nodeCount) { return 0; } } for ($i = 0; $i < 32; $i++) { if ($node >= $this->nodeCount) { break; } $node = $this->readNode($node, 1 & ((0xFF & ord($binary[$i >> 3])) >> 7 - ($i % 8))); } if ($node <= $this->nodeCount) { return NULL; } return $node; } private function readNode($node, $index) { return unpack('N', $this->read($node * 8 + $index * 4, 4))[1]; } private function getData($node) { // 根据节点编号获取信息 $offset = $node + $this->nodeCount * 7; $bytes = $this->read($offset, 2); $size = unpack('N', str_pad($bytes, 4, "\x00", STR_PAD_LEFT))[1]; $offset += 2; return $this->read($offset, $size); } private function read($offset, $length) { // 从指定位置读取指定长度 if ($length <= 0) { return NULL; } if (fseek($this->fp, $offset + $this->nodeOffset) === 0) { return fread($this->fp, $length); } } } ?>