- 本文地址: https://www.yangdx.com/2019/02/10.html
- 转载请注明出处
函数如下:
/**
* 获取客户端IP
* @return string
*/
function getClientIp() {
$keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];
foreach ($keys as $key) {
if (isset($_SERVER[$key])) {
$ip = array_filter(explode(', ', $_SERVER[$key]));
$ip = filter_var($ip[0], FILTER_VALIDATE_IP);
if ($ip) {
return $ip;
}
}
}
return '';
}
分析:
按顺序依次判断$_SERVER['HTTP_X_FORWARDED_FOR']、$_SERVER['HTTP_CLIENT_IP']、$_SERVER['REMOTE_ADDR']这三个变量,如果有值就马上返回。
翻开PHP手册,查看$_SERVER数组的解释,你会发现,手册里居然没有HTTP_X_FORWARDED_FOR、HTTP_CLIENT_IP这两个元素,只有REMOTE_ADDR的解释。
首先,$_SERVER数组以HTTP_开头的元素,是来自客户端的header头信息,也就是说,它们是客户端传给服务器的。因此,这些值是可以伪造的,是不安全的!但是,这并不代表它们就没有用处。
解释如下:
- HTTP_X_FORWARDED_FOR 是有标准定义,用来识别经过HTTP代理后的客户端IP地址,多级代理的话IP以 英文逗号+空格 分隔,格式:clientip, proxy1, proxy2。详细解释见 http://zh.wikipedia.org/wiki/X-Forwarded-For
- HTTP_CLIENT_IP 未成标准,不一定服务器都实现了。
- REMOTE_ADDR 是最后一个跟你的服务器握手的IP,可能是用户的代理服务器,也可能是你自己的反向代理。
如果你的服务器是直接暴露在公网,允许用户直连,那单独用$_SERVER['REMOTE_ADDR']就可以获取到用户的真实IP。
如果你的服务器是经过nginx反向代理,那就要用$_SERVER['HTTP_X_FORWARDED_FOR']判断。最后一个地址是最后一个代理服务器的IP,这通常是一个比较可靠的信息来源。但前提是nginx有设置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
HTTP_X_FORWARDED_FOR 是有标准定义,用来识别经过HTTP代理后的客户端IP地址,多级代理的话IP以 英文逗号+空格 分隔,格式:clientip, proxy1, proxy2
这里的 clientip 才是 用户真实ip 所以
$ip = filter_var(end($ip), FILTER_VALIDATE_IP);
这里应该改为
ip = filter_var($ip[0], FILTER_VALIDATE_IP);
博主回复:
感谢指正!