PHP most accurate / safe way to get real user IP address in 2017

Viewed 13230

What is the most accurate way to get user's IP address in 2017 via PHP?

I've read a lot of SO questions and answers about it, but most of answers are old and commented by users that these ways are unsafe.

For example, take a look at this question (2011): How to get the client IP address in PHP?

Tim Kennedy's answer contains a recommendation to use something like:

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

But as I've read a lot, I have seen that to use X_FORWARDED_FOR is unsafe, as the comment below highlights:

Do NOT use the above code unless you know EXACTLY what it does! I've seen MASSIVE security holes due to this. The client can set the X-Forwarded-For or the Client-IP header to any arbitrary value it wants. Unless you have a trusted reverse proxy, you shouldn't use any of those values.

As I didn't know EXACTLY what it does, I don't want to take the risk. He said it is unsafe, but did not provide a safe method to get user's IP address.

I've tried the simple $_SERVER['REMOTE_ADDR'];, but this returns the wrong IP. I've tested this and my real IP follows this pattern: 78.57.xxx.xxx, but I get an IP address like: 81.7.xxx.xxx

So do you have any ideas?

10 Answers
  1. Because of different network setups (proxy servers, private networks, etc.) and how administrators configure their networks, it is difficult to obtain the client IP address. Standards are being addressed related to this issue.

  2. The following function worked in 4 different tests (Home Network, VPN, Remote connection, public internet). The code can be used as base code for your project. Modify as needed.

  3. The function does validate the IP address, but does not validate IP ranges. This would be an additional test after you obtain the client IP.

  4. $_SERVER["REMOTE_ADDR"] does not always return the true client IP address.

  5. Because some of the parameters can be set by end users, security can be an issue.

Set Client IP address

$clientIpAddress = $du->setClientIpAddress($_SERVER);

public function setClientIpAddress($serverVars) {
    # Initialization
    $searchList = "HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR,HTTP_X_FORWARDED,HTTP_X_CLUSTER_CLIENT_IP,HTTP_FORWARDED_FOR,HTTP_FORWARDED,REMOTE_ADDR";
    $clientIpAddress = "";

    # Loop through parameters
    $mylist = explode(',', $searchList);
    foreach ($mylist as $myItem) {
        # Is our list set?
        if (isset($serverVars[trim($myItem)])) {
            # Loop through IP addresses
            $myIpList = explode(',', $serverVars[trim($myItem)]);
            foreach ($myIpList as $myIp) {
                if (filter_var(trim($myIp), FILTER_VALIDATE_IP)) {
                    # Set client IP address
                    $clientIpAddress = trim($myIp);

                    # Exit loop
                    break;
                }
            }
        }

        # Did we find any IP addresses?
        if (trim($clientIpAddress) != "") {
            # Exit loop
            break;
        }
    }

    # Default (if needed)
    if (trim($clientIpAddress) == "") {
        # IP address was not found, use "Unknown"
        $clientIpAddress = "Unknown";
    }

    # Exit
    return $clientIpAddress;
}
Related