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

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


当前回答

$_SERVER['REMOTE_ADDR']可能不包含真实的客户端IP地址,例如,它会为通过代理连接的客户端提供一个代理地址。这可能 不过,这是你真正想要的,取决于你如何处理ip。某人的私有RFC1918地址可能对你没有任何好处,如果你试图查看你的流量来自哪里,或者记住用户最后从哪个IP连接,代理或NAT网关的公共IP可能更适合存储。

有几个HTTP报头,如X-Forwarded-For,可以由各种代理设置,也可以不设置。问题是这些只是HTTP头,任何人都可以设置。他们的内容没有保证。$_SERVER['REMOTE_ADDR']是web服务器接收到连接的实际物理IP地址,响应将被发送到该地址。其他任何信息都是随意和自愿的。只有一种情况下您可以信任此信息:您正在控制设置此报头的代理。意思只有当你知道100%的头是在哪里和如何设置,你应该注意它的任何重要的。

话虽如此,下面是一些示例代码:

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

其他回答

这个函数应该能正常工作

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

如果您不喜欢使用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;
}

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

我喜欢这样的代码:

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

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