在PHP中检索用户正确IP地址的最准确方法是什么?

我知道有太多的

变量标头可用于IP地址检索。我想知道是否就使用上述变量最准确地检索用户的真实IP地址(众所周知没有一种方法是完美的)是否达成共识?

我花了一些时间试图找到一个深入的解决方案,并根据许多资源提出了以下代码。如果有人可以在答案中戳出一个洞或阐明一些可能更准确的内容,我将非常喜欢。

 /**

* Retrieves the best guess of the client's actual IP address.

* Takes into account numerous HTTP proxy headers due to variations

* in how different ISPs handle IP addresses in headers between hops.

*/

public function get_ip_address() {

// Check for shared internet/ISP IP

if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))

return $_SERVER['HTTP_CLIENT_IP'];

// Check for IPs passing through proxies

if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {

// Check if multiple IP addresses exist in var

$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);

foreach ($iplist as $ip) {

if ($this->validate_ip($ip))

return $ip;

}

}

}

if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))

return $_SERVER['HTTP_X_FORWARDED'];

if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))

return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];

if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))

return $_SERVER['HTTP_FORWARDED_FOR'];

if (!empty($_SERVER['HTTP_FORWARDED']) && $this->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.

*

* @access public

* @param string $ip

*/

public function validate_ip($ip) {

if (filter_var($ip, FILTER_VALIDATE_IP,

FILTER_FLAG_IPV4 |

FILTER_FLAG_IPV6 |

FILTER_FLAG_NO_PRIV_RANGE |

FILTER_FLAG_NO_RES_RANGE) === false)

return false;

self::$ip = $ip;

return true;

}

回答:

REMOTE_ADDR仍然代表IP地址的 最可靠

来源。$_SERVER远程客户端很容易欺骗这里提到的其他变量。该解决方案的目的是尝试确定位于代理后面的客户端的IP地址。为了您的一般目的,您可以考虑将其与直接从$_SERVER['REMOTE_ADDR']两者存储并返回的IP地址结合使用。

它不会通过注入自己的请求标头来保护您免受0.1%恶意用户滥用系统的侵害。如果依靠IP地址执行某些关键任务,请诉诸于REMOTE_ADDR代理,而不必理会这些代理。

回答:

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) === true){

foreach (explode(',', $_SERVER[$key]) as $ip){

$ip = trim($ip); // just to be safe

if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){

return $ip;

}

}

}

}

}

希望对您有所帮助!


您的代码似乎已经很完整了,我看不到其中的任何可能的错误(除了常见的IP警告),validate_ip()尽管如此,我还是将功能更改为依赖过滤器扩展:

public function validate_ip($ip)

{

if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false)

{

return false;

}

self::$ip = sprintf('%u', ip2long($ip)); // you seem to want this

return true;

}

您的HTTP_X_FORWARDED_FOR代码段也可以从此简化:

// check for IPs passing through proxies

if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))

{

// check if multiple ips exist in var

if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false)

{

$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);

foreach ($iplist as $ip)

{

if ($this->validate_ip($ip))

return $ip;

}

}

else

{

if ($this->validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))

return $_SERVER['HTTP_X_FORWARDED_FOR'];

}

}

对此:

// check for IPs passing through proxies

if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))

{

$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);

foreach ($iplist as $ip)

{

if ($this->validate_ip($ip))

return $ip;

}

}

您可能还需要验证IPv6地址。

以上是 在PHP中检索用户正确IP地址的最准确方法是什么? 的全部内容, 来源链接: utcz.com/qa/404531.html

回到顶部