如何在PHP中编写检查访问者IP地址的功能?

4

我仍然对这个主题感到困惑,希望得到关于如何通过PHP检查访问者IP地址的任何帮助和参考。

我知道在编写代码之前询问问题似乎有些懒惰,但现在我也正在搜索相关信息。希望有人能给出一般性的答案或一些阅读链接?

顺便说一下,当我们需要编写这样的功能时,需要考虑什么?

PS:非常感谢大家。这是启发性的争论。说实话,我更倾向于选择那些给答案带来了尊重而不是真相的答案。因为直到现在,我还不知道正确的答案。或许在我对该主题本身有一个扎实的理解之前,我需要更多年的学习。


1
https://dev59.com/-HI-5IYBdhLWcg3w3cnS - Mike B
@Mike 最好不要链接那段代码。 - Your Common Sense
1
@Col 因为...?无论接受的答案如何,我们能否同意实际问题几乎相同? - Mike B
2
因为所有点赞的人都不知道这个问题。任何只返回一个IP地址且该地址不是REMOTE_ADDR的代码都是错误的。因为PHP拥有的唯一IP地址(在TCP/IP协议方面)就是REMOTE_ADDR。其余的只是HTTP头。 - Your Common Sense
8个回答

6

请参阅$_SERVER,特别是:

$_SERVER['REMOTE_ADDR'];

1
如果您的客户端正在通过代理服务器浏览,则 $_SERVER['REMOTE_ADDR'] 只会返回代理服务器的 IP 地址,而不是客户机器的 IP 地址。这并不是非常可靠的。这可能是一个更好的解决方案:https://dev59.com/mUzSa4cB1Zd3GeqPpMLv#2505718但是,请注意获取 IP 地址永远不是完全可靠的:https://dev59.com/30rSa4cB1Zd3GeqPTyAT#1678748 - Mathias Bynens
1
@Mathais Bynens:比你可能尝试检测到的任何HTTP头都要可靠,而且不需要大量的代码。 - jasonbar

5

好的,justjoe,我看到你对这个参数感到困惑,我在其中起了很大的作用。

以下是更多的解释。

答案取决于任务。你有两个选择:

如果你只需要一个IP地址,你可以只使用REMOTE_ADDR而不使用其他任何参数。查看Web服务器的访问日志:只有一个IP地址,即REMOTE_ADDR。至少它能保证你得到一个有效的IP地址。在许多情况下,比如流量计数器,这是唯一可靠的方法。这是“如何获取IP地址”的通用答案。

如果你想记录一个可能更精确的地址,那么你可以记录多个地址,而不是一个。但是,你必须连同REMOTE_ADDR一起记录这些HTTP头信息,而不是替代它。这些地址有一些用处。但是你不能过分依赖它们。但是如果你关心的话,你可以从中挖掘一些信息。

FORWARDED_FOR头的唯一用途是当一个Web服务器配置错误时,将真实的IP地址放入此变量中。在这种情况下,它可以被用作IP地址。但是当然,这必须在每个特定的情况下手动完成,而不是作为一般建议。但无论如何,我会退出这样的Web服务器,因为它里面不能只有一个配置错误。


非常感谢您的解释。现在我明白了在创建此类功能时需要考虑什么。我将使用它来跟踪用户。关于IP范围,我认为我只需要一个。拥有正确的IP很重要,但代码不必具有真实的IP。一切都将存储在数据库中。这更像是手动黑名单/白名单功能。 - justjoe
我正在使用xampp在本地php开发环境中测试获取引用网站IP地址,但是这段代码没有显示IP - var_dump("ip=".$_SERVER['REMOTE_ADDR']); 但是这段代码显示了它 - var_dump(gethostbyname("传递此处的网站地址")); 那么哪种方法是正确的? - dev-m
@devm 参考站点与 IP 地址无关。这个地址不属于一个站点,而是属于一个访问者。 - Your Common Sense

4
为了获取用户的IP地址,您应该使用以下内容:
$ip = $_SERVER['REMOTE_ADDR']

