提问人:Anup Prakash 提问时间:6/9/2010 最后编辑:Peter MortensenAnup Prakash 更新时间:10/25/2023 访问量:2140465
如何在PHP中获取客户端IP地址
How to get the client IP address in PHP
答:
它应该包含在变量中。$_SERVER['REMOTE_ADDR']
$_SERVER['REMOTE_ADDR']
实际上可能不包含真实的客户端 IP 地址,因为它会为您提供通过代理连接的客户端的代理地址。那可能
不过,要成为你真正想要的,这取决于你对IP做了什么。如果您试图查看您的流量来自哪里,或者记住用户上次连接的 IP,代理或 NAT 网关的公共 IP 可能更适合存储,那么某人的私人RFC1918地址可能对您没有任何好处。
有几个 HTTP 标头,例如,它们可能由各种代理设置,也可能不由各种代理设置。问题在于,这些只是任何人都可以设置的HTTP标头。无法保证其内容。 是 Web 服务器从中接收连接并将响应发送到的实际物理 IP 地址。其他任何事情都只是任意和自愿的信息。只有一种情况可以信任此信息:您正在控制设置此标头的代理。这意味着只有当您 100% 知道标题的设置位置和方式时,您才应该注意任何重要的事情。X-Forwarded-For
$_SERVER['REMOTE_ADDR']
话虽如此,下面是一些示例代码:
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
编者按:使用上述代码具有安全隐患。客户端可以将所有 HTTP 标头信息(即 )设置为它想要的任何任意值。因此,使用起来要可靠得多,因为用户无法设置。$_SERVER['HTTP_...
$_SERVER['REMOTE_ADDR']
寄件人:http://roshanbh.com.np/2007/12/getting-real-ip-address-in-php.html
评论
X-Forwarded-For
Client-IP
X-Forwarded-For
可能包含多个 IP 地址,用逗号分隔;并且应该真正被“解析”而不是从表面上看(AFAIK,它几乎从不包含单个 IP)。
echo $_SERVER['REMOTE_ADDR'];
http://php.net/manual/en/reserved.variables.server.php
评论
::1
127.0.0.1
答案是使用 $_SERVER
变量。例如,将返回客户端的 IP 地址。$_SERVER["REMOTE_ADDR"]
无论您做什么,请确保不要信任从客户端发送的数据。 包含连接方的真实 IP 地址。这是你能找到的最可靠的值。$_SERVER['REMOTE_ADDR']
但是,它们可能位于代理服务器后面,在这种情况下,代理可能已将 ,但此值很容易被欺骗。例如,它可以由没有代理的人设置,或者 IP 可以是代理后面 LAN 的内部 IP。$_SERVER['HTTP_X_FORWARDED_FOR']
这意味着,如果您要保存 ,请确保也保存该值。例如,通过将这两个值保存在数据库的不同字段中。$_SERVER['HTTP_X_FORWARDED_FOR']
$_SERVER['REMOTE_ADDR']
如果要将 IP 作为字符串保存到数据库,请确保至少有 45 个字符的空间。IPv6 将继续存在,这些地址比旧的 IPv4 地址大。
(请注意,IPv6 通常最多使用 39 个字符,但 IPv4 地址也有一个特殊的 IPv6 表示法,其完整形式最多可以是 45 个字符。因此,如果您知道自己在做什么,则可以使用 39 个字符,但如果您只想设置并忘记它,请使用 45 个字符)。
评论
REMOTE_ADDR
$_SERVER['REMOTE_ADDR']
REMOTE_ADDR
HTTP_X_FORWARDED_FOR
HTTP_X_FORWARDED_FOR
我喜欢这个代码片段:
function getClientIP() {
if (isset($_SERVER)) {
if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]))
return $_SERVER["HTTP_X_FORWARDED_FOR"];
if (isset($_SERVER["HTTP_CLIENT_IP"]))
return $_SERVER["HTTP_CLIENT_IP"];
return $_SERVER["REMOTE_ADDR"];
}
if (getenv('HTTP_X_FORWARDED_FOR'))
return getenv('HTTP_X_FORWARDED_FOR');
if (getenv('HTTP_CLIENT_IP'))
return getenv('HTTP_CLIENT_IP');
return getenv('REMOTE_ADDR');
}
评论
getenv
$_SERVER
这是我使用的方法,它验证 IPv4 输入:
// Get user IP address
if ( isset($_SERVER['HTTP_CLIENT_IP']) && ! empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) && ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = (isset($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
}
$ip = filter_var($ip, FILTER_VALIDATE_IP);
$ip = ($ip === false) ? '0.0.0.0' : $ip;
评论
我最喜欢的解决方案是 Zend Framework 2 的使用方式。它还考虑了属性 ,但它声明了一个类来设置一些受信任的代理,并返回一个 IP 地址而不是数组。我认为这是最接近它的解决方案:$_SERVER
HTTP_X_FORWARDED_FOR
HTTP_CLIENT_IP
REMOTE_ADDR
class RemoteAddress
{
/**
* Whether to use proxy addresses or not.
*
* As default this setting is disabled - IP address is mostly needed to increase
* security. HTTP_* are not reliable since can easily be spoofed. It can be enabled
* just for more flexibility, but if user uses proxy to connect to trusted services
* it's his/her own risk, only reliable field for IP address is $_SERVER['REMOTE_ADDR'].
*
* @var bool
*/
protected $useProxy = false;
/**
* List of trusted proxy IP addresses
*
* @var array
*/
protected $trustedProxies = array();
/**
* HTTP header to introspect for proxies
*
* @var string
*/
protected $proxyHeader = 'HTTP_X_FORWARDED_FOR';
// [...]
/**
* Returns client IP address.
*
* @return string IP address.
*/
public function getIpAddress()
{
$ip = $this->getIpAddressFromProxy();
if ($ip) {
return $ip;
}
// direct IP address
if (isset($_SERVER['REMOTE_ADDR'])) {
return $_SERVER['REMOTE_ADDR'];
}
return '';
}
/**
* Attempt to get the IP address for a proxied client
*
* @see http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10#section-5.2
* @return false|string
*/
protected function getIpAddressFromProxy()
{
if (!$this->useProxy
|| (isset($_SERVER['REMOTE_ADDR']) && !in_array($_SERVER['REMOTE_ADDR'], $this->trustedProxies))
) {
return false;
}
$header = $this->proxyHeader;
if (!isset($_SERVER[$header]) || empty($_SERVER[$header])) {
return false;
}
// Extract IPs
$ips = explode(',', $_SERVER[$header]);
// trim, so we can compare against trusted proxies properly
$ips = array_map('trim', $ips);
// remove trusted proxy IPs
$ips = array_diff($ips, $this->trustedProxies);
// Any left?
if (empty($ips)) {
return false;
}
// Since we've removed any known, trusted proxy servers, the right-most
// address represents the first IP we do not know about -- i.e., we do
// not know if it is a proxy server, or a client. As such, we treat it
// as the originating IP.
// @see http://en.wikipedia.org/wiki/X-Forwarded-For
$ip = array_pop($ips);
return $ip;
}
// [...]
}
评论
$_SERVER
下面是一个更简洁的代码示例,介绍了获取用户 IP 地址的好方法。
$ip = $_SERVER['HTTP_CLIENT_IP']
? $_SERVER['HTTP_CLIENT_IP']
: ($_SERVER['HTTP_X_FORWARDED_FOR']
? $_SERVER['HTTP_X_FORWARDED_FOR']
: $_SERVER['REMOTE_ADDR']);
下面是一个使用 elvis 运算符的较短版本:
$_SERVER['HTTP_CLIENT_IP']
? : ($_SERVER['HTTP_X_FORWARDED_FOR']
? : $_SERVER['REMOTE_ADDR']);
这是一个使用 isset 删除通知的版本(谢谢你,@shasi kanth):
$ip = isset($_SERVER['HTTP_CLIENT_IP'])
? $_SERVER['HTTP_CLIENT_IP']
: (isset($_SERVER['HTTP_X_FORWARDED_FOR'])
? $_SERVER['HTTP_X_FORWARDED_FOR']
: $_SERVER['REMOTE_ADDR']);
评论
$ip = $_SERVER['HTTP_CLIENT_IP']?$_SERVER['HTTP_CLIENT_IP']:($_SERVER['HTTP_X_FORWARDED_FOR']?$_SERVER['HTTP_X_FORWARDED_FOR']:$_SERVER['REMOTE_ADDR']);
像下面这样吗?
if (($ip=filter_input(INPUT_SERVER, 'REMOTE_ADDR', validate_ip)) === false or empty($ip)) {
exit;
}
echo $ip;
聚苯乙烯
if (($ip=filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP|FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_NO_RES_RANGE)) === false) {
header('HTTP/1.0 400 Bad Request');
exit;
}
所有以“HTTP_”或“X-”开头的标头都可能是欺骗性的,分别是用户定义的。如果您想跟踪,请使用 cookie 等。
以下是我发现的最先进的方法,我过去已经尝试过其他一些方法。确保获取访问者的 IP 地址是有效的(但请注意,任何黑客都可以轻松伪造 IP 地址)。
function get_ip_address() {
// Check for shared Internet/ISP IP
if (!empty($_SERVER['HTTP_CLIENT_IP']) && validate_ip($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
}
// Check for IP addresses passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// Check if multiple IP addresses exist in var
if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false) {
$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($iplist as $ip) {
if (validate_ip($ip))
return $ip;
}
}
else {
if (validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))
return $_SERVER['HTTP_X_FORWARDED_FOR'];
}
}
if (!empty($_SERVER['HTTP_X_FORWARDED']) && validate_ip($_SERVER['HTTP_X_FORWARDED']))
return $_SERVER['HTTP_X_FORWARDED'];
if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
return $_SERVER['HTTP_FORWARDED_FOR'];
if (!empty($_SERVER['HTTP_FORWARDED']) && validate_ip($_SERVER['HTTP_FORWARDED']))
return $_SERVER['HTTP_FORWARDED'];
// Return unreliable IP address since all else failed
return $_SERVER['REMOTE_ADDR'];
}
/**
* Ensures an IP address is both a valid IP address and does not fall within
* a private network range.
*/
function validate_ip($ip) {
if (strtolower($ip) === 'unknown')
return false;
// Generate IPv4 network address
$ip = ip2long($ip);
// If the IP address is set and not equivalent to 255.255.255.255
if ($ip !== false && $ip !== -1) {
// Make sure to get unsigned long representation of IP address
// due to discrepancies between 32 and 64 bit OSes and
// signed numbers (ints default to signed in PHP)
$ip = sprintf('%u', $ip);
// Do private network range checking
if ($ip >= 0 && $ip <= 50331647)
return false;
if ($ip >= 167772160 && $ip <= 184549375)
return false;
if ($ip >= 2130706432 && $ip <= 2147483647)
return false;
if ($ip >= 2851995648 && $ip <= 2852061183)
return false;
if ($ip >= 2886729728 && $ip <= 2887778303)
return false;
if ($ip >= 3221225984 && $ip <= 3221226239)
return false;
if ($ip >= 3232235520 && $ip <= 3232301055)
return false;
if ($ip >= 4294967040)
return false;
}
return true;
}
评论
试试这个:
$_SERVER['REMOTE_ADDR'];
评论
$ip = "";
if (!empty($_SERVER["HTTP_CLIENT_IP"]))
{
// Check for IP address from shared Internet
$ip = $_SERVER["HTTP_CLIENT_IP"];
}
elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"]))
{
// Check for the proxy user
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}
else
{
$ip = $_SERVER["REMOTE_ADDR"];
}
echo $ip;
评论
$ip
$ip = $_SERVER['REMOTE_ADDR']
好吧,这可以通过使用名为 的变量来简单地完成。GLOBAL
$_SERVER
是一个数组,其属性名称为 。$_SERVER
REMOTE_ADDR
只需像这样分配它:
$userIp = $_SERVER['REMOTE_ADDR'];
或者直接像或一样使用它。echo $_SERVER['REMOTE_ADDR'];
echo ($_SERVER['REMOTE_ADDR']);
以下函数确定所有可能性,并以逗号分隔的格式(ip、ip 等)返回值。
它还具有可选的验证功能(默认禁用的第一个参数),用于根据(专用范围和保留范围)验证 IP 地址。
<?php
echo GetClientIP(true);
function GetClientIP($validate = False) {
$ipkeys = array(
'REMOTE_ADDR',
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP'
);
/*
Now we check each key against $_SERVER if containing such value
*/
$ip = array();
foreach ($ipkeys as $keyword) {
if (isset($_SERVER[$keyword])) {
if ($validate) {
if (ValidatePublicIP($_SERVER[$keyword])) {
$ip[] = $_SERVER[$keyword];
}
}
else{
$ip[] = $_SERVER[$keyword];
}
}
}
$ip = ( empty($ip) ? 'Unknown' : implode(", ", $ip) );
return $ip;
}
function ValidatePublicIP($ip){
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return true;
}
else {
return false;
}
}
正如之前所有其他人所说,您可以使用来获取客户端 IP 地址。$_SERVER['REMOTE_ADDR'];
此外,如果您需要有关用户的更多信息,可以使用以下命令:
<?php
$ip = '0.0.0.0';
$ip = $_SERVER['REMOTE_ADDR'];
$clientDetails = json_decode(file_get_contents("http://ipinfo.io/$ip/json"));
echo "You're logged in from: <b>" . $clientDetails->country . "</b>";
?>
客户更具体的信息会进入$clientDetails。
您可以通过以下方式获取存储在变量中的 JSON 项目$clientDetails:$clientDetails->PostalCode/hostname/region/loc...
我正在使用 ipinfo.io 来获取额外的信息。
此功能很紧凑,您可以在任何地方使用它。但!
别忘了这一点!在这种类型的函数或代码块中,不能保证记录用户的真实 IP 地址,因为某些用户可以使用代理或其他安全网关来不可见或无法跟踪
PHP函数:
function GetIP()
{
if ( getenv("HTTP_CLIENT_IP") ) {
$ip = getenv("HTTP_CLIENT_IP");
} elseif ( getenv("HTTP_X_FORWARDED_FOR") ) {
$ip = getenv("HTTP_X_FORWARDED_FOR");
if ( strstr($ip, ',') ) {
$tmp = explode(',', $ip);
$ip = trim($tmp[0]);
}
} else {
$ip = getenv("REMOTE_ADDR");
}
return $ip;
}
用法:
$IP = GetIP();
或直接GetIP();
这是一个简单的衬里
$ip = $_SERVER['HTTP_X_FORWARDED_FOR']?: $_SERVER['HTTP_CLIENT_IP']?: $_SERVER['REMOTE_ADDR'];
编辑:
上面的代码可能会返回保留地址(如 10.0.0.1)、途中所有代理服务器的地址列表等。 若要处理这些情况,请使用以下代码:
function valid_ip($ip) {
// for list of reserved IP addresses, see https://en.wikipedia.org/wiki/Reserved_IP_addresses
return $ip && substr($ip, 0, 4) != '127.' && substr($ip, 0, 4) != '127.' && substr($ip, 0, 3) != '10.' && substr($ip, 0, 2) != '0.' ? $ip : false;
}
function get_client_ip() {
// using explode to get only client ip from list of forwarders. see https://en.wikipedia.org/wiki/X-Forwarded-For
return
@$_SERVER['HTTP_X_FORWARDED_FOR'] ? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2)[0] :
@$_SERVER['HTTP_CLIENT_IP'] ? explode(',', $_SERVER['HTTP_CLIENT_IP'], 2)[0] :
valid_ip(@$_SERVER['REMOTE_ADDR']) ?:
'UNKNOWN';
}
echo get_client_ip();
互联网背后有不同类型的用户,因此我们希望从不同的部分捕获 IP 地址。这些是:
1. $_SERVER['REMOTE_ADDR']
-
这包含客户端的真实 IP 地址。这是您可以从用户那里找到的最可靠的价值。
2. $_SERVER['REMOTE_HOST']
-
这将获取用户从中查看当前页面的主机名。但是要使此脚本正常工作,必须在 httpd.conf 内部配置主机名查找。
3. $_SERVER['HTTP_CLIENT_IP']
-
当用户来自共享 Internet 服务时,这将获取 IP 地址。
4. $_SERVER['HTTP_X_FORWARDED_FOR']
- 当用户在代理后面时,这将从他/她那里获取 IP 地址。
所以我们可以使用下面的组合函数,从不同位置观看的用户那里获取真实的IP地址,
// Function to get the user IP address
function getUserIP() {
$ipaddress = '';
if (isset($_SERVER['HTTP_CLIENT_IP']))
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_X_FORWARDED']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
else if(isset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
$ipaddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_FORWARDED']))
$ipaddress = $_SERVER['HTTP_FORWARDED'];
else if(isset($_SERVER['REMOTE_ADDR']))
$ipaddress = $_SERVER['REMOTE_ADDR'];
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
评论
用于获取 IP 地址的安全且可感知警告的代码段:
$ip = filter_input(INPUT_SERVER, 'HTTP_CLIENT_IP', FILTER_VALIDATE_IP)
?: filter_input(INPUT_SERVER, 'HTTP_X_FORWARDED_FOR', FILTER_VALIDATE_IP)
?: $_SERVER['REMOTE_ADDR']
?? '0.0.0.0'; // Or other value fits "not defined" in your logic
此函数应按预期工作
function Get_User_Ip()
{
$IP = false;
if (getenv('HTTP_CLIENT_IP'))
{
$IP = getenv('HTTP_CLIENT_IP');
}
else if(getenv('HTTP_X_FORWARDED_FOR'))
{
$IP = getenv('HTTP_X_FORWARDED_FOR');
}
else if(getenv('HTTP_X_FORWARDED'))
{
$IP = getenv('HTTP_X_FORWARDED');
}
else if(getenv('HTTP_FORWARDED_FOR'))
{
$IP = getenv('HTTP_FORWARDED_FOR');
}
else if(getenv('HTTP_FORWARDED'))
{
$IP = getenv('HTTP_FORWARDED');
}
else if(getenv('REMOTE_ADDR'))
{
$IP = getenv('REMOTE_ADDR');
}
//If HTTP_X_FORWARDED_FOR == server ip
if((($IP) && ($IP == getenv('SERVER_ADDR')) && (getenv('REMOTE_ADDR')) || (!filter_var($IP, FILTER_VALIDATE_IP))))
{
$IP = getenv('REMOTE_ADDR');
}
if($IP)
{
if(!filter_var($IP, FILTER_VALIDATE_IP))
{
$IP = false;
}
}
else
{
$IP = false;
}
return $IP;
}
<?php
/**
* Function to get the client ip address
*
* @return string The Ip address
*/
function getIp(): string {
if (! empty($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
}
if (! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
return $_SERVER['HTTP_X_FORWARDED_FOR'];
}
return $_SERVER['REMOTE_ADDR'] ?? '?';
}
甚至更小
/**
* Function to get the client ip address
*
* @return string The Ip address
*/
function getIp(): string {
return $_SERVER['HTTP_CLIENT_IP'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
}
就这一点,我很惊讶它还没有被提及,是获取那些位于CloudFlare基础设施后面的站点的正确IP地址。它将破坏您的 IP 地址,并赋予它们相同的值。 幸运的是,他们也有一些可用的服务器标头。 与其我重写已经写过的东西,不如看看这里以获得更简洁的答案,是的,我很久以前也经历过这个过程。https://stackoverflow.com/a/14985633/1190051
function get_client_ip()
{
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);
if ((bool) filter_var($ip, FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 |
FILTER_FLAG_NO_PRIV_RANGE |
FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
}
}
return null;
}
或者压缩版本:
function get_ip() {
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) === true) {
foreach (array_map('trim', explode(',', $_SERVER[$key])) as $ip) {
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
return $ip;
}
}
}
}
}
这里有一些代码,应该通过检查各种来源来选择有效的 IP。
首先,它会检查“REMOTE_ADDR”是否是公共 IP(而不是您信任的反向代理之一),然后遍历其中一个 HTTP 标头,直到找到公共 IP 并返回它。(菲律宾比索 5.2+)
只要反向代理受信任或服务器直接与客户端连接,它就应该是可靠的。
//Get client's IP or null if nothing looks valid
function ip_get($allow_private = false)
{
//Place your trusted proxy server IPs here.
$proxy_ip = ['127.0.0.1'];
//The header to look for (Make sure to pick the one that your trusted reverse proxy is sending or else you can get spoofed)
$header = 'HTTP_X_FORWARDED_FOR'; //HTTP_CLIENT_IP, HTTP_X_FORWARDED, HTTP_FORWARDED_FOR, HTTP_FORWARDED
//If 'REMOTE_ADDR' seems to be a valid client IP, use it.
if(ip_check($_SERVER['REMOTE_ADDR'], $allow_private, $proxy_ip)) return $_SERVER['REMOTE_ADDR'];
if(isset($_SERVER[$header]))
{
//Split comma separated values [1] in the header and traverse the proxy chain backwards.
//[1] https://en.wikipedia.org/wiki/X-Forwarded-For#Format
$chain = array_reverse(preg_split('/\s*,\s*/', $_SERVER[$header]));
foreach($chain as $ip) if(ip_check($ip, $allow_private, $proxy_ip)) return $ip;
}
return null;
}
//Check for valid IP. If 'allow_private' flag is set to truthy, it allows private IP ranges as valid client IP as well. (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
//Pass your trusted reverse proxy IPs as $proxy_ip to exclude them from being valid.
function ip_check($ip, $allow_private = false, $proxy_ip = [])
{
if(!is_string($ip) || is_array($proxy_ip) && in_array($ip, $proxy_ip)) return false;
$filter_flag = FILTER_FLAG_NO_RES_RANGE;
if(!$allow_private)
{
//Disallow loopback IP range which doesn't get filtered via 'FILTER_FLAG_NO_PRIV_RANGE' [1]
//[1] https://www.php.net/manual/en/filter.filters.validate.php
if(preg_match('/^127\.$/', $ip)) return false;
$filter_flag |= FILTER_FLAG_NO_PRIV_RANGE;
}
return filter_var($ip, FILTER_VALIDATE_IP, $filter_flag) !== false;
}
其中之一:
$ip = $_SERVER['REMOTE_ADDR'];
$ip = $_SERVER['HTTP_CLIENT_IP'];
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$ip = $_SERVER['HTTP_X_FORWARDED'];
$ip = $_SERVER['HTTP_FORWARDED_FOR'];
$ip = $_SERVER['HTTP_FORWARDED'];
评论
快速解决方案(无错误)
function getClientIP():string
{
$keys=array('HTTP_CLIENT_IP','HTTP_X_FORWARDED_FOR','HTTP_X_FORWARDED','HTTP_FORWARDED_FOR','HTTP_FORWARDED','REMOTE_ADDR');
foreach($keys as $k)
{
if (!empty($_SERVER[$k]) && filter_var($_SERVER[$k], FILTER_VALIDATE_IP))
{
return $_SERVER[$k];
}
}
return "UNKNOWN";
}
评论
X-FORWARDED-FOR: fakeip
strtok($k, ';,')
HTTP_X_FORWARDED
HTTP_FORWARDED
for=1.1.1.1;by=1.1.1.0
要获取客户端 IP 地址,请使用 。getenv("REMOTE_ADDR")
例如
$ip_address = getenv("REMOTE_ADDR");
echo $ip_address;
如果您使用 localhost 调用您的服务器,它将打印出 .
因此,请使用直接服务器 IP 地址或域呼叫您的服务器。::1
在PHP中,获取公共IP的最后一个选项应该总是出于太多的安全原因。$_SERVER["REMOTE_ADDR"]
以下是获取客户端的已验证 IP 地址的解决方法。
public static function getPublicIP() : string
{
$realIP = "Invalid IP Address";
$activeHeaders = [];
$headers = [
"HTTP_CLIENT_IP",
"HTTP_PRAGMA",
"HTTP_XONNECTION",
"HTTP_CACHE_INFO",
"HTTP_XPROXY",
"HTTP_PROXY",
"HTTP_PROXY_CONNECTION",
"HTTP_VIA",
"HTTP_X_COMING_FROM",
"HTTP_COMING_FROM",
"HTTP_X_FORWARDED_FOR",
"HTTP_X_FORWARDED",
"HTTP_X_CLUSTER_CLIENT_IP",
"HTTP_FORWARDED_FOR",
"HTTP_FORWARDED",
"ZHTTP_CACHE_CONTROL",
"REMOTE_ADDR" #this should be the last option
];
#Find active headers
foreach ($headers as $key)
{
if (array_key_exists($key, $_SERVER))
{
$activeHeaders[$key] = $_SERVER[$key];
}
}
#Reemove remote address since we got more options to choose from
if(count($activeHeaders) > 1)
{
unset($activeHeaders["REMOTE_ADDR"]);
}
#Pick a random item now that we have a secure way.
$realIP = $activeHeaders[array_rand($activeHeaders)];
#Validate the public IP
if (filter_var($realIP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
{
return $realIP;
}
return $realIP;
}
正如你在这里看到的,$_SERVER[“REMOTE_ADDR”] 是我们对 IP 的最后一个选择。收到 IP 后,我们还会验证 IP,以确保质量和安全性。
如果您不喜欢使用 if-else/switch 语句,那么以下解决方案适合您。
function get_client_ip()
{
$fields = array(
'HTTP_CF_CONNECTING_IP',
'HTTP_X_SUCURI_CLIENTIP',
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR',
// more custom fields
);
foreach ($fields as $ip_field) {
if (!empty($_SERVER[$ip_field])) {
return $_SERVER[$ip_field];
}
}
return null;
}
您可以使用以下功能
function get_client_ip() {
$ipaddress = '';
if (isset($_SERVER['HTTP_CLIENT_IP']))
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_X_FORWARDED']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_FORWARDED']))
$ipaddress = $_SERVER['HTTP_FORWARDED'];
else if(isset($_SERVER['REMOTE_ADDR']))
$ipaddress = $_SERVER['REMOTE_ADDR'];
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
我使用了其他答案之一,并添加了一些其他内容,例如CloudFlare代理和NGINX代理检测。
/**
* Gets, validates and returns the connecting client's IP
*/
function getClientIP(){
// Get real visitor IP behind CloudFlare network
if (!empty($_SERVER["HTTP_CF_CONNECTING_IP"]) && validateIP($_SERVER['HTTP_CF_CONNECTING_IP'])) {
return $_SERVER["HTTP_CF_CONNECTING_IP"];
}
// Get real visitor IP behind NGINX proxy - https://easyengine.io/tutorials/nginx/forwarding-visitors-real-ip/
if (!empty($_SERVER["HTTP_X_REAL_IP"]) && validateIP($_SERVER['HTTP_X_REAL_IP'])) {
return $_SERVER["HTTP_X_REAL_IP"];
}
// Check for shared Internet/ISP IP
if (!empty($_SERVER['HTTP_CLIENT_IP']) && validateIP($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
}
// Check for IP addresses passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// Check if multiple IP addresses exist in var
if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false) {
$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($iplist as $ip) {
if (validateIP($ip))
return $ip;
}
}
else {
if (validateIP($_SERVER['HTTP_X_FORWARDED_FOR']))
return $_SERVER['HTTP_X_FORWARDED_FOR'];
}
}
if (!empty($_SERVER['HTTP_X_FORWARDED']) && validateIP($_SERVER['HTTP_X_FORWARDED']))
return $_SERVER['HTTP_X_FORWARDED'];
if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && validateIP($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && validateIP($_SERVER['HTTP_FORWARDED_FOR']))
return $_SERVER['HTTP_FORWARDED_FOR'];
if (!empty($_SERVER['HTTP_FORWARDED']) && validateIP($_SERVER['HTTP_FORWARDED']))
return $_SERVER['HTTP_FORWARDED'];
// Return unreliable IP address since all else failed
return $_SERVER['REMOTE_ADDR'];
}
/**
* Ensures an IP address is both a valid IP address and does not fall within
* a private network range.
*/
function validateIP($ip) {
if (strtolower($ip) === 'unknown')
return false;
// Generate IPv4 network address
$ip = ip2long($ip);
// Do additional filtering on IP
if(!filter_var($ip, FILTER_VALIDATE_IP))
return false;
// If the IP address is set and not equivalent to 255.255.255.255
if ($ip !== false && $ip !== -1) {
// Make sure to get unsigned long representation of IP address
// due to discrepancies between 32 and 64 bit OSes and
// signed numbers (ints default to signed in PHP)
$ip = sprintf('%u', $ip);
// Do private network range checking
if ($ip >= 0 && $ip <= 50331647)
return false;
if ($ip >= 167772160 && $ip <= 184549375)
return false;
if ($ip >= 2130706432 && $ip <= 2147483647)
return false;
if ($ip >= 2851995648 && $ip <= 2852061183)
return false;
if ($ip >= 2886729728 && $ip <= 2887778303)
return false;
if ($ip >= 3221225984 && $ip <= 3221226239)
return false;
if ($ip >= 3232235520 && $ip <= 3232301055)
return false;
if ($ip >= 4294967040)
return false;
}
return true;
}
我在生产节点中使用它,效果很好。由于大部分代码都来自这里,我在 GNU @ https://github.com/d3vdigital/whatsmyip-node 下发布了一个节点
评论
使用 $ip = $_SERVER[“REMOTE_ADDR”] 这会将 IP 保存在 IP 变量中。
我们可以将其用于 localhost 和网站
function get_ip() {
$ip = '';
if (isset($_SERVER['HTTP_CLIENT_IP'])){
$ip = $_SERVER['HTTP_CLIENT_IP'];
}else if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}else if(isset($_SERVER['HTTP_X_FORWARDED'])){
$ip = $_SERVER['HTTP_X_FORWARDED'];
}else if(isset($_SERVER['HTTP_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_FORWARDED_FOR'];
}else if(isset($_SERVER['HTTP_FORWARDED'])){
$ip = $_SERVER['HTTP_FORWARDED'];
}else if(isset($_SERVER['REMOTE_ADDR'])){
$ip = $_SERVER['REMOTE_ADDR'];
}
if( empty($ip) || $ip == '0.0.0.0' || substr( $ip, 0, 2 ) == '::' ){
$ip = file_get_contents('https://api.ipify.org/');
$ip = ($ip===false?$ip:'');
}
return $ip;
}
<?php
/**
* Get the real IP address of the client
*
* @param array $trusted_proxies list of IP addresses of reverse proxy servers that you trust
* @return mixed client IP or null
*/
function get_client_ip($trusted_proxies=[]) {
// In cli mode, there is no remote address
if (empty($_SERVER['REMOTE_ADDR'])) {
return null;
}
$client_ip = $_SERVER['REMOTE_ADDR'];
// If the remote address is not a trusted proxy, we shouldn't trust
// any headers that malicious clients may send
if (!in_array($client_ip, $trusted_proxies)) {
return $client_ip;
}
// The request is coming from a trusted proxy, so we can trust the
// "forwarded for" headers
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
return $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if (isset($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
}
// No forwarded client IP header provided; this might be some kind
// of health check request. Just return the trusted proxy IP.
return $client_ip;
}
// Example usage
// if the app doesn't work behind proxy server:
$ip = get_client_ip();
// if you're behind reverse proxy, pass the IP address like this:
$ip = get_client_ip(trusted_proxies: ['10.10.10.10']);
// or like this, for older PHP versions:
$ip = get_client_ip(['10.10.10.10']);
正如许多人所说,寻找真人 IP 的“反代理”有点难以创建,因为您需要信任的代理的 IP 列表。Cvolton 是 Geometry Dash 玩家,它用 PHP 和 MySQL 重新创建了整个游戏服务器,并具有绕过 Cloudflare 和 7mPl“localhost bug”获取用户 IP 的功能。这是代码(因为原始代码被分成 2 个文件,所以这里是融合文件)(获取 IP 函数也在程序的末尾):
/*
* ip_in_range.php - Function to determine if an IP is located in a
* specific range as specified via several alternative
* formats.
*
* Network ranges can be specified as:
* 1. Wildcard format: 1.2.3.*
* 2. CIDR format: 1.2.3/24 OR 1.2.3.4/255.255.255.0
* 3. Start-End IP format: 1.2.3.0-1.2.3.255
*
* Return value BOOLEAN : ip_in_range($ip, $range);
*
* Copyright 2008: Paul Gregg <[email protected]>
* 10 January 2008
* Version: 1.2
*
* Source website: http://www.pgregg.com/projects/php/ip_in_range/
* Version 1.2
*
* This software is Donationware - if you feel you have benefited from
* the use of this tool then please consider a donation. The value of
* which is entirely left up to your discretion.
* http://www.pgregg.com/donate/
*
* Please do not remove this header, or source attibution from this file.
*/
/*
* Modified by James Greene <[email protected]> to include IPV6 support
* (original version only supported IPV4).
* 21 May 2012
*/
class ipInRange {
// decbin32
// In order to simplify working with IP addresses (in binary) and their
// netmasks, it is easier to ensure that the binary strings are padded
// with zeros out to 32 characters - IP addresses are 32 bit numbers
public static function decbin32 ($dec) {
return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT);
}
// ipv4_in_range
// This function takes 2 arguments, an IP address and a "range" in several
// different formats.
// Network ranges can be specified as:
// 1. Wildcard format: 1.2.3.*
// 2. CIDR format: 1.2.3/24 OR 1.2.3.4/255.255.255.0
// 3. Start-End IP format: 1.2.3.0-1.2.3.255
// The function will return true if the supplied IP is within the range.
// Note little validation is done on the range inputs - it expects you to
// use one of the above 3 formats.
public static function ipv4_in_range($ip, $range) {
if (strpos($range, '/') !== false) {
// $range is in IP/NETMASK format
list($range, $netmask) = explode('/', $range, 2);
if (strpos($netmask, '.') !== false) {
// $netmask is a 255.255.0.0 format
$netmask = str_replace('*', '0', $netmask);
$netmask_dec = ip2long($netmask);
return ( (ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec) );
} else {
// $netmask is a CIDR size block
// fix the range argument
$x = explode('.', $range);
while(count($x)<4) $x[] = '0';
list($a,$b,$c,$d) = $x;
$range = sprintf("%u.%u.%u.%u", empty($a)?'0':$a, empty($b)?'0':$b,empty($c)?'0':$c,empty($d)?'0':$d);
$range_dec = ip2long($range);
$ip_dec = ip2long($ip);
# Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
#$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));
# Strategy 2 - Use math to create it
$wildcard_dec = pow(2, (32-$netmask)) - 1;
$netmask_dec = ~ $wildcard_dec;
return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec));
}
} else {
// range might be 255.255.*.* or 1.2.3.0-1.2.3.255
if (strpos($range, '*') !==false) { // a.b.*.* format
// Just convert to A-B format by setting * to 0 for A and 255 for B
$lower = str_replace('*', '0', $range);
$upper = str_replace('*', '255', $range);
$range = "$lower-$upper";
}
if (strpos($range, '-')!==false) { // A-B format
list($lower, $upper) = explode('-', $range, 2);
$lower_dec = (float)sprintf("%u",ip2long($lower));
$upper_dec = (float)sprintf("%u",ip2long($upper));
$ip_dec = (float)sprintf("%u",ip2long($ip));
return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) );
}
return false;
}
}
public static function ip2long6($ip) {
if (substr_count($ip, '::')) {
$ip = str_replace('::', str_repeat(':0000', 8 - substr_count($ip, ':')) . ':', $ip);
}
$ip = explode(':', $ip);
$r_ip = '';
foreach ($ip as $v) {
$r_ip .= str_pad(base_convert($v, 16, 2), 16, 0, STR_PAD_LEFT);
}
return base_convert($r_ip, 2, 10);
}
// Get the ipv6 full format and return it as a decimal value.
public static function get_ipv6_full($ip)
{
$pieces = explode ("/", $ip, 2);
$left_piece = $pieces[0];
$right_piece = $pieces[1];
// Extract out the main IP pieces
$ip_pieces = explode("::", $left_piece, 2);
$main_ip_piece = $ip_pieces[0];
$last_ip_piece = $ip_pieces[1];
// Pad out the shorthand entries.
$main_ip_pieces = explode(":", $main_ip_piece);
foreach($main_ip_pieces as $key=>$val) {
$main_ip_pieces[$key] = str_pad($main_ip_pieces[$key], 4, "0", STR_PAD_LEFT);
}
// Check to see if the last IP block (part after ::) is set
$last_piece = "";
$size = count($main_ip_pieces);
if (trim($last_ip_piece) != "") {
$last_piece = str_pad($last_ip_piece, 4, "0", STR_PAD_LEFT);
// Build the full form of the IPV6 address considering the last IP block set
for ($i = $size; $i < 7; $i++) {
$main_ip_pieces[$i] = "0000";
}
$main_ip_pieces[7] = $last_piece;
}
else {
// Build the full form of the IPV6 address
for ($i = $size; $i < 8; $i++) {
$main_ip_pieces[$i] = "0000";
}
}
// Rebuild the final long form IPV6 address
$final_ip = implode(":", $main_ip_pieces);
return ip2long6($final_ip);
}
// Determine whether the IPV6 address is within range.
// $ip is the IPV6 address in decimal format to check if its within the IP range created by the cloudflare IPV6 address, $range_ip.
// $ip and $range_ip are converted to full IPV6 format.
// Returns true if the IPV6 address, $ip, is within the range from $range_ip. False otherwise.
public static function ipv6_in_range($ip, $range_ip)
{
$pieces = explode ("/", $range_ip, 2);
$left_piece = $pieces[0];
$right_piece = $pieces[1];
// Extract out the main IP pieces
$ip_pieces = explode("::", $left_piece, 2);
$main_ip_piece = $ip_pieces[0];
$last_ip_piece = $ip_pieces[1];
// Pad out the shorthand entries.
$main_ip_pieces = explode(":", $main_ip_piece);
foreach($main_ip_pieces as $key=>$val) {
$main_ip_pieces[$key] = str_pad($main_ip_pieces[$key], 4, "0", STR_PAD_LEFT);
}
// Create the first and last pieces that will denote the IPV6 range.
$first = $main_ip_pieces;
$last = $main_ip_pieces;
// Check to see if the last IP block (part after ::) is set
$last_piece = "";
$size = count($main_ip_pieces);
if (trim($last_ip_piece) != "") {
$last_piece = str_pad($last_ip_piece, 4, "0", STR_PAD_LEFT);
// Build the full form of the IPV6 address considering the last IP block set
for ($i = $size; $i < 7; $i++) {
$first[$i] = "0000";
$last[$i] = "ffff";
}
$main_ip_pieces[7] = $last_piece;
}
else {
// Build the full form of the IPV6 address
for ($i = $size; $i < 8; $i++) {
$first[$i] = "0000";
$last[$i] = "ffff";
}
}
// Rebuild the final long form IPV6 address
$first = ip2long6(implode(":", $first));
$last = ip2long6(implode(":", $last));
$in_range = ($ip >= $first && $ip <= $last);
return $in_range;
}
}
/* These two functions are from Cvolton (github.com/Cvolton) */
/* https://github.com/Cvolton/GMDprivateServer/blob/master/incl/lib/mainLib.php#L511 */
function isCloudFlareIP($ip) {
$cf_ips = array(
'173.245.48.0/20',
'103.21.244.0/22',
'103.22.200.0/22',
'103.31.4.0/22',
'141.101.64.0/18',
'108.162.192.0/18',
'190.93.240.0/20',
'188.114.96.0/20',
'197.234.240.0/22',
'198.41.128.0/17',
'162.158.0.0/15',
'104.16.0.0/13',
'104.24.0.0/14',
'172.64.0.0/13',
'131.0.72.0/22'
);
foreach ($cf_ips as $cf_ip) {
if (ipInRange::ipv4_in_range($ip, $cf_ip)) {
return true;
}
}
return false;
}
function getIP(){
if (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && $this->isCloudFlareIP($_SERVER['REMOTE_ADDR'])) //CLOUDFLARE REVERSE PROXY SUPPORT
return $_SERVER['HTTP_CF_CONNECTING_IP'];
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && ipInRange::ipv4_in_range($_SERVER['REMOTE_ADDR'], '127.0.0.0/8')) //LOCALHOST REVERSE PROXY SUPPORT (7m.pl)
return $_SERVER['HTTP_X_FORWARDED_FOR'];
return $_SERVER['REMOTE_ADDR'];
}
我知道代码真的很长(也许里面有一些无用的东西,我没有写程序,我只是融合了它们),所以你可以尝试优化它(比如将 3 个函数融合成一个,只保留你需要的功能)但这(通常)有效。 代码来自 https://github.com/Cvolton/GMDprivateServer/ The Cvolton 的函数: https://github.com/Cvolton/GMDprivateServer/blob/master/incl/lib/mainLib.php#L511 ip_in_range类: https://github.com/Cvolton/GMDprivateServer/blob/master/incl/lib/ip_in_range.php
我已经得到了很多答案,我决定提供改进的代码来获取访问者 IP 地址。
- 与CloudFlare兼容
- 获取CloudFlare网络背后的真实访客IP
- 处理涉及多个代理的情况 (HTTP_X_FORWARDED_FOR)
- HTTP_X_FORWARDED_FOR可以有多个IP,如“1.1.1.1,2.2.2.2”
- 如果没有 _SERVER 美元,请工作。
- 筛选专用 IP 和/或保留 IP
- 在X_FORWARDED_FOR中处理所有转发的 IP
- 检查共享 Internet/ISP IP (HTTP_CLIENT_IP)
function GetIP() {
// Compatible with CloudFlare
// 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"];
}
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) === true)
{
// Handle the case where there are multiple proxies involved
// HTTP_X_FORWARDED_FOR can have multiple ip like '1.1.1.1,2.2.2.2'
foreach (array_map('trim', explode(',', $_SERVER[$key])) as $ip)
{
// Filter private and/or reserved IPs;
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false)
{
return $ip;
}
}
} else {
// Work if $_SERVER was not available.
foreach (array_map('trim', explode(',', getenv($key))) as $ip)
{
// Filter private and/or reserved IPs;
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false)
{
return $ip;
}
}
}
}
}
评论