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

PHP 安裝 GeoIP 擴展:依據 IP 獲取地理位置與計算距離完整教學

     編輯:PHP 綜合知識

前言

在 Web 開發中,根據訪客的 IP 地址獲取其地理位置(國家、城市、經緯度)是常見需求,例如提供本地化內容、統計訪客分佈或實現「附近的人」功能。PHP 的 GeoIP 擴展結合 MaxMind 提供的免費資料庫,能高效完成此任務。本文將詳細介紹在 Linux 環境下安裝 GeoIP 擴展、配置資料庫、查詢 IP 地理信息,以及利用經緯度計算兩點距離並實現範圍查詢的完整流程。

一、安裝 GeoIP PHP 擴展

1. 安裝系統依賴庫

首先需要安裝 GeoIP 開發庫:

sudo apt-get install libgeoip-dev

2. 通過 PECL 安裝 PHP 擴展

安裝指定版本的 geoip 擴展(Beta 版需指定版本號):

pecl install geoip-1.1.0

提示:若使用 apt 安裝的 PHP,可直接安裝 php5-geoip 包。

3. 修改 php.ini 配置

在 php.ini 中添加擴展載入與資料庫目錄配置:

extension=geoip.so
geoip.custom_directory="/usr/share/GeoIP"

二、下載並配置 GeoLiteCity 資料庫

MaxMind 提供免費的 GeoLiteCity 資料庫(解壓後約 18MB),下載地址:
https://dev.maxmind.com/geoip/legacy/install/city/

下載、解壓並移動到指定目錄:

wget https://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz
sudo mkdir -v /usr/share/GeoIP
sudo mv -v GeoLiteCity.dat /usr/share/GeoIP/GeoIPCity.dat

三、測試 GeoIP 功能

1. PHP 互動模式測試

php -a
<?php
print_r(geoip_record_by_name('106.37.165.80'));
// 按 Ctrl+D 運行
/*
輸出範例:
Array
(
    [continent_code] => AS
    [country_code] => CN
    [country_code3] => CHN
    [country_name] => China
    [region] => 22
    [city] => Beijing
    [postal_code] =>
    [latitude] => 39.928901672363
    [longitude] => 116.38829803467
    [dma_code] => 0
    [area_code] => 0
)
*/

2. 命令行工具 geoiplookup 測試

先安裝工具包:

sudo apt-get install geoip-bin geoip-database

查看 IP 信息(以 61.145.122.155 為例):

geoiplookup 61.145.122.155 -f /usr/share/GeoIP/GeoIP.dat
# GeoIP Country Edition: CN, China

geoiplookup 61.145.122.155 -f /usr/share/GeoIP/GeoIPCity.dat
# GeoIP City Edition, Rev 1: CN, 30, Guangdong, Guangzhou, N/A, 23.116699, 113.250000, 0, 0

說明: geoip-database 提供的 GeoIP.dat 僅精確到國家;從 MaxMind 官網下載的 GeoLiteCity 則包含城市、經緯度等詳細信息。直接執行 geoiplookup IP 會同時顯示兩個資料庫的結果。

四、根據 IP 獲取經緯度並計算距離

1. 獲取訪客經緯度

$record = geoip_record_by_name($_SERVER['REMOTE_ADDR']);
$lat = $record['latitude'];   // 緯度
$lon = $record['longitude'];  // 經度

注意: 返回值中,西經和南緯為負數。

2. 經緯度與米制換算

  • 緯度:1 度 ≈ 110,852 米
  • 經度:1 度 ≈ 111,320 × cos(緯度) 米

3. 以當前用戶為中心,查詢 5000 米內的用戶

$y = 5000 / 110852;                    // 緯度範圍
$x = 5000 / (111320 * cos($lat));      // 經度範圍

$sql = "SELECT * FROM `user` 
        WHERE `lat` BETWEEN {$lat} - {$y} AND {$lat} + {$y}
          AND `lon` BETWEEN {$lon} - {$x} AND {$lon} + {$x};";

資料表需預先存儲用戶的 lat(緯度)與 lon(經度)字段。上述 SQL 查出的是一個矩形粗略範圍,需進一步用精確公式過濾超出 5 公里的用戶。

4. Haversine 公式計算兩點精確距離

function distance($lat1, $lon1, $lat2, $lon2) {
    $R = 6371393; // 地球平均半徑(米)
    $dlat = deg2rad($lat2 - $lat1);
    $dlon = deg2rad($lon2 - $lon1);
    $a = pow(sin($dlat / 2), 2) 
       + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * pow(sin($dlon / 2), 2);
    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
    $d = $R * $c;
    return round($d);
}

// 測試:赤道上經度相差 1 度的距離
echo distance(0, 0, 0, 1); // 約 111202 米

5. 根據距離排序用戶

$users = [
    'win' => ['dis' => 1024, 'age' => 31],
    'osx' => ['dis' => 512,  'age' => 15],
    'lin' => ['dis' => 512,  'age' => 25],
];

foreach ($users as $k => $v) {
    $sort['dis'][$k] = $v['dis'];
    $sort['age'][$k] = $v['age'];
}
// 先按距離升序,距離相同則按年齡降序
array_multisort($sort['dis'], SORT_ASC, $sort['age'], SORT_DESC, $users);

echo json_encode($users);
// {"lin":{"dis":512,"age":25},"osx":{"dis":512,"age":15},"win":{"dis":1024,"age":31}}

總結

本文完整演示了:

  1. 安裝 libgeoip-dev 與 pecl install geoip
  2. 下載配置 GeoLiteCity.dat 至 /usr/share/GeoIP/GeoIPCity.dat
  3. 使用 geoip_record_by_name() 獲取國家、城市、經緯度
  4. 利用經緯度換算矩形範圍進行 SQL 粗略查詢
  5. 用 Haversine 公式精確計算距離並排序

這套方案適用於「附近的人」、門店定位、區域統計等場景,配合資料庫空間索引(如 MySQL SPATIAL INDEX 或 PostgreSQL PostGIS)可進一步提升大數據量下的查詢性能。

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