我的网站采取的是nginx+apache+php+mysql(
部署在同一台服务器)
nginx作为前端,反向代理到apache,通过apache处理php,apache和php获取客户端IP为
127.0.0.1
因为是在同一台服务器,通过nginx访问apache,这时就相当于nginx作为客户端(浏览器)访问了apache一样,所以获取IP时,获取到的是
127.0.0.1
可以通过修改nginx和apache的配置文件达到获取真实IP
nginx配置文件添加(nginx.conf): proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location块添加这三行。
apache主要修改格式化日志的字符串(httpd.conf):LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
修改为:
LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
php可以通过以下代码获取真实IP:$_SERVER['HTTP_X_FORWARDED_FOR']
参照官方wecenter3.1.3版本,system/functions.inc.php的fetch_ip函数(81行)
其实官方也已经完全考虑到了代理问题,官方的fetch_ip函数已经对代理IP做了处理,有兴趣的可以自己扒扒代码。
但是处理的时候漏判了127.0.0.1这种状态
官方是先判断代理IP是否能获取,如果能获取,则在判断$_SERVER['REMOTE_ADDR']是否为内网IPif ($_SERVER['HTTP_X_FORWARDED_FOR'] and valid_internal_ip($_SERVER['REMOTE_ADDR']))
{
$ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
上面是官方代码,可以看到调用了valid_internal_ip函数,问题就出现在valid_internal_ip函数中,因为nginx和apache、php都在同一台服务器,$_SERVER['REMOTE_ADDR']获取到的IP是127.0.0.1,而valid_internal_ip只判断了以10、172.16-172.31、192.168开头的IP,并没有判断127.0.0.1,所以fetch_ip函数获取的ip是127.0.0.1
解决方法很简单,添加对127.0.0.1判断即可,在valid_internal_ip函数的122行添加下面3行代码:
if($ip === '127.0.0.1') {
return true;
}
添加完valid_internal_ip函数的部分代码:
if (!valid_ip($ip))
{
return false;
}
if($ip === '127.0.0.1') {
return true;
}
$ip_address = explode('.', $ip);
if ($ip_address[0] == 10)
{
return true;
}
当然,这种方式并不是最完美的方式,没有考虑到更多的场景和情况,比如IPV6、localhost的判断等。不过已经能应付大部分的情景。
反馈给官方,希望wecenter越做越好!!!!!!
阅读全文
收起全文