'安徽', 'BJ' => '北京', 'CQ' => '重庆', 'FJ' => '福建', 'GD' => '广东', 'GS' => '甘肃', 'GX' => '广西', 'GZ' => '贵州', 'HA' => '河南', 'HE' => '河北', 'HI' => '海南', 'HK' => '香港', 'HL' => '黑龙江', 'HN' => '湖南', 'HB' => '湖北', 'JL' => '吉林', 'JS' => '江苏', 'JX' => '江西', 'LN' => '辽宁', 'MO' => '澳门', 'NM' => '内蒙古', 'NX' => '宁夏', 'QH' => '青海', 'SC' => '四川', 'SD' => '山东', 'SH' => '上海', 'SN' => '陕西', 'SX' => '山西', 'TJ' => '天津', 'TW' => '台湾', 'XJ' => '新疆', 'XZ' => '西藏', 'YN' => '云南', 'ZJ' => '浙江', ]; /** * 将IP地址转换为整数 * @param string $ip IP地址字符串 * @return int IP地址对应的整数 */ private function ipToInt($ip) { $ipParts = explode('.', $ip); if (count($ipParts) !== 4) { return 0; } $result = 0; for ($i = 0; $i < 4; $i++) { $part = intval($ipParts[$i]); if ($part < 0 || $part > 255) { return 0; } $result = ($result << 8) + $part; } return $result; } /** * 根据IP地址查询省份 * @param string $ip IP地址字符串 * @return string 省份名称,如果不存在则返回空字符串 */ public function queryProvince($ip) { if (empty($this->ipData)) { return ''; } $ipInt = $this->ipToInt($ip); if ($ipInt === 0) { return ''; } // 使用二分查找 $left = 0; $right = count($this->ipData) - 1; while ($left <= $right) { $mid = intval(($left + $right) / 2); $startIp = $this->ipData[$mid][0]; $endIp = $this->ipData[$mid][1]; if ($ipInt >= $startIp && $ipInt <= $endIp) { // 找到匹配的范围 $provinceCode = $this->ipData[$mid][2]; return $this->getProvinceName($provinceCode); } elseif ($ipInt < $startIp) { $right = $mid - 1; } else { $left = $mid + 1; } } return ''; } /** * 根据省份简写获取省份汉字名称 * @param string $provinceCode 省份简写 * @return string 省份汉字名称,如果不存在则返回空字符串 */ private function getProvinceName($provinceCode) { return isset($this->provinceMap[$provinceCode]) ? $this->provinceMap[$provinceCode] : ''; } /** * 获取所有支持的省份映射 * @return array 省份映射数组 */ public function getProvinceMap() { return $this->provinceMap; } /** * 添加或更新省份映射 * @param string $code 省份简写 * @param string $name 省份汉字名称 */ public function addProvinceMap($code, $name) { $this->provinceMap[$code] = $name; } /** * 获取当前加载的IP数据条数 * @return int IP数据条数 */ public function getIpDataCount() { return count($this->ipData); } /** * 从 ngx_ip_data.h 格式的文本解析 IP 数据 * @param string $content 文件内容 * @return array 解析出的 IP 数据数组 */ public static function parseFromNgxFormat($content) { $ipData = []; // 匹配类似 { 0x01000100, 0x010003FF, "FJ" } 的格式 $pattern = '/\{\s*0x([0-9A-Fa-f]+)\s*,\s*0x([0-9A-Fa-f]+)\s*,\s*"([A-Z]{2})"\s*\}/'; if (preg_match_all($pattern, $content, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $startIp = hexdec($match[1]); $endIp = hexdec($match[2]); $province = $match[3]; $ipData[] = [$startIp, $endIp, $province]; } } return $ipData; } }