nginx反向代理下thinkphp、php獲取不到正確的外網ip,nginxthinkphp
在記錄用戶發送短信需要獲取用戶ip時,tp一直獲取的是內網ip:10.10.10.10
tp框架獲取ip方法:get_client_ip

![]()
1 /**
2 * 獲取客戶端IP地址
3 * @param integer $type 返回類型 0 返回IP地址 1 返回IPV4地址數字
4 * @param boolean $adv 是否進行高級模式獲取(有可能被偽裝)
5 * @return mixed
6 */
7 function get_client_ip($type = 0,$adv=false) {
8 $type = $type ? 1 : 0;
9 static $ip = NULL;
10 if ($ip !== NULL) return $ip[$type];
11 if($adv){
12 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
13 $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
14 $pos = array_search('unknown',$arr);
15 if(false !== $pos) unset($arr[$pos]);
16 $ip = trim($arr[0]);
17 }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
18 $ip = $_SERVER['HTTP_CLIENT_IP'];
19 }elseif (isset($_SERVER['REMOTE_ADDR'])) {
20 $ip = $_SERVER['REMOTE_ADDR'];
21 }
22 }elseif (isset($_SERVER['REMOTE_ADDR'])) {
23 $ip = $_SERVER['REMOTE_ADDR'];
24 }
25 // IP地址合法驗證
26 $long = sprintf("%u",ip2long($ip));
27 $ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
28 return $ip[$type];
29 }
View Code
因一些原因,w項目是在Apache下,後來另外一些項目擠進來使用了nginx,nginx下的項目需要也微信80端口授權,所以使用了反向代理。
經過反向代理後,由於在客戶端和web服務器之間增加了中間層,因此web服務器無法直接拿到客戶端的ip,通過$remote_addr變量拿到的將是反向代理服務器的ip地址
tp框架自帶函數獲取的是$remote_addr,所以我們沒辦法獲取真實ip。
打開/usr/local/reverse_proxy_nginx/conf/nginx.conf 可以看到如下關鍵配置
location / {
proxy_pass http://backend2;
#Proxy Settings
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
測試
$remoteaddr=$_SERVER["REMOTE_ADDR"];
echo $remoteaddr;
echo "---";
$remotehost=$_SERVER["REMOTE_HOST"];
echo $remotehost;
echo "---";
$xforwardedfor=$_SERVER["HTTP_X_FORWARDED_FOR"];
echo $xforwardedfor;
echo "---";
$xrealip=$_SERVER["HTTP_X_REAL_IP"];
echo $xrealip;
輸出
10.10.10.123------181.128.136.191---181.128.136.191
181.128.136.191便是你真實的外網ip,所以只需要獲取HTTP_X_FORWARDED_FOR或者HTTP_X_REAL_IP就可以了。
下面是修改後的tp框架函數
ThinkPHP\Common\functions.php

![]()
1 /*
2 * 訪問時用localhost訪問的,讀出來的是“::1”是正常情況。
3 * ::1說明開啟了ipv6支持,這是ipv6下的本地回環地址的表示。
4 * 使用ip地址訪問或者關閉ipv6支持都可以不顯示這個。
5 */
6 function get_client_ip() {
7 $ip = "unknown";
8 if (isset($_SERVER)) {
9 if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
10 $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
11 } elseif (isset($_SERVER["HTTP_CLIENT_ip"])) {
12 $ip = $_SERVER["HTTP_CLIENT_ip"];
13 } else {
14 $ip = $_SERVER["REMOTE_ADDR"];
15 }
16 } else {
17 if (getenv('HTTP_X_FORWARDED_FOR')) {
18 $ip = getenv('HTTP_X_FORWARDED_FOR');
19 } elseif (getenv('HTTP_CLIENT_ip')) {
20 $ip = getenv('HTTP_CLIENT_ip');
21 } else {
22 $ip = getenv('REMOTE_ADDR');
23 }
24 }
25 if(trim($ip)=="::1"){
26 $ip="127.0.0.1";
27 }
28 return $ip;
29 }
View Code
Apache下的tp項目,再調用get_client_ip函數就可正常獲取外網ip了