IP 獲取分類與應用場景
| 類型 | 用途 | 關鍵變數/指令 |
| 伺服器公網 IP | 對外服務識別、授權驗證、多 IP 輪換 | ifconfig, ip addr, curl ifconfig.me |
| 客戶端真實 IP | 風控、日誌審計、地理定位、個性化內容 | $_SERVER['REMOTE_ADDR'], HTTP_X_FORWARDED_FOR, HTTP_CLIENT_IP |
一、獲取伺服器公網 IP(Linux 環境)
方法 1:解析 ifconfig/ip 指令輸出
<?php
/**
* 獲取伺服器所有非內網 IP
* @return array IP 陣列
*/
function getServerIps() {
// 使用 ip 指令(現代 Linux 推薦)或 ifconfig
$cmd = "ip -4 addr show scope global 2>/dev/null | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'";
// 兼容舊系統
if (empty(trim(shell_exec($cmd)))) {
$cmd = "/sbin/ifconfig | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}' | grep -v '^127\\.'";
}
exec($cmd, $ips);
// 過濾私有/保留 IP 範圍
$filtered = array_filter($ips, function($ip) {
$long = ip2long($ip);
// 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8
return !(
($long & 0xFF000000) == 0x0A000000 || // 10.x.x.x
($long & 0xFFF00000) == 0xAC100000 || // 172.16-31.x.x
($long & 0xFFFF0000) == 0xC0A80000 || // 192.168.x.x
($long & 0xFF000000) == 0x7F000000 // 127.x.x.x
);
});
shuffle($filtered); // 隨機排序,利於輪換
return array_values($filtered);
}
$ips = getServerIps();
print_r($ips);
// Array ( [0] => 203.0.113.45 [1] => 198.51.100.23 )
?>
方法 2:呼叫外部 API(簡單但有依賴)
<?php
function getPublicIpApi() {
$apis = array(
'https://api.ipify.org',
'https://ifconfig.me/ip',
'https://ipinfo.io/ip',
'https://icanhazip.com'
);
foreach ($apis as $api) {
$ctx = stream_context_create(array('http' => array('timeout' => 3)));
$ip = @file_get_contents($api, false, $ctx);
if ($ip && filter_var(trim($ip), FILTER_VALIDATE_IP)) {
return trim($ip);
}
}
return false;
}
?>
二、獲取客戶端真實 IP(穿透代理/負載均衡)
標準獲取函數
<?php
/**
* 獲取客戶端真實 IP
* @return string IP 位址
*/
function getClientIp() {
$headers = array(
'HTTP_CLIENT_IP', // 標準代理頭
'HTTP_X_FORWARDED_FOR', // 標準代理鏈(可能多個 IP,逗號分隔)
'HTTP_X_FORWARDED', // 較少見
'HTTP_X_CLUSTER_CLIENT_IP', // 某些負載均衡
'HTTP_FORWARDED_FOR', // RFC 7239
'HTTP_FORWARDED', // RFC 7239
'REMOTE_ADDR' // 直接連線/最後防線
);
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
$ips = explode(',', $_SERVER[$header]);
foreach ($ips as $ip) {
$ip = trim($ip);
// 驗證 IP 格式並排除私有 IP
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
}
}
// 兜底:直接連線 IP(可能為私有 IP)
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
// 簡化版(常見場景足夠)
function getClientIpSimple() {
if (!empty($_SERVER['HTTP_CLIENT_IP']) && filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP)) {
return $_SERVER['HTTP_CLIENT_IP'];
}
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($ips as $ip) {
$ip = trim($ip);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
return $ip;
}
}
}
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
?>
Nginx 代理配置關鍵(確保 Header 傳遞正確)
# nginx.conf / site.conf
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# ...
}
三、IP 地理定位(調用第三方 API)
新浪 IP 查詢介面(免費、支援 JSONP)
<?php
/**
* 獲取 IP 所在地理位置
* @param string $ip
* @return string 位置描述
*/
function getIpLocation($ip) {
$url = "https://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip={$ip}";
$ctx = stream_context_create(array('http' => array('timeout' => 5)));
$json = @file_get_contents($url, false, $ctx);
if (!$json) return '查詢失敗';
$data = json_decode($json, true);
if (empty($data) || $data['ret'] != 1) return '未知位置';
// 組合地址:國家 省份 城市 區 ISP
$parts = array();
foreach (array('country', 'province', 'city', 'district', 'isp') as $field) {
if (!empty($data[$field]) && $data[$field] != 'XX') {
$parts[] = $data[$field];
}
}
return implode(' ', $parts) ?: '未知位置';
}
// 使用範例
$ip = getClientIp();
echo "您的 IP: {$ip} 位置: " . getIpLocation($ip);
// 輸出:您的 IP: 203.0.113.45 位置: 台灣 台北市 中正區 中華電信
?>
其他免費 IP 定位 API 推薦
| 服務 | API 端點 | 限制 | 特色 |
| ipapi.co | https://ipapi.co/{ip}/json/ | 1000/天 | 欄位豐富、支援 HTTPS |
| ipinfo.io | https://ipinfo.io/{ip}/json | 50k/月 | 速度快、含 ASN、公司資訊 |
| ip-api.com | https://ip-api.com/json/{ip} | 45/分鐘 | 批次查詢支援 |
| MaxMind GeoLite2 | 本地資料庫 | 無限制 | 離線查詢、準確度高、需定期更新 |
四、IP 處理工具函數庫
<?php
class IpUtils {
// IP 轉長整數(IPv4)
public static function toLong($ip) {
return sprintf('%u', ip2long($ip));
}
// 長整數轉 IP
public static function fromLong($long) {
return long2ip($long);
}
// CIDR 範圍檢查
public static function inCidr($ip, $cidr) {
list($net, $mask) = explode('/', $cidr);
$netLong = ip2long($net);
$ipLong = ip2long($ip);
$maskLong = ~((1 << (32 - $mask)) - 1);
return ($ipLong & $maskLong) == ($netLong & $maskLong);
}
// 取得 CIDR 範圍起始/結束 IP
public static function cidrRange($cidr) {
list($net, $mask) = explode('/', $cidr);
$netLong = ip2long($net);
$hosts = 1 << (32 - $mask);
return array(
'start' => long2ip($netLong),
'end' => long2ip($netLong + $hosts - 1),
'count' => $hosts
);
}
// IPv6 簡易支援(需 PHP 支援)
public static function isValidV6($ip) {
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false;
}
}
// 使用範例
var_dump(IpUtils::inCidr('192.168.1.50', '192.168.1.0/24')); // true
var_dump(IpUtils::cidrRange('10.0.0.0/8')); // 16777216 個 IP
?>
安全性與隱私合規提醒
- GDPR/個資法:IP 視為個人資料,蒐集需告知同意,保留期限需限制
- 代理偽裝:
X-Forwarded-For 可被偽造,關鍵風控決策需結合裝置指紋、行為分析
- 內網洩露:錯誤訊息、日誌避免輸出內網 IP(10.x, 172.16-31.x, 192.168.x)
- IPv6 部署:現代系統需支援 IPv6 格式(如
2001:db8::1),資料庫欄位建議 VARCHAR(45)
結語
IP 獲取看似簡單,實則涉及網路拓撲、代理穿透、隱私合規等多層面。建立可靠的 getClientIp() 函數庫、配合 Nginx 正確傳遞 Header、善用本地 GeoIP 資料庫離線查詢,是打造高可用、安全、合規系統的關鍵基礎設施。