php PHP获取客户端IP地址的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3003145/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 08:23:26  来源:igfitidea点击:

How to get the client IP address in PHP

phpenvironment-variablesip-address

提问by Anup Prakash

How can I get the client IP address using PHP?

如何使用 PHP 获取客户端 IP 地址?

I want to keep record of the user who logged into my website through his/her IP address.

我想记录通过他/她的 IP 地址登录我网站的用户。

回答by Emil Vikstr?m

Whatever you do, make sure not to trust data sent from the client. $_SERVER['REMOTE_ADDR']contains the real IP address of the connecting party. That is the most reliable value you can find.

无论您做什么,请确保不要信任从客户端发送的数据。$_SERVER['REMOTE_ADDR']包含连接方的真实 IP 地址。这是您能找到的最可靠的值。

However, they can be behind a proxy server in which case the proxy may have set the $_SERVER['HTTP_X_FORWARDED_FOR'], but this value is easily spoofed. For example, it can be set by someone without a proxy, or the IP can be an internal IP from the LAN behind the proxy.

但是,它们可能位于代理服务器后面,在这种情况下,代理可能已设置$_SERVER['HTTP_X_FORWARDED_FOR'],但此值很容易被欺骗。例如,它可以由没有代理的人设置,或者 IP 可以是来自代理后面 LAN 的内部 IP。

This means that if you are going to save the $_SERVER['HTTP_X_FORWARDED_FOR'], make sure you alsosave the $_SERVER['REMOTE_ADDR']value. E.g. by saving both values in different fields in your database.

这意味着如果您要保存$_SERVER['HTTP_X_FORWARDED_FOR'],请确保您保存该$_SERVER['REMOTE_ADDR']值。例如,将两个值保存在数据库的不同字段中。

If you are going to save the IP to a database as a string, make sure you have space for at least 45 characters. IPv6is here to stay and those addresses are larger than the older IPv4 addresses.

如果您要将 IP 作为字符串保存到数据库中,请确保您有至少45 个字符的空间。IPv6将继续存在,并且这些地址比旧的 IPv4 地址大。

(Note that IPv6 usually uses 39 characters at most but there is also a special IPv6 notation for IPv4 addresseswhich in its full form can be up to 45 characters. So if you know what you are doing you can use 39 characters, but if you just want to set and forget it, use 45).

(请注意,IPv6 通常最多使用 39 个字符,但IPv4 地址也有一种特殊的IPv6 表示法,其完整形式最多可达 45 个字符。因此,如果您知道自己在做什么,则可以使用 39 个字符,但如果您只想设置并忘记它,使用45)。

回答by Tim Kennedy

$_SERVER['REMOTE_ADDR']may not actually contain real client IP addresses, as it will give you a proxy address for clients connected through a proxy, for example. That may well be what you really want, though, depending what your doing with the IPs. Someone's private RFC1918 address may not do you any good if you're say, trying to see where your traffic is originating from, or remembering what IP the user last connected from, where the public IP of the proxy or NAT gateway might be the more appropriate to store.

$_SERVER['REMOTE_ADDR']可能实际上并不包含真实的客户端 IP 地址,因为它会为您提供一个代理地址,用于通过代理连接的客户端,例如。不过,这很可能是您真正想要的,这取决于您对 IP 的处理方式。某人的私有 RFC1918 地址可能对您没有任何好处,如果您想查看您的流量来自何处,或记住用户上次连接的 IP,代理或 NAT 网关的公共 IP 可能更多适合存放。

There are several HTTP headers like X-Forwarded-Forwhich may or may not be set by various proxies. The problem is that those are merely HTTP headers which can be set by anyone. There's no guarantee about their content. $_SERVER['REMOTE_ADDR']is the actual physical IP address that the web server received the connection from and that the response will be sent to. Anything else is just arbitrary and voluntary information. There's only one scenario in which you can trust this information: you are controlling the proxy that sets this header. Meaning only if you know 100% where and how the header was set should you heed it for anything of importance.

有几个 HTTP 标头,例如X-Forwarded-For可能会或可能不会由各种代理设置。问题是那些只是任何人都可以设置的 HTTP 标头。不能保证他们的内容。$_SERVER['REMOTE_ADDR']是 Web 服务器从其接收连接并将响应发送到的实际物理 IP 地址。其他任何东西都只是任意和自愿的信息。只有一种情况您可以信任此信息:您正在控制设置此标头的代理。这意味着只有当您 100% 知道标题的设置位置和方式时,您才应该注意它的任何重要事项。

Having said that, here's some sample code:

话虽如此,这里有一些示例代码:

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'];
}

