mirror of https://github.com/dnomd343/echoIP
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.7 KiB
96 lines
2.7 KiB
<?php
|
|
|
|
// 数据来源:IPIP免费数据库 ipipfree.ipdb
|
|
// 初始化类:new IPDB($fileName)
|
|
// 请求方式:getDistrict($ip)
|
|
// 返回格式:
|
|
// {
|
|
// '0': 国家
|
|
// '1': 省、直辖市
|
|
// '2': 市
|
|
// }
|
|
// 注:仅国内省市数据
|
|
//
|
|
// 请求版本:getVersion()
|
|
// 返回格式:YYYYMMDD
|
|
|
|
class IPDB {
|
|
private $fp; // 文件指针
|
|
private $meta; // 元数据信息
|
|
private $nodeCount;
|
|
private $nodeOffset;
|
|
|
|
public function __construct($fileName) { // 构造函数
|
|
$this->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;
|
|
}
|
|
return explode("\t", $this->getData($node));
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
?>
|