首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

ThinkPHP 6 整合 UTFWry 地址庫實現 IP 定位:從擴展安裝到生產級封裝

     編輯:PHP 相關知識

背景

ThinkPHP 6 內建 think-helper 提供 Request::ip(),但 IP 歸屬地解析需第三方擴展。UTFWry 是純真資料庫的 UTF-8 版,免費、離線、查詢極快(微秒級),適合高併發日誌記錄、風控、地域業務。

安裝與配置

  1. 下載擴展類: composer require thinkphp/extension-ip-location(或手動放入 extend/org/Net/IpLocation.php)
  2. 下載資料庫: UTFWry.dat 放入 extend/org/Net/ 或 runtime/ip/
  3. 配置路徑(config/app.php):
    '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查詢 IP114.114.114.114
beginipIP 段起始114.114.114.0
endipIP 段結束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);

資料庫更新策略

  • 純真/UTFWry 官方約每月更新,編寫定時任務 php think ip:update 下載最新 .dat 覆蓋。
  • 新一代 ip2region (xdb) 更新更頻繁、精度更高(街道級),遷移成本低(同介面),強烈建議新專案直接採用。

總結

ThinkPHP + UTFWry 實現 IP 定位只需三步:裝擴展、放資料庫、調介面。生產環境務必加上 Redis 快取、多庫降級、異常日誌、定期更新 四件套。新專案建議直接上 ip2region xdb,性能與精度雙贏。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved