一直很想用IP去分辯出用戶是哪個國家哪個城市來的,之前都是用免費網路連線的方案(比如 http://ipinfodb.com), 可是這類方案有每個月1000次的限額,超過之後就要付費。所以一直想把整個地理資料庫塞在自己伺服器裏面,這樣就可以無限次查詢了。搞了好久,今天總算搞定!本篇文章是參考了Grok AI的教學,並且實作出來的。如果有不懂的,可以用Grok AI查一下。
我採用的是.mmdb資料庫,而不是.csv資料庫導入mysql。原因是.mmdb是二進位制,速度可以是mysql的十分之一,所以如果你沒有把資料配合其他資料整合為一個mysql的需求,只是單純想查國家城市,採用.mmdb比較結省空間也省時間。而且PHP可以直接在讀取.mmdb,上面也有很完善的方案了(geoip2)。
首先,我們要先下載地理ip的資料庫
1. 請到 https://www.maxmind.com
2. 點右上角 "Sign IN"
3. 最底下有一個 "how to creat new one",進入
4. 再找到 "sign up for free GeoLite services",進入
5. 再點選 "You can sign up for GeoLite on our main website"
6. 填入註冊資料,然後過程需要email認證,這個就是一般註冊流程,我是覺得密碼設定要來回再跑一次email認證是有點奇怪,不過....就也沒出什麼毛病。
7. 登入之後,左側點選 "Download files"
8. 下載 GeoLite ASN > Download GZIP,檔案是GeoLite2-ASN_20250807.tar.gz (但日期可能隨時間會改變),這個檔案是查詢來源的組識ISP(中華電信或遠傳或Microsoft...),不要的人可以省略
9. 下載 GeoLite City > Download GZIP,檔案是GeoLite2-City_20250805.tar.gz (但日期可能隨時間會改變), 這個檔案是查詢來源的城市國家
10. 解壓縮開來,然後把檔案(GeoLite2-City.mmdb和GeoLite2-ASN.mmdb)存到 伺服器 /var/www/html/geoip/ 資料夾裏面,沒有的話就新建。我是用SFTP方式上傳的,這樣可以直接讓Apache直接擁有檔案的存取權,如果是自己用檔案挪過去的,就要再做以下步驟。
11. 如果不是用sftp上傳的,是自己在伺服器上下載的,就要CentOS再執行以下兩行,給予權限
[~]# chown apache:apache /var/www/html/geoip/*.mmdb
[~]# chmod 644 /var/www/html/geoip/*.mmdb
12. 再檢查一下資料庫是不是可以讀取
[~]# ls -l /var/www/html/geoip/
出現以下權限宣告-rw-rw-r--就是沒問題了
-rw-rw-r-- 1 rman rman 10700660 8月 7 23:26 GeoLite2-ASN.mmdb
-rw-rw-r-- 1 rman rman 60705209 8月 7 23:27 GeoLite2-City.mmdb
13. 如果你的 CentOS 7 預設啟用 SELinux,可能限制 Apache 存取 /var/www/html/geoip 。
檢查 SELinux 狀態
[~]# sestatus
若顯示「enabled」,設定正確的 SELinux 上下文:
[~]# chcon -R -t httpd_sys_content_t /var/www/html/geoip/
到這裏,資料庫的設定告一段落,接下來,就都是CentOS上面的操作
先檢查PHP有沒有curl和mbstring的功能,因為會用這個下載composer這個套件架構
[~]# php -m | grep -E 'curl|mbstring'
沒問題的話會出現
curl
mbstring
查看有沒有composer套件
[~]# composer --version
如果出現以下,就是代表之前沒有裝過composer這個套件安裝器
bash: composer: 找不到指令...
先進入html目錄預備安裝composer
[~]# cd /var/www/html
安裝composer套件,我們這裏是直接用最新版,然而你也可以指定自己要的版本
[~ html]# php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
[~ html]# php composer-setup.php --install-dir=/usr/local/bin --filename=composer
裝好了,可以看一下版本資訊
[~ html]# composer --version
composer只是一個套件架構,我們要的是底下的geoip功能去讀取mmdb資料庫,所以我們要再裝geoip2,為了配合我的PHP5.6.4,我選擇套件2.9.0版
[~ html]# cd /var/www/html
[~ html]# composer require geoip2/geoip2:~2.9.0
裝好之後, geoip2會產生vendor資料夾,因此,我們要再讓apache可運行有足夠權限去運行
[~ html]# chown -R apache:apache /var/www/html/vendor
[~ html]# chmod -R 755 /var/www/html/vendor
如果怕網路有不相干的人進來讀取mmdb資料庫,我們可以弄一個.htaccess,然後存在geoip資料夾裏面
.htaccess內容是
一樣要給權限
[~l html]# chown apache:apache /var/www/html/geoip/.htaccess
[~ html]# chmod 644 /var/www/html/geoip/.htaccess
重啟伺服器, 搞定
[~ html]# systemctl restart httpd
在PHP要怎麼操作,PHP程式範例如下, 你可以依照你想要再行修改,不想查找ISP組織名的,可以把那些相關的刪除,我自己是覺得mmdb效率真的超快!所以就算多查一個organization也不花什麼時間
require '/vendor/autoload.php';
use GeoIp2\Database\Reader;
$cityDbPath = '/var/www/html/geoip/GeoLite2-City.mmdb';
$asnDbPath = '/var/www/html/geoip/GeoLite2-ASN.mmdb';
$ipAddress = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '8.8.8.8';
try {
$cityReader = new Reader($cityDbPath);
$asnReader = new Reader($asnDbPath);
$cityRecord = $cityReader->city($ipAddress);
$asnRecord = $asnReader->asn($ipAddress);
$country = isset($cityRecord->country->isoCode) ? $cityRecord->country->isoCode : '未知';
$city = isset($cityRecord->city->name) ? $cityRecord->city->name : '未知';
$region = isset($cityRecord->subdivisions[0]->name) ? $cityRecord->subdivisions[0]->name : '未知';
$organization = isset($asnRecord->autonomousSystemOrganization) ? $asnRecord->autonomousSystemOrganization : '未知';
echo "IP: $ipAddress<br>";
echo "國家: $country<br>";
echo "城市: $city<br>";
echo "行政區: $region <br>";
echo "組織: $organization<br>";
} catch (Exception $e) {
echo "錯誤: " . $e->getMessage();
}
我自己使用心得這筆 GeoLite City 資料,台灣方面的很齊全,所有城市都找的到,但大陸的城市或印度城市就不一定找的到。後來想一想,其實是可以搭配 http://ipinfodb.com 一起使用, 先用本地geoip2功能找mmdb資料庫,因為比較快。如果找不到時,再花時間去連線 ipinfodb.com 回傳地理資料。(if...then...)
