【发布时间】:2012-11-18 18:15:27
【问题描述】:
我正在使用这个 PHP 代码来获取访问者的 IP 地址:
<?php echo $_SERVER['REMOTE_ADDR']; ?>
但是,当他们使用代理时,我无法从访问者那里获得真实的 IP 地址。。在这种情况下,有什么方法可以获取访问者的 IP 地址吗?
【问题讨论】:
-
如果代理不是完全匿名的,您只能从代理获取真实 ip,否则您将获得的只是代理 ip
我正在使用这个 PHP 代码来获取访问者的 IP 地址:
<?php echo $_SERVER['REMOTE_ADDR']; ?>
但是,当他们使用代理时,我无法从访问者那里获得真实的 IP 地址。。在这种情况下,有什么方法可以获取访问者的 IP 地址吗?
【问题讨论】:
试试这个 php 代码。
<?PHP
function getUserIP()
{
// Get real visitor IP behind CloudFlare network
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
$_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
}
$client = @$_SERVER['HTTP_CLIENT_IP'];
$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = $_SERVER['REMOTE_ADDR'];
if(filter_var($client, FILTER_VALIDATE_IP))
{
$ip = $client;
}
elseif(filter_var($forward, FILTER_VALIDATE_IP))
{
$ip = $forward;
}
else
{
$ip = $remote;
}
return $ip;
}
$user_ip = getUserIP();
echo $user_ip; // Output IP address [Ex: 177.87.193.134]
?>
【讨论】:
HTTP_CLIENT_IP 和HTTP_X_FORWARDED_FOR 可以被伪造。只有REMOTE_ADDR 不能。
这是我见过的最常见的技术:
function getUserIP() {
if( array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) ) {
if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',')>0) {
$addr = explode(",",$_SERVER['HTTP_X_FORWARDED_FOR']);
return trim($addr[0]);
} else {
return $_SERVER['HTTP_X_FORWARDED_FOR'];
}
}
else {
return $_SERVER['REMOTE_ADDR'];
}
}
请注意,它并不能保证您将始终获得正确的用户 IP,因为有很多方法可以隐藏它。
【讨论】:
HTTP_X_FORWARDED_FOR 标头的少数解决方案之一,如果请求通过一个或多个代理(根据en.wikipedia.org/wiki/X-Forwarded-For#Format),该标头可能包含逗号分隔的列表(根据en.wikipedia.org/wiki/X-Forwarded-For#Format)
HTTP_X_FORWARDED_FOR 标头,因此最好使用filter_var(trim($addr), FILTER_VALIDATE_IP) 对其进行测试,以确保在返回它之前至少有一个有效的IP 地址。
这是我的方法:
function getRealUserIp(){
switch(true){
case (!empty($_SERVER['HTTP_X_REAL_IP'])) : return $_SERVER['HTTP_X_REAL_IP'];
case (!empty($_SERVER['HTTP_CLIENT_IP'])) : return $_SERVER['HTTP_CLIENT_IP'];
case (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) : return $_SERVER['HTTP_X_FORWARDED_FOR'];
default : return $_SERVER['REMOTE_ADDR'];
}
}
使用方法:
$ip = getRealUserIp();
【讨论】:
代理可能会发送 HTTP_X_FORWARDED_FOR 标头,但即使这样也是可选的。
另外请记住,访问者可能会共享 IP 地址;大学网络、大公司和第三世界/低预算 ISP 倾向于与许多用户共享 IP。
【讨论】:
应用此代码获取 IP 地址:
if (getenv('HTTP_X_FORWARDED_FOR')) { $pipaddress = getenv('HTTP_X_FORWARDED_FOR');
$ipaddress = getenv('REMOTE_ADDR');
echo "Your Proxy IP address is : ".$pipaddress. "(via $ipaddress)" ; }
else { $ipaddress = getenv('REMOTE_ADDR'); echo "Your IP address is : $ipaddress"; }
------------------------------------------------------------------------
【讨论】:
这是我的功能。
好处:
/**
* Get real user ip
*
* Usage sample:
* GetRealUserIp();
* GetRealUserIp('ERROR',FILTER_FLAG_NO_RES_RANGE);
*
* @param string $default default return value if no valid ip found
* @param int $filter_options filter options. default is FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
*
* @return string real user ip
*/
function GetRealUserIp($default = NULL, $filter_options = 12582912) {
$HTTP_X_FORWARDED_FOR = isset($_SERVER)? $_SERVER["HTTP_X_FORWARDED_FOR"]:getenv('HTTP_X_FORWARDED_FOR');
$HTTP_CLIENT_IP = isset($_SERVER)?$_SERVER["HTTP_CLIENT_IP"]:getenv('HTTP_CLIENT_IP');
$HTTP_CF_CONNECTING_IP = isset($_SERVER)?$_SERVER["HTTP_CF_CONNECTING_IP"]:getenv('HTTP_CF_CONNECTING_IP');
$REMOTE_ADDR = isset($_SERVER)?$_SERVER["REMOTE_ADDR"]:getenv('REMOTE_ADDR');
$all_ips = explode(",", "$HTTP_X_FORWARDED_FOR,$HTTP_CLIENT_IP,$HTTP_CF_CONNECTING_IP,$REMOTE_ADDR");
foreach ($all_ips as $ip) {
if ($ip = filter_var($ip, FILTER_VALIDATE_IP, $filter_options))
break;
}
return $ip?$ip:$default;
}
【讨论】:
如果Proxy是你信任的,你可以试试:(假设Proxy IP是151.101.2.10)
<?php
$trustProxyIPs = ['151.101.2.10'];
$clientIP = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL;
if (in_array($clientIP, $trustProxyIPs)) {
$headers = ['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR'];
foreach ($headers as $key => $header) {
if (isset($_SERVER[$header]) && filter_var($_SERVER[$header], FILTER_VALIDATE_IP)) {
$clientIP = $_SERVER[$header];
break;
}
}
}
echo $clientIP;
这将防止直接请求的客户端伪造转发标头,并通过受信任的代理获取真实 IP。
【讨论】:
是的,$_SERVER["HTTP_X_FORWARDED_FOR"] 是我在 nginx 服务器上的代理下查看我的 ip 的方式。
但最好的办法是在代理下请求的页面上运行phpinfo(),这样您就可以查看所有可用变量并查看带有您真实 IP 的变量。
【讨论】:
这适用于 Windows 和 Linux!不管是本地主机还是在线..
function getIP() {
$ip = $_SERVER['SERVER_ADDR'];
if (PHP_OS == 'WINNT'){
$ip = getHostByName(getHostName());
}
if (PHP_OS == 'Linux'){
$command="/sbin/ifconfig";
exec($command, $output);
// var_dump($output);
$pattern = '/inet addr:?([^ ]+)/';
$ip = array();
foreach ($output as $key => $subject) {
$result = preg_match_all($pattern, $subject, $subpattern);
if ($result == 1) {
if ($subpattern[1][0] != "127.0.0.1")
$ip = $subpattern[1][0];
}
//var_dump($subpattern);
}
}
return $ip;
}
【讨论】:
exec(),并且没有理由太复杂。获取访问者的IP并不需要这么多。即使你用它来获取服务器IP,也应该是3行短代码,涵盖windows服务器和linux。