| 方案 | 優點 | 缺點 | 適用場景 |
| 純真資料庫 + 本地解析 | 離線、免費、無 API 限流 | 需定期更新資料庫、記憶體佔用大 | 高併發、內網、對準確度要求不極高 |
| 第三方 API(淘騰訊/高德/ipapi) | 準確、免維護、支援 IPv6 | 需網路、有 QPS 限制、可能收費 | 公開網站、需高準確度 |
| MaxMind GeoIP2 (本地 mmdb) | 準確度高、官方維護、支援 IPv6 | 需授權、資料庫較大 | 企業級應用 |
本地純真資料庫實作
原文提供的 QQWry 類別解析 qqwry.dat,核心邏輯:
- 讀取索引區首尾位移,計算記錄數
- 二分搜尋定位 IP 所在記錄
- 讀取國家/地區字串(支援指向壓縮)
優化版使用範例
<?php
require_once 'QQWry.class.php';
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
// 取第一個 IP(代理鏈)
$ip = explode(',', $ip)[0];
$qqwry = new QQWry();
$result = $qqwry->QQWry($ip);
if ($result === 0) {
$location = trim($qqwry->Country . ' ' . $qqwry->Local);
// 映射到分站域名
$cityMap = [
'北京' => 'bj.example.com',
'上海' => 'sh.example.com',
'廣東' => 'gz.example.com',
'深圳' => 'sz.example.com',
];
foreach ($cityMap as $keyword => $domain) {
if (strpos($location, $keyword) !== false) {
header("Location: https://{$domain}");
exit;
}
}
}
// 預設導向總站
header('Location: https://www.example.com');
第三方 API 方案(以 ip-api.com 為例)
<?php
function getCityByIp(string $ip): ?string {
$url = "https://ip-api.com/json/{$ip}?lang=zh-CN&fields=city,status";
$json = @file_get_contents($url);
if (!$json) return null;
$data = json_decode($json, true);
return ($data['status'] ?? '') === 'success' ? $data['city'] : null;
}
$ip = $_SERVER['REMOTE_ADDR'];
$city = getCityByIp($ip);
if ($city) {
$domain = match ($city) {
'北京' => 'bj.example.com',
'上海' => 'sh.example.com',
default => 'www.example.com',
};
header("Location: https://{$domain}");
exit;
}
生產環境關鍵優化
- 快取 IP 解析結果:Redis 設定 TTL 24h,避免重複查詢/檔案讀取。
- 非同步導向:前端 JS 讀取後端 API 取得分站域名,再
window.location.href 導向,避免首屏阻塞。
- 支援 IPv6:純真資料庫舊版不支援,建議改用 MaxMind GeoIP2 或 API。
- 備用策略:解析失敗/超時導向總站,記錄日誌供事後分析。
- CDN 邊緣計算:Cloudflare Workers / 阿里云 EdgeRoutine 直接在邊緣節點完成導向,零回源延遲。
程式碼結構建議
src/
├── Geo/
│ ├── DriverInterface.php // 介面:resolve(string $ip): ?string
│ ├── QQWryDriver.php // 純真實作
│ ├── MaxMindDriver.php // GeoIP2 實作
│ └── ApiDriver.php // 第三方 API 實作
├── GeoResolver.php // 工廠+快取+備用邏輯
└── Middleware/
└── RedirectToSubsite.php // Laravel/ThinkPHP 中介層
結語
IP 分站導向看似簡單,實則涉及資料準確度、效能、高可用、IPv6 相容多重考量。建議採用「介面隔離 + 多驅動 + Redis 快取 + 邊緣計算」架構,漸進式升級而非一次性重構。
- 上一篇文章: PHP in_array() 函數完整指南:參數、嚴格模式與效能陷阱
- 下一篇文章: PHP 取得字串首字母(支援中文拼音首字母)實作
Copyright ©
程式碼之家 All Rights Reserved