1.前言
PHP如何獲取用戶的真實IP地址?如果看過一些入門教科書的朋友可能會記得,書上告訴我們使用如下方法獲取:$_SERVER["REMOTE_ADDR"];但是現實真的是如此嗎?並不是,因爲隨着互聯網的發展,我們訪問的途徑變得多種多樣,用戶可以使用代理IP代理訪問、也可能通過CDN加速訪問,那麼你所獲取的IP可能只是代理或者最近一個節點的IP,而不是真實用戶的IP。
2.打印服務器在不同狀態下的捕捉情況
根據下面的代碼,我們可以得到各個CDN加速後的IP結果:
<?php
print_r($_SERVER);
?>
2.1百度CDN打印結果
Array
(
[HTTP_X_FORWARDED_FOR] => 119.164.27.53,123.234.0.103,27.221.124.94
[HTTP_X_REAL_IP] => 119.164.27.53
[REMOTE_ADDR] => 150.138.138.169
.........
)
2.2阿里CDN打印結果
Array
(
[HTTP_ALI_CDN_REAL_IP] => 119.164.27.53
[HTTP_X_FORWARDED_FOR] => 119.164.27.53
[REMOTE_ADDR] => 115.124.31.68
.........
)
2.3七雲牛CDN打印結果
Array
(
[HTTP_ALI_CDN_REAL_IP] => 119.164.27.53
[HTTP_X_FORWARDED_FOR] => 119.164.27.53
[REMOTE_ADDR] => 182.92.246.161
.........
)
綜上幾家常見的CDN加速,我們可以總結出:使用CDN時,$_SERVER變量中就會含有“HTTP_X_FORWARDED_FOR”元素,並且它裏面含有用戶的真實IP地址,所以根據這個特點,我們可以封裝出以下函數:
function _get_client_ip() {
$clientip = '';
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$clientip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$clientip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$clientip = getenv('REMOTE_ADDR');
} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$clientip = $_SERVER['REMOTE_ADDR'];
}
preg_match("/[\d.]{7,15}/", $clientip, $clientipmatches);
$clientip = $clientipmatches[0] ? $clientipmatches[0] : 'unknown';
return $clientip;
}
先解釋一下 REMOTE_ADDR 、 HTTP_X_FORWARDED_FOR 、 HTTP_CLIENT_IP 是什麼?不然看的一臉懵逼。
- REMOTE_ADDR 表示訪客 IP ,如果使用代理訪問則顯示代理 IP
- HTTP_X_FORWARDED_FOR 表示訪客 IP ,如果不使用代理訪問則爲空
- HTTP_CLIENT_IP 表示代理服務器 IP ,如果不使用代理訪問則爲空
PS: REMOTE_ADDR 是無法更改的,而 HTTP_X_FORWARDED_FOR 、 HTTP_CLIENT_IP 是由客戶端(一般指代理服務器)自行設定的。
3.根據不同需求選擇不同方案
對於IP地址的獲取和使用,我們應該根據業務和需求去獲取用戶的IP地址。
3.1投票系統/活動
做投票系統/活動的時候最主要的是防止刷票,所以推薦使用使用$_SERVER["REMOTE_ADDR"]去獲取客戶 IP ,因爲通過HTTP_X_FORWARDED_FOR 、 HTTP_CLIENT_IP 獲取到的IP有可能是刷票者僞造的,而$_SERVER["REMOTE_ADDR"]是最穩妥的。
3.2網站訪問統計
此時應該使用我們封裝的函數去獲取用戶的IP地址,以便訪客通過代理服務器訪問網站時能獲取到訪客的真實 IP,如果你認爲網絡比較複雜,你可以同時存儲REMOTE_ADDR、HTTP_X_FORWARDED_FOR和HTTP_CLIENT_IP 。