使用PHP获取客户端IP地址

235

我想获取访问我的网站的客户端IP地址。我正在使用PHP的 $_SERVER 超全局变量:

$_SERVER['REMOTE_ADDR'];

但是我发现它不能正确地给出我的IP地址。我获取了我的IP地址并发现它与我的IP地址不同,我还可以在一些网站上看到我的IP地址,例如:

http://whatismyipaddress.com/

我将给出的IP地址粘贴到我的PHP函数中,但是这个网站没有显示任何关于它的结果。这个问题是如何产生的,我该如何获取客户端的IP地址?


5
以下是需要翻译的内容:What is the most accurate way to retrieve a user's correct IP address in PHP?I'm using $_SERVER['REMOTE_ADDR'] but I think it is not accurate when the user is behind a proxy or load balancer. Is there any other way to get the real IP address of the user? - Ares
2
如果您在本地服务器上,它将是不同的(例如:192.168.xxx.xxx),因为您从whatsmyip检查时,您获取的是ISP提供给您的IP。 - Class
在您的计算机上,您会看到您的私有IP地址(192..),而在网站上,您会看到您的公共IP地址(84...)。一般来说,您的公共IP地址是唯一有趣的。 - CustomX
12
这并不是重复的内容,因为这在Google中排名最高。Stackoverflow的人们,请注意。"标记为重复"发生得太频繁了。如果这个排名更好,那一定有其原因。Google已经说话了。 - 3Dom
4个回答

427

获取访问者/客户端的IP地址最简单的方法是使用$_SERVER['REMOTE_ADDR']$_SERVER['REMOTE_HOST']变量。

然而,有时这样做不能返回正确的访问者IP地址,因此我们可以使用其他一些服务器变量来获取IP地址。

下面两个函数在功能上是等效的,区别仅在于值是如何以及从哪里检索到的。

在PHP中,getenv()用于获取环境变量的值。

// Function to get the client IP address
function get_client_ip() {
    $ipaddress = '';
    if (getenv('HTTP_CLIENT_IP'))
        $ipaddress = getenv('HTTP_CLIENT_IP');
    else if(getenv('HTTP_X_FORWARDED_FOR'))
        $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
    else if(getenv('HTTP_X_FORWARDED'))
        $ipaddress = getenv('HTTP_X_FORWARDED');
    else if(getenv('HTTP_FORWARDED_FOR'))
        $ipaddress = getenv('HTTP_FORWARDED_FOR');
    else if(getenv('HTTP_FORWARDED'))
       $ipaddress = getenv('HTTP_FORWARDED');
    else if(getenv('REMOTE_ADDR'))
        $ipaddress = getenv('REMOTE_ADDR');
    else
        $ipaddress = 'UNKNOWN';
    return $ipaddress;
}

$_SERVER是一个包含由Web服务器创建的服务器变量的数组。

// Function to get the client IP address
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;
}

44
请注意,该函数也可能会给你带来很大的错误。特别是,HTTP_X_FORWARDED_FOR可以是客户端选择设置的任何内容,而REMOTE_ADDR则更难伪造,如果客户端想要获得实际的响应。 - eis
3
即使它不是伪造的,也有很多设置会使其只填充客户端内部网络IP,这将是无用的。 - eis
5
这段代码容易被伪造,请注意在使用时小心! - jnhghy - Alexandru Jantea
5
在你被黑客攻击之前,你需要阅读这篇文章:https://dev59.com/O3A75IYBdhLWcg3w-OVA#TaygEYcBWogLw_1bdnPR。 - Pacerier
2
@huykon225 因为您在本地主机上。请尝试将脚本上传到服务器上进行测试。 - TarangP
显示剩余9条评论

143

在PHP 5.3或更高版本中,您可以像这样获取它:

$ip = getenv('HTTP_CLIENT_IP')?:
getenv('HTTP_X_FORWARDED_FOR')?:
getenv('HTTP_X_FORWARDED')?:
getenv('HTTP_FORWARDED_FOR')?:
getenv('HTTP_FORWARDED')?:
getenv('REMOTE_ADDR');

4
这对我有效,而标记为正确答案的那个则没有。 - Matical
9
如果变量未设置,getenv将返回false,而$_SERVER在变量未设置时会出现“undefined index”的错误。 - Michael
4
通常我不喜欢嵌套的三元运算符,但在这种情况下我真的很喜欢它... - Charles Harmon
2
我倾向于完全避免在PHP中使用三元运算符,因为它的(不合逻辑的)左结合性。请参见http://phpsadness.com/sad/30 - GeriBoss
3
GeriBoss,解决那个phpsadness测试用例并同时使代码更易读并不难:echo (FALSE ? "a" : (FALSE ? "b" : "c"))."\n"; echo (FALSE ? "a" : (TRUE ? "b" : "c"))."\n"; echo (TRUE ? "a" : (FALSE ? "b" : "c"))."\n"; echo (TRUE ? "a" : (TRUE ? "b" : "c"))."\n"; - Michael
显示剩余6条评论

1
    $ipaddress = '';
    if ($_SERVER['HTTP_CLIENT_IP'] != '127.0.0.1')
        $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
    else if ($_SERVER['HTTP_X_FORWARDED_FOR'] != '127.0.0.1')
        $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
    else if ($_SERVER['HTTP_X_FORWARDED'] != '127.0.0.1')
        $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
    else if ($_SERVER['HTTP_FORWARDED_FOR'] != '127.0.0.1')
        $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
    else if ($_SERVER['HTTP_FORWARDED'] != '127.0.0.1')
        $ipaddress = $_SERVER['HTTP_FORWARDED'];
    else if ($_SERVER['REMOTE_ADDR'] != '127.0.0.1')
        $ipaddress = $_SERVER['REMOTE_ADDR'];
    else
        $ipaddress = 'UNKNOWN';

-18
这是一个用于获取本地和局域网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) === true){
            foreach (explode(',', $_SERVER[$key]) as $IPaddress){
                $IPaddress = trim($IPaddress); // Just to be safe

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

                    return $IPaddress;
                }
            }
        }
    }
}

39
对于“不提供来源”的回答,得到-1分。(链接:https://dev59.com/-HI-5IYBdhLWcg3w3cnS#2031935) - BlueRaja - Danny Pflughoeft
代码function getLocalIP(){ exec("ipconfig /all", $output); foreach($output as $line){ if (preg_match("/(.)IPv4 Address(.)/", $line)){ $ip = $line; $ip = str_replace("IPv4 Address. . . . . . . . . . . :","",$ip); $ip = str_replace("(Preferred)","",$ip); } } return trim($ip); } - Prem Kumar Maurya
5
有很多负面标记,但只有这个答案包含FILTER_VALIDATE_IP,如果没有过滤可能会存在重大安全问题。 - saur

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