一、获取客户端ip代码
php
/**
* @description: 获取客户端IP
* @return string
*/
public static function getClientIp()
{
$ip = '';
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'),'unknown'))
{
$ip = getenv('HTTP_CLIENT_IP');
}
else if(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'),'unkown'))
{
$ip = getenv('HTTP_X_FORWARDED_FOR');
//线上环境,反向代理,ip会记录前置代理的ip(ip1, ip2, ip3),取第一个真正请求的ip验证
$ipArr = explode(',',$ip);
$ip = trim($ipArr[0]);
}
else if(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'),'unkown'))
{
$ip = getenv('REMOTE_ADDR');
}
else if(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp(getenv('REMOTE_ADDR'),'unkown'))
{
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
二、遇到的问题
1、通过步骤一中获取客户端ip的方法,ajax请求获取到的客户端的ip是服务端的ip地址;
经最后排查,ajax请求链接在nginx中设置了反向代理
需要在nginx中配置'proxy_set_header X-Forwarded-For proxy_add_x_forwarded_for;'后,在php中使用_SERVER['HTTP_X_FORWARDED_FOR']才能取到代理前的客户端ip
具体nginx配置如下:
php
xc.test.com.conf配置内容:
location ^~ /ajax/ {
proxy_set_header Host www.test.com;
proxy_pass http://www.test.com;
proxy_set_header RealHost $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
2、配置完成重启nginx
内网环境$_SERVER['HTTP_X_FORWARDED_FOR']获取到ip是单个ip地址,确实是客户端ip
正式环境$_SERVER['HTTP_X_FORWARDED_FOR']获取到的是ip串,ip之间有**,空格**分隔
ip1, ip2, ip3
其中ip1是真实的客户端ip地址,ip2和ip3是代理ip地址,正式环境网关走了几次代理,便会有几个ip拼接,这种情况获取客户端ip,需要取第一个ip1,详见步骤一种的代码处理。
三、延伸
* REMOTE_ADDR 客户端跟服务器"握手"时候的IP。如果使用了"匿名代理",REMOTE_ADDR将显示代理服务器的IP。(这个情况就和我遇到的问题一致,nginx里没有设置HTTP_X_FORWARDED_FOR,_SERVER\['HTTP_X_FORWARDED_FOR'\]为空,便读取了_SERVER['REMOTE_ADDR']的值,即代理服务器的ip)
* HTTP_CLIENT_IP 是代理服务器发送的HTTP头。如果是"超级匿名代理",则返回none值。同样,REMOTE_ADDR也会被替换为这个代理服务器的IP。
* $_SERVER['REMOTE_ADDR']; //访问端(有可能是客户端ip,有可能是代理的ip)IP
* $_SERVER['HTTP_CLIENT_IP']; //代理端的(有可能存在,可伪造)
* $_SERVER['HTTP_X_FORWARDED_FOR']; //用户是在哪个IP使用的代理(有可能存在,也可以伪造)