geek notes for advice seekers

$_SERVER[‘HTTP_X_FORWARDED_FOR’] returns multiple IPs, what to do?

Before reading this article, you should know that HTTP_X_FORWARDED_FOR should only be used for websites behind a proxy, otherwise you should use REMOTE_ADDR!! This article talks about getting the right visitor IP through HTTP_X_FORWARDED_FOR for applications behind a reverse proxy!

You might have faced it as it’s not so well documented. Note that i’m using nginx as reverse proxy, and this may not be the case with all the servers.

Yes HTTP_X_FORWARDED_FOR might return multiple IPs. And i’ve read multiple bogus statements on internet saying the first IP is the right one. This is incorrect.

The first IP may be the real client behind many proxies, but it can be fake (modified through headers).

So what is correct is to get the LAST IP from the list of IPs, which is the IP that connected to your (reverse) proxy, this is what you probably need in 99% of cases, trust me.

Here is the code in PHP:

$ip_array=explode(“,”, $_SERVER[‘HTTP_X_FORWARDED_FOR’]);


, , ,

4 Responses to “$_SERVER[‘HTTP_X_FORWARDED_FOR’] returns multiple IPs, what to do?”

  • Strablet says:

    Thanks for explaining the array bit. I’ve been reading a ton and it looks like everyone uses the same standard code. They don’t even bother to correct the crappy sad English in the comments when they copy and past it. So I took what you wrote and here is what I’m using:

    //returns the real ip address of a user (really?)
    function getRealIpPlus(){

    $ip="unknown"; //catch the missed 1%

    if (strstr(strtolower($_SERVER['HTTP_USER_AGENT']), 'mobile') || strstr(strtolower($_SERVER['HTTP_USER_AGENT']), 'android')) { //check for mobile devices
    $ip = "mobile";

    elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) { //check if IP is from shared Internet

    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { //check if IP is passed from proxy
    $ip_array=explode(“,”, $_SERVER['HTTP_X_FORWARDED_FOR']);
    $ip=trim($ip_array[count($ip_array) - 1]);

    elseif (!empty($_SERVER['REMOTE_ADDR'])) { //standard IP check

    return $ip;

    So I end up with two things in my table, “unknown” and “mobile”, along with a list of IPs. I haven’t tested this at work yet, where I usually can’t catch the IP. But I’d never tried to explode the array before, like you suggested. Thanks again.

  • kevin says:

    Hi Strablet,

    The point of my article is to say: it’s useless to find which proxy may be the good one, just use the last IP in the x_forwarded_for header. Users will use other proxies? Well that’s not a problem, anyway not all proxies add this header. Just get the IP connecting and nothing more, the rest is UNRELIABLE.

    Also, my article is for backends behind reverse proxies, if you don’t have a reverse proxy: x_forwarded_for is unreliable, use REMOTE_ADDR!

    Better block “real” proxies that some people are abusing of, than fake IPs, or you may end up with problems in some cases.

  • Stephan says:

    To shorten the script i use the following one liner:

    $ip = trim(end(explode(‘,’, $_SERVER[‘HTTP_X_FORWARDED_FOR’])));

    instead of

    $ip_array=explode(“,”, $_SERVER[‘HTTP_X_FORWARDED_FOR’]);
    $ip=trim($ip_array[count($ip_array) – 1]);


  • Ron Jeremy says:

    It’s better if you use this:
    $ip = stristr($_SERVER[‘HTTP_X_FORWARDED_FOR’], ‘,’) ? trim(end(explode(‘,’, $_SERVER[‘HTTP_X_FORWARDED_FOR’]))) : $_SERVER[‘HTTP_X_FORWARDED_FOR’];

    This way you will also get the right IP if there are no multiple addresses.

Leave a Reply

Your email address will not be published.