ThinkPHP 6 內建 think-helper 提供 Request::ip(),但 IP 歸屬地解析需第三方擴展。UTFWry 是純真資料庫的 UTF-8 版,免費、離線、查詢極快(微秒級),適合高併發日誌記錄、風控、地域業務。
composer require thinkphp/extension-ip-location(或手動放入 extend/org/Net/IpLocation.php)extend/org/Net/ 或 runtime/ip/'ip_location' => [
'library' => 'org\Net\IpLocation',
'dat_file' => app()->getRuntimePath() . 'ip/UTFWry.dat',
],
<?php
namespace app\controller;
use think\Request;
use think\facade\App;
class Index {
public function ipTest(Request $request) {
// 1. 獲取客戶端 IP(支援代理、CDN 真實 IP)
$ip = $request->ip(); // 自動處理 HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR, REMOTE_ADDR
// 2. 實例化定位器
$datFile = App::getConfig('ip_location.dat_file');
$locator = new \org\Net\IpLocation($datFile);
// 3. 查詢
$location = $locator->getlocation($ip);
// 4. 格式化輸出
$result = [
'ip' => $ip,
'country' => $location['country'] ?? '',
'area' => $location['area'] ?? '',
'region' => trim(($location['country'] ?? '') . ' ' . ($location['area'] ?? '')),
];
return json($result);
}
}
| 鍵 | 含義 | 範例 |
|---|---|---|
| ip | 查詢 IP | 114.114.114.114 |
| beginip | IP 段起始 | 114.114.114.0 |
| endip | IP 段結束 | 114.114.114.255 |
| country | 國家/省份 | 北京市 |
| area | 地區/運營商 | 電信/海淀區 |
<?php
namespace app\service;
use think\facade\Cache;
use think\facade\Log;
class IpLocationService {
private array $datFiles = [
'utfwry' => 'utfwry.dat', // UTF-8 版(推薦)
'qqwry' => 'qqwry.dat', // GBK 版,需 iconv
'ip2region' => 'ip2region.xdb', // 新一代,更快、更準
];
public function locate(string $ip): array {
// 1. 快取鍵
$cacheKey = "ip_loc:{$ip}";
if ($cached = Cache::get($cacheKey)) {
return $cached;
}
// 2. 嘗試主資料庫
foreach ($this->datFiles as $name => $file) {
$datPath = app()->getRuntimePath() . "ip/{$file}";
if (!is_file($datPath)) continue;
try {
$locator = new \org\Net\IpLocation($datPath);
$location = $locator->getlocation($ip);
// GBK 資料庫需轉碼
if ($name === 'qqwry') {
$location['country'] = iconv('GBK', 'UTF-8//IGNORE', $location['country'] ?? '');
$location['area'] = iconv('GBK', 'UTF-8//IGNORE', $location['area'] ?? '');
}
$result = [
'ip' => $ip,
'country' => $location['country'] ?? '',
'area' => $location['area'] ?? '',
'source' => $name,
];
// 3. 快取 30 天(IP 歸屬地極少變更)
Cache::set($cacheKey, $result, 86400 * 30);
return $result;
} catch (\Throwable $e) {
Log::warning("IP location {$name} failed: {$e->getMessage()}");
continue; // 降級嘗試下一個
}
}
// 3. 全部失敗返回預設
return ['ip' => $ip, 'country' => '未知', 'area' => '未知', 'source' => 'none'];
}
// 批量查詢(日誌分析、用戶畫像)
public function locateBatch(array $ips): array {
$results = [];
foreach ($ips as $ip) {
$results[$ip] = $this->locate($ip);
}
return $results;
}
}
<?php
$locator = new \org\Net\IpLocation($datFile);
$area = $locator->getlocation('www.baidu.com'); // 內部自動 gethostbyname
var_dump($area);
php think ip:update 下載最新 .dat 覆蓋。ThinkPHP + UTFWry 實現 IP 定位只需三步:裝擴展、放資料庫、調介面。生產環境務必加上 Redis 快取、多庫降級、異常日誌、定期更新 四件套。新專案建議直接上 ip2region xdb,性能與精度雙贏。