前言:我们在使用PHP获取的IP可能是客户端真实的IP,也可能是代理服务器的IP,也有可能根本取不到任何IP值。
如果客户端是使用代理服务器来访问,那 $_SERVER["REMOTE_ADDR"] 取到的是代理服务器的IP地址,而不是真正的客户端IP。如果想透过代理服务器取得客户端的真实IP,就要使用 $_SERVER["HTTP_X_FORWARDED_FOR"] ,但客户端必须使用“透明代理”的情况下,$_SERVER["HTTP_X_FORWARDED_FOR"]才是客户端真正的IP(如是多层代理,该值可能是由客户端真实IP和多个代理服务器的IP并由逗号分隔),而在“匿名代理”、“欺骗性代理”的情况下是代理服务器的IP(如果是多层代理,该值可能由逗号隔开的多个代理服务器的IP组成),此外在“高匿名代理”的情况下是空值。
具体情况如下:
1.没有使用代理服务器:$_SERVER['REMOTE_ADDR']是真实ip,$_SERVER['HTTP_X_FORWARDED_FOR']无值或不存在;
2.透明代理服务器(Transparent Proxies):最后一 $_SERVER['REMOTE_ADDR']个代理服务器ip,$_SERVER['HTTP_X_FORWARDED_FOR']是由真实ip和代理ip用逗号隔开组成的;
3.普通匿名代理服务器(Anonymous Proxies):$_SERVER['REMOTE_ADDR']是最后一个代理服务器ip,$_SERVER['HTTP_X_FORWARDED_FOR']是由多个代理ip用逗号隔开组成的,向访问对象透露了客户端是使用代理服务器;
4.欺骗性代理服务器(Distorting Proxies):$_SERVER['REMOTE_ADDR']是代理服务器ip,$_SERVER['HTTP_X_FORWARDED_FOR']是由多个代理ip用逗号隔开组成的,同样透露了客户端是使用了代理服务器,但编造了一个虚假的随机IP代替客户端的真实IP来欺骗它;
5.高匿名代理服务器(High Anonymity Proxies ):无论是REMOTE_ADDR还是HTTP_FORWARDED_FOR,这些头消息未必能够取得到,因为不同的浏览器不同的网络设备可能发送不同的IP头消息,这种情况获取的ip可能是空值也科也可能是“unknown”。
获取ip的代码实现如下:
function get_real_ip() { //代理服务器 if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] && strcasecmp( $_SERVER['HTTP_X_FORWARDED_FOR'], 'unknown' ) ) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif ( isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp( $_SERVER['REMOTE_ADDR'], 'unknown' ) ) { $ip = $_SERVER['REMOTE_ADDR']; } //代理服务器的情况 if ( false !== strpos($ip, ',') ){ $ip = reset(explode(',', $ip)); } return $ip; }
注意:PHP获取客户端IP时另外一点需注意,使用函数getenv(’HTTP_X_FORWARDED_FOR’)或getenv(’REMOTE_ADDR’) 也可以如上代码一样取得同样的效果。但getenv()不支持在IIS的isapi方式下运行的PHP。