Development PHP

Authored by Corey Ballou


Advanced Method to Retrieve the Client IP in PHP

There are perhaps hundreds if not thousands of articles on obtaining your visitor’s IP address. The majority if these entries will refer to a small subset of global $_SERVER variables (HTTP_X_FORWARDED_FOR, HTTP_CLIENT_IP, and REMOTE_ADDR). Although both fast and simple solutions utilizing nested ternary operations exist, they are generally prone to a fairly large bug. The HTTP_X_FORWARDED_FOR server directive may contain a comma delimited list of IP addresses based upon several proxy hops prior to the client request packet reaching it’s destination.

After scouring the web I came across two sites demonstrating what appears to be the most accurate IP retrieval method I have come across. I found a number of inefficiencies in the two functions so I’m going to provide you with my optimized version.

A Word of Warning

$_SERVER['REMOTE_ADDR'] still represents the most reliable source of an IP address. The other $_SERVER variables mentioned above can be spoofed by a remote client very easily. The purpose of this solution is to attempt to determine the IP address of a client sitting behind a proxy. For your general purposes, you might consider using this in combination with the IP returned directly from $_SERVER[‘REMOTE_ADDR’] and storing both. For 99.9% of users this solution will suit your needs perfectly. It will not protect you from the 0.1% of malicious users looking to abuse your system by injecting their own request headers. If relying on IP addresses for something mission critical, stick to $_SERVER['REMOTE_ADDR'] and don’t bother catering to those behind a proxy.

Update: An Optimized Solution

The following solution was the result of a StackOverflow post and makes use of PHP’s filter_var(). It’s much more succinct and easier to understand given the usage of pre-defined constants:

My Original Solution

I can’t be sure which of the two sites to credit, either Grant Burton or admin for his post here.


  1. I added isset and !empty checks within get_ip_address() to avoid a wasted call to validate_ip() if no IP needed checking
  2. In the case of the $_SERVER[‘HTTP_X_FORWARDED_FOR’] variable I added a call to strpos to determine if the variable contained a comma separated list of IPs prior to using explode and iterating over a possibly non-existent array.
  3. In validate_ip(), I did a check against the value “unknown” as it has been noted this header value is set on occasion. The check is done using strtolower to ensure that the cases match.
  4. I converted the array of private network IP address ranges to their signed integer counterparts using ip2long to speed things up as these values are merely used as a lookup.
  5. I removed the array and foreach loop and replaced it with a series of if() blocks to test whether the ip falls within invalid ranges. Since the foreach loop no longer existed, I only need one conversion from the IP address to a signed integer.
  6. As noted in the documentation for ip2long, I convert the IP address to an unsigned integer using sprintf. This alleviates the issue of the ip being converted to a negative signed integer on 32 bit machines.
  7. Since the ip is now an unsigned integer, the last if() statement can be simplified to only check that the IP is greater than the lower bound since the range carries all the way to

One thing to note is the location I placed the unsigned integer conversion in validate_ip(). It appears after the check to determine if the IP was valid because ip2long returns a -1 in the event that the ip matches If we have converted to an unsigned integer prior to the if statement, the IP would be considered valid. Doing the unsigned int conversion also allows us to simplify the last range of IPs because we know anything equal to did not enter the loop. Other simplifications included a quick check for !empty on $_SERVER variables prior to hitting validate_ip() as we dont need the overhead from making that call if we already know the variable to be invalid.

Author: Corey Ballou

Corey Ballou is the CEO of Whether you're a student, young professional, entrepreneur, startup, or small business, you can be up and online fast with your own custom domain, email, and webpage on POP. Corey is a professional PHP developer by trade, specializing in custom web applications development for startups, small businesses, and agencies. Follow Corey on Twitter @cballou.

  • Pingback: JQueryin | Securing Your PHP Sessions()

  • Yervand

    Thank you. this was really helpful for the application i’m currently developing :)

  • Pingback: PHP Most Viewed | PHP TutorialsPHP Tutorials()

  • Deepak Pradhan

    Thanks! I have been trying to figure this out as well for past few days.
    It is bookmarked, likely will be used and experience shared

  • Ron Aaron

    Thanks for the code! I need to know incoming IPs for my site, but can’t get past clever proxy users. Cheers.

  • handes

    What about IPV6 addresses?

  • chriszo111

    I just found out about these functions. Very well written, only question I have is at the lines 63, 64 in your “Original Solution” I see this:
    if ($ip >;= 3221225984 && $ip ;= 3232235520 && $ip ;=” a typo and should be “>=” ?
    Anyways thanks for this time-saving code!

  • Revathy Santhanam

    and what do you do when after all this you still get the Proxy’s IP instead of the client’s?
    i have tried a lot of solutions, but none of them work. I always end up with Proxy’s IP instead of the client’s. any help?

  • Medha

    Hello Corey,
    I want to retrieve client’s MAC address using PHP. I have a user login form (a HTML page) with a submit button. When a user clicks the button, I should be able to retrieve the user machine’s MAC address & store in my database. Is it possible ?

    Thanks in advance.