PHP:如何检查客户端是不是是本地的?
Posted
技术标签:
【中文标题】PHP:如何检查客户端是不是是本地的?【英文标题】:PHP: how to check if the client is local?PHP:如何检查客户端是否是本地的? 【发布时间】:2011-10-23 08:56:40 【问题描述】:我需要检查文件是否在“本地”(同一台机器或网络)打开。我正在使用:
<?php
if ((substr($_SERVER['REMOTE_ADDR'],0,8) == "192.168.") || ($_SERVER['REMOTE_ADDR'] == "127.0.0.1"))
// client is local
else
// client is not local
但我不确定这是不是最好的方法。
有什么更简单的方法?
【问题讨论】:
在这里您将自己限制为 IPv4。如今,这还不够。您应该 a) 也熟悉 IPv6,并且 b) 定义定义列表什么是“本地”:真的只有 192.168.*?如果您在具有自己 IP 的网络中怎么办?还是在 10.* 网络内? How to know if an IP is external or not? 的可能重复项 【参考方案1】:Friek 说的是真的,但前提是你知道如何获取真实客户端的 IP,你可以使用 PHP filters 判断它是否是本地地址:
if ( ! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) )
// is a local ip address
【讨论】:
如果真正的客户端 IP 是 IPv6,这将不起作用。 它应该根据 2010 年的这个问题工作:bugs.php.net/bug.php?id=47435【参考方案2】:“万无一失”,一如既往,可能很棘手。
如果我们确实限制自己使用 IPv4,则检查“127.0.0.1”会处理 localhost 的情况,但会检查“192.168”。完全错误 - 只有在恰好位于 192.168 网络的服务器上运行脚本时,它才会使用 16 位子网掩码。
对照 $_SERVER['SERVER_ADDR'] 检查 $_SERVER['REMOTE_ADDR'] 会是更好的选择。不过,这仍然不能解决多宿主主机(即除了 127.0.0.1 之外还有多个 IP 地址的主机)的情况。
为了捕获所有相同网络的情况,您需要根据 REMOTE_ADDR 检查 SERVER_ADDR 和子网掩码的组合,但子网掩码在 $_SERVER 中不可用。
但是我找到了一个功能,它几乎可以满足您的需求here。这是几个屏幕,它被称为clientInSameSubnet。不是我的代码,但看起来不错。
【讨论】:
检查 $_SERVER['SERVER_ADDR'] 是个坏主意。在 rfc1918 空间中拥有虚拟主机并不一定意味着客户端也来自该空间。例如,有负载均衡结构,其中节点位于私有子网中,而负载均衡器具有“公共”IP(请参阅linuxvirtualserver.org/VS-NAT.html) 你肯定有一个观点,正如我所说,万无一失并不容易。但是比问题中引用的代码要好,而且涵盖了常见的情况。 @Uffe, 那么我们如何从 PHP 中获取与子网掩码相关的信息呢? 尝试使用客户端 IP=192.168.10.10
和服务器 IP=192.168.10.1
运行 clientInSameSubnet()
函数,它返回 false。我是否误解了该功能的作用?好像应该是真的……【参考方案3】:
如果有人无法找到@Uffe 建议的上述代码,我将其包含在下面:
<?php
/**
* Check if a client IP is in our Server subnet
*
* @param string $client_ip
* @param string $server_ip
* @return boolean
*/
function clientInSameSubnet($client_ip=false,$server_ip=false)
if (!$client_ip)
$client_ip = $_SERVER['REMOTE_ADDR'];
if (!$server_ip)
$server_ip = $_SERVER['SERVER_ADDR'];
// Extract broadcast and netmask from ifconfig
if (!($p = popen("ifconfig","r"))) return false;
$out = "";
while(!feof($p))
$out .= fread($p,1024);
fclose($p);
// This is to avoid wrapping.
$match = "/^.*".$server_ip;
$match .= ".*Bcast:(\d1,3\.\d1,3i\.\d1,3\.\d1,3).*";
$match .= "Mask:(\d1,3\.\d1,3\.\d1,3\.\d1,3)$/im";
if (!preg_match($match,$out,$regs))
return false;
$bcast = ip2long($regs[1]);
$smask = ip2long($regs[2]);
$ipadr = ip2long($client_ip);
$nmask = $bcast & $smask;
return (($ipadr & $smask) == ($nmask & $smask));
【讨论】:
以上是关于PHP:如何检查客户端是不是是本地的?的主要内容,如果未能解决你的问题,请参考以下文章
如何在使用本地 CRL 文件(C#)的验证过程中检查客户端证书吊销