1
如果您的客户端正在通过代理服务器浏览,则 $_SERVER['REMOTE_ADDR'] 只会返回代理服务器的 IP 地址,而不是客户机器的 IP 地址。这并不是非常可靠的。这可能是一个更好的解决方案:https://dev59.com/mUzSa4cB1Zd3GeqPpMLv#2505718但是,请注意获取 IP 地址永远不是完全可靠的:https://dev59.com/30rSa4cB1Zd3GeqPTyAT#1678748 - Mathias Bynens
@Mathias 好的,你最终能决定哪一个是“不太可靠”的吗?HTTP头怎么可能比IP地址更可靠呢? - Your Common Sense
当用户使用代理服务器时,您将在此处找到答案。function getRealIpAddr() { if (!empty($_SERVER['HTTP_CLIENT_IP'])) //检查共享互联网的IP地址 { $ip=$_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //检查是否通过代理传递了IP地址 { $ip=$_SERVER['HTTP_X_FORWARDED_FOR']; } else { $ip=$_SERVER['REMOTE_ADDR']; } return $ip; }该函数的第一次尝试是获取客户端机器的直接IP地址,如果不可用,则尝试使用HTTP_X_FORWARDED_FOR获取转发的IP地址。 - Sanjay Khatri
你选择的不是IP地址,而是HTTP头。 - Your Common Sense

2
如果您的客户端正在通过代理服务器浏览,则$_SERVER ['REMOTE_ADDR']只会返回代理服务器的IP地址,而不是客户机器的IP地址。这并不是非常可靠的。以下可能是更好的解决方案:
function get_ip_address() {
 foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
  if (array_key_exists($key, $_SERVER)) {
   foreach (explode(',', $_SERVER[$key]) as $ip) {
    $ip = trim($ip); // just to be safe
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
     self::$ip = $ip;
     return $ip;
    }
   }
  }
 }
}

这个问题在 Stack Overflow 上已经讨论过了。请参考 “What is the most accurate way to retrieve a user’s correct IP address in PHP?”。上述代码是该问题被接受答案的优化版本。
然而,请注意获取 IP 地址永远不是完全可靠的:php / ajax REMOTE_ADDR set to IP of bogus network adapter

2
@Col称代码愚蠢并表示它没有回答问题是两码事。 - Mike B
1
@Mathias 1. 如同HTTP头部那样轻松地欺骗 IP 地址。2. IP 地址始终比 HTTP 头部更可靠。3. 这段代码尝试了但失败了。 - Your Common Sense
1
@Col,你能用多少种不同的表达方式来解释同一件事情呢?我要求你解释为什么除了REMOTE_ADDR以外使用其他东西都是不明智的,但你似乎只会简单地回应侮辱性言辞。我并不想引发宗教争论。我相信你有非常好的理由。我只是想找出这个原因是什么。 - Mike B
2
插一句话... REMOTE_ADDR不可欺骗的。它是TCP/IP协议在三次握手中确认的地址,以建立双向连接,因此您的服务器可以将某些内容发送回客户端。另一方面,HTTP标头由客户端设置,可以是任何内容。此外,您有什么理由查看代理后面的内容,您能获得什么?可能是一堆10.0.1.x地址,这对您也没有什么帮助。 - deceze
1
@Mathias 如果有人想要隐藏他的地址,他会使用一个匿名代理,该代理不会在HTTP头中转发真实地址。你可能只会得到一些内部IP地址,这些地址是企业网络通过代理路由所有出站流量时转发的。而这些地址对你来说并没有什么帮助。 - deceze
显示剩余12条评论

2

一般而言,与客户端相关的所有PHP信息都存储在$_SERVER变量中。因此,每当您想要查看特定信息时,请执行以下代码以查找相关信息:

echo "<pre>";
print_r($_SERVER);
echo "</pre>";
//or just
phpinfo(32);

$_SERVER['REMOTE_ADDR'] 是唯一可以获取的IP地址,尽管它可能不是“客户端地址”。


1

以下内容可达到目的。

$ip = $_SERVER['REMOTE_ADDR'];

echo "IP address is : " :.$ip;

-1
我建议您使用第三方IP地址到地理位置转换器来计算位置。这样,您就不必承担数据库空间、准确性和查询的负担。
您所需要做的就是像这样:
http://third-party-url.com?ip=IP_ADDRESS

它会返回XML或数据数组。

你可以随后使用它来做任何你想做的事情。

这里有两个受欢迎的网站。 * 我的IP地址查询和地理定位 * SimpleGeo

还有很多类似的网站.. 也许其他人可以在这里添加它们。


-1

只需在您的代码顶部使用此代码:

if (function_exists('apache_request_headers'))
{
    $headers = apache_request_headers();

    if (array_key_exists('X-Forwarded-For', $headers))
    {
        $ips = explode(',',$headers['X-Forwarded-For'],2);
        $_SERVER["REMOTE_ADDR"]= trim($ips[0]);
    }
}

它将确保在负载均衡应用程序中,$_SERVER["REMOTE_ADDR"]始终保持正确的IP地址。


始终保留错误的 IP,以防万一没有任何配置错误的负载均衡器。 - Your Common Sense
如果存在X-Forwarded-For,那么你怎么可能有配置错误的负载均衡器呢?此外,如果你关心这样的事情,你可能也不会使用负载均衡器,这意味着上述代码对你也不适用... - Marcin
因为X-Forwarded-For并不是你可能认为的负载均衡器独有的功能,而只是非常常见的HTTP头部,可以被任何代理或路由器添加。 - Your Common Sense

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接