Editor's note:Using the above code has security implications. The client can set all HTTP header information (ie. $_SERVER['HTTP_...) to any arbitrary value it wants. As such it's far more reliable to use $_SERVER['REMOTE_ADDR'], as this cannot be set by the user.

编者注:使用上述代码有安全隐患。客户端可以将所有 HTTP 头信息(即$_SERVER['HTTP_...)设置为它想要的任意值。因此,使用更可靠$_SERVER['REMOTE_ADDR'],因为用户无法设置。

From: http://roshanbh.com.np/2007/12/getting-real-ip-address-in-php.html

来自:http: //roshanbh.com.np/2007/12/getting-real-ip-address-in-php.html

回答by josh123a123

Here is a cleaner code sample of a good way to get the IP address of the user.

这是获取用户 IP 地址的好方法的更清晰的代码示例。

$ip = $_SERVER['HTTP_CLIENT_IP'] ? $_SERVER['HTTP_CLIENT_IP'] : ($_SERVER['HTTP_X_FORWARDED_FOR'] ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']);

Here is a shorter version that uses the elvis operator:

这是使用 elvis 运算符的较短版本:

$_SERVER['HTTP_CLIENT_IP'] ? : ($_SERVER['HTTP_X_FORWARDED_FOR'] ? : $_SERVER['REMOTE_ADDR']);

Here is a version that uses isset to remove notices (thank you, @shasi kanth):

这是一个使用 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'];

回答by Kyle Cronin

It should be contained in the $_SERVER['REMOTE_ADDR']variable.

它应该包含在$_SERVER['REMOTE_ADDR']变量中。

回答by algorhythm

My favourite solution is the way Zend Framework 2 uses. It also considers the $_SERVERproperties HTTP_X_FORWARDED_FOR, HTTP_CLIENT_IP, REMOTE_ADDRbut it declares a class for it to set some trusted proxies and it returns one IP address not an array. I think this is the solution that comes closest to it:

我最喜欢的解决方案是 Zend Framework 2 使用的方式。它还考虑$_SERVER属性HTTP_X_FORWARDED_FOR, HTTP_CLIENT_IPREMOTE_ADDR但它声明了一个类来设置一些受信任的代理,并返回一个 IP 地址而不是数组。我认为这是最接近它的解决方案:

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;
    }

    // [...]
}

See the full code here: https://raw.githubusercontent.com/zendframework/zend-http/master/src/PhpEnvironment/RemoteAddress.php

在此处查看完整代码:https: //raw.githubusercontent.com/zendframework/zend-http/master/src/PhpEnvironment/RemoteAddress.php

回答by K.Suthagar

There are different types of users behind the Internet, so we want to catch the IP address from different portions. Those are:

Internet 背后有不同类型的用户,因此我们希望从不同的部分捕获 IP 地址。那些是:

1. $_SERVER['REMOTE_ADDR']- This contains the real IP address of the client. That is the most reliable value you can find from the user.

1.$_SERVER['REMOTE_ADDR']- 这包含客户端的真实 IP 地址。这是您可以从用户那里找到的最可靠的值。

2. $_SERVER['REMOTE_HOST']- This will fetch the host name from which the user is viewing the current page. But for this script to work, hostname lookups on inside httpd.conf must be configured.

2.$_SERVER['REMOTE_HOST']- 这将获取用户正在查看当前页面的主机名。但是为了让这个脚本工作,必须配置在 httpd.conf 中的主机名查找。

3. $_SERVER['HTTP_CLIENT_IP']- This will fetch the IP address when the user is from shared Internet services.

3.$_SERVER['HTTP_CLIENT_IP']- 当用户来自共享 Internet 服务时,这将获取 IP 地址。

4. $_SERVER['HTTP_X_FORWARDED_FOR']- This will fetch the IP address from the user when he/she is behind the proxy.

4.$_SERVER['HTTP_X_FORWARDED_FOR']- 当他/她在代理后面时,这将从用户那里获取 IP 地址。

So we can use this following combined function to get the real IP address from users who are viewing in diffrent positions,

所以我们可以使用下面这个组合函数,从不同位置的用户那里得到真实的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;
}

回答by manuelbcd

The following is the most advanced method I have found, and I have already tried some others in the past. It is valid to ensure to get the IP address of a visitor (but please note that any hacker could falsify the IP address easily).

以下是我找到的最先进的方法,过去我已经尝试过其他一些方法。确保获取访问者的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;
}

回答by kainosnous

The answer is to use $_SERVERvariable. For example, $_SERVER["REMOTE_ADDR"]would return the client's IP address.

答案是使用$_SERVER变量。例如,$_SERVER["REMOTE_ADDR"]将返回客户端的 IP 地址。

回答by Johan Wikstr?m

I like this codesnippet:

我喜欢这个代码片段:

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');
}