1. 程式人生 > >php 獲取客戶端的真實IP地址 和 檢查客戶端從什麼地方過來的請求

php 獲取客戶端的真實IP地址 和 檢查客戶端從什麼地方過來的請求

/*
 * 函式功能: 獲取客戶端的真實IP地址 * 
 * 為什麼要用這個函式?
 * 因為我們線上Web伺服器絕大部分都處於Netscaler(簡稱NS)後面,客戶端訪問的地址統一由NS排程 * NS排程的訪問其實就是NS做了一層代理, 這期間就有一個問題, 因為真實的地址是內部IP請求的 * 當我們的應用去請獲取 $_SERVER["REMOTE_ADDR"] 的時候, 得到的就是 NS 的內部 IP, 獲取不了 * 真正的客戶端 IP 地址.
 * 
 * 當請求經過 NS 排程之後, NS 會把客戶端的真實 IP 附加到 HTTP_CLIENT_IP 後,我們要提取的就 * 是這個地址
. * * 如測試資料: * [HTTP_CLIENT_IP] => 192.168.2.251, 192.168.3.252, 218.82.113.110 * 這條資訊是我測試的結果, 前面兩個 IP 是我偽造的, 最後那個 IP 才是我真實的地址. * * 同樣我也測試過通過代理的資料 * [HTTP_X_FORWARDED_FOR] => 192.168.2.179, 123.45.67.78 64.191.50.54 * 前面兩個IP是我偽造的, 最後面那個地址才是 proxy 的真實地址 * * 提醒: * HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR
都可以在客戶端偽造, 不要輕易直接使用這兩個值, 因為 * 惡意使用者可以在裡面輸入PHP程式碼, 或者像偽造 N ', 讓你的程式執行有問題, 如果要直接使用這 * 兩個值的時候最簡單的應該判斷一下長度(最長15), 或用正則匹配一下是否是一個有效的IP地址 * * 引數: * * @param string $proxy_override, [true|false], 是否優先獲取從代理過來的地址 * @return string * */ function get_client_ip_from_ns($proxy_override = false) { if ($proxy_override
) { /* 優先從代理那獲取地址或者 HTTP_CLIENT_IP 沒有值 */ $ip = empty($_SERVER["HTTP_X_FORWARDED_FOR"]) ? (empty($_SERVER["HTTP_CLIENT_IP"]) ? NULL : $_SERVER["HTTP_CLIENT_IP"]) : $_SERVER["HTTP_X_FORWARDED_FOR"]; } else { /* HTTP_CLIENT_IP, 雖然這個值可以被偽造, 但被偽造之後 NS 會把客戶端真實的 IP 附加在後面 */ $ip = empty($_SERVER["HTTP_CLIENT_IP"]) ? NULL : $_SERVER["HTTP_CLIENT_IP"]; } if (empty($ip)) { $ip = $_SERVER['REMOTE_ADDR']; } /* 真實的IP在以逗號分隔的最後一個, 當然如果沒用代理, 沒偽造IP, 就沒有逗號分離的IP */ if ($p = strrpos($ip, ",")) { $ip = substr($ip, $p+1); } return trim($ip); } /* * 檢查客戶端從什麼地方過來的請求 * * <code> * // 嚴格檢查此頁面來源中域名必須包含 .dod.com * if (!check_client_referer(true, '.dod.com')) { * die('非法提交的資料'); * } * // 鬆散檢查來源url中必須包含.51.com * if (!check_client_referer()) { * die('非法提交的資料'); * } * </code> * * @param bool $restrict 是否進行嚴格的查檢, 此方式為用正則對host進行匹配 * @param string $allow 允許哪些 referer 過來請求 * @return true / false 在允許的列表內返回true * */ function check_client_referer($restrict = true, $allow = '.xx5.com') { $referer = isset($_SERVER['HTTP_REFERER']) ? trim($_SERVER['HTTP_REFERER']) : null; if (empty($referer)) { return true; } /* 空的 referer 直接允許 */ if ($restrict) { /* 更加嚴格的查檢, 此值為true, allow 可以輸入正則來匹配 */ $url = parse_url($referer); /* host 為空時直接返回不false */ if (empty($url['host'])) { return false; } /* 將正則中的.替換掉為\.真正匹配.再進行匹配 */ $allow = '/'.str_replace('.', '\.', $allow).'/'; return 0 < preg_match($allow, $url['host']); } return false !== strpos($referer, $allow); } ?>