Introduction to GeoIP

In case you’ve ever used Google Analytics or any simmilar tool where you can see exact location from where visitors of your site came from, you’ve probably wondered how they were able to dig that info. Is it magic or what? Of course, it’s not kind of magic, exact location of visitor is defined by visitor’s IP address, and technology used to locate user by his IP is well known as GeoIP.

Today we are going to look how to locate visitor of your site with PHP and Max Mind’s GeoIP database. In examples bellow we used free(lite) versions of GeoIP databases, because fully supported GeoIP databases are not free(you’d have to pay $50USD setup + $12USD update for GeoIP Country and $370USD + $90USD for GeoIP City base). Drawback of lite version is that it is not as accurate as fully supported GeoIP databases, but it is still very usefull and probably good enough for great majority of live projects.

MaxMind offer API for dozen of programming languages (full list is available here), details about PHP API are available here. This tutorial deal with so called “Pure PHP API”, there are also PECL extensions and apache mod_geoip modul available. Apache modul provide better perfomance, but Pure PHP API is easier to set up.

Just for a start let’s download all PHP API files from http://www.maxmind.com/download/geoip/api/php/, and save them somewhere inside of your Web tree(let say /htdocs/geoip). To use GeoIP Country you need to download lite database from here, and for GeoLiteCity download database from here. Just for the sake of simplicity, we are going to unpack both bases to the same dir where we saved our PHP API’s files (/htods/geoip in our example).

GeoIP Country
——————————–
Now, let’s see how country detection works:

<?php
/**
 * GeoIP Country Database Example
 *
 * @version $Id$
 * @package geoip
 * @copyright © 2006 Lampix.net
 * @author Dragan Dinic <dinke@lampix.net>
 */

require_once("geoip.inc");

$gi = geoip_open("GeoIP.dat", GEOIP_STANDARD);

$ip = $_SERVER['REMOTE_ADDR'];
//if you test on localhost use IP bellow for test
//since $_SERVER['REMOTE_ADDR'] would be 127.0.0.1
//$ip = "89.216.226.174";

$country_name = geoip_country_name_by_addr($gi, $ip);
$country_code = geoip_country_code_by_addr($gi, $ip);
if($country_name)
{
	echo "Your country is: $country_name <br />";
	echo "Country Code is: $country_code <br />";
}
else
{
	echo "Sorry, we weren't able to locate you.";
}

geoip_close($gi);
?>

So, at the beggining we’ve included geoip.inc which contains all functions needed to use GeoIP country database, then we’ve created new instance of GeoIP class with geoip_open function, and at the end we called proper functions(geoip_country_name_by_addr and geoip_country_code_by_addr) to get country name/code in which detected IP address reside. Again, in case you test localy, don’t use $_SERVER['REMOTE_ADDR'].

When you run script above you should get something like this as output:

Your country is: Serbia and Montenegro
Country Code is: CS

GeoIP City
—————————-
Now, let’s extend visitor’s country data with exact location(like city, postal code etc.)

<?php
/**
 * GeoIP City Database Example
 *
 * @version $Id$
 * @package geoip
 * @copyright © 2006 Lampix.net
 * @author Dragan Dinic <dinke@lampix.net>
 */

require_once("geoipcity.inc");

$gi = geoip_open("GeoLiteCity.dat", GEOIP_STANDARD);

$ip = $_SERVER['REMOTE_ADDR'];
//if you test on localhost use IP bellow for test
//since $_SERVER['REMOTE_ADDR'] would be 127.0.0.1
//$ip = "89.216.226.174";

$record = geoip_record_by_addr($gi, $ip);

if(!$record)
{
	echo "Sorry, we weren't able to locate you.";
}
else
{
	echo "Country: " .$record->country_name . "<br />";
	echo "Country Code: " . $record->country_code . "<br />";
	echo "Country Code 2: " . $record->country_code3 . "<br />";
	echo "Region: " .$record->region . "<br />";
	echo "City: " .$record->city . "<br />";
	echo "Postal Code: " .$record->postal_code . "<br />";
	echo "Latitude: " .$record->latitude . "<br />";
	echo "Longitude: " .$record->longitude . "<br />";
	echo "DMA Code: " .$record->dma_code . "<br />";
	echo "Area Code: " .$record->area_code . "<br />";
}

geoip_close($gi);
?>

As you see, PHP code is simmilar as in our country detection example, with exception that we used geoipcity.inc and GeoLiteCity.dat database. Function geoip_record_by_addr($gi, $ip) return instance of ‘geoiprecord’ class which contains in it’s properties location’s data we used in our example. After you run script you should get output like this one:

Country: Serbia and Montenegro
Country Code: CS
Country Code 2: SCG
Region: 02
City: Beograd
Postal Code: 11000
Latitude: 44.8186
Longitude: 20.4681
DMA Code:
Area Code:

CaseStudy – Redirection depending of Country
————————————————————–
At the end, we are going to see some real GeoIP usage. Our goal is to redirect users on multy language site(blog) to proper language section on the site depending of their location. Here is how code looks like on my own blog:

<?php
/**
 * Case Study - GeoIP Redirection
 *
 * @version $Id$
 * @package geoip
 * @copyright © 2006 Lampix.net
 * @author Dragan Dinic <dinke@lampix.net>
 */

require_once("geoip/geoip.inc");

$gi = geoip_open("geoip/GeoIP.dat",GEOIP_STANDARD);

$country_code = geoip_country_code_by_addr($gi, $_SERVER['REMOTE_ADDR']);

geoip_close($gi);

if($country_code == 'CS')
{
        header("HTTP/1.1 301 Moved Permanently");
        header('Location: http://www.dinke.net/blog/sr/');
}
else
{
        header("HTTP/1.1 301 Moved Permanently");
        header('Location: http://www.dinke.net/blog/en/');
}
?>

Above example is used on this blog in order to redirect all users located out of Serbia to english version of the blog. Sending custom 301 redirection headers is important so bots(like google etc. google) are able to index blog pages without problems.

Comments

  1. max
    October 23rd, 2007 | 1:30 pm

    good tutorial, thanks. i have to try…

  2. Roy Sinclair
    November 6th, 2007 | 8:19 am

    Great Tutorial.
    I was ready to hurt someone as i could just not get it working.

    Read the your tut and 2 mins later i have a GeoIP redirecting.

    Thx

  3. eddie
    December 13th, 2007 | 8:36 pm

    dinke, thanks for this great tutorial. but now, because i’m a newbie, so i don’t know how to figure out to detect commenter’s city, flag and country in my wordpress blog’s comment area. i just know the wordpress’s php function to detect/displaying commenter’s ip using $comment->comment_author_IP or comment_author_IP !

    i wanna the output like this one:

    comment from: city flag country

    i’ve asked in wordpress support forum, but there’s no people know to do that. once again, i’m a newbie, so please be patient. :) please tell me the way.

  4. May 15th, 2008 | 10:47 am

    [...] [...]

  5. May 21st, 2008 | 5:57 am

    Cool, I am looking for it long time, it is very happy to see it.

  6. Deus
    June 17th, 2008 | 2:32 pm

    The Redirection depending of Country does not work :S
    It redirects all surfers depending the country they are.
    Anyone knows why?

  7. Matt
    June 24th, 2008 | 10:48 pm

    yep, redirect does not work, I am in Serbia and I see the English version or this blog. oops!

  8. June 24th, 2008 | 10:52 pm

    Redirection works just fine for me, I am on SBB Network. Either your ISP IP is not listed in free db or you’re gengo cookie (plugin used for dual language blog) is set to english so you are always redirected to english version.

  9. June 24th, 2008 | 11:07 pm

    Just tested country code on my own server and got the same output as in time I wrotte this article:

    Your country is: Serbia and Montenegro
    Country Code is: CS

    See for yourself:
    http://www.dinke.net/geoip/country_test.php

  10. olaf
    July 3rd, 2008 | 7:48 pm

    Geoip country works for me, but i cant get geolite city to work no matter what i do. I have all the required files for it to work.

  11. olaf
    July 3rd, 2008 | 7:56 pm

    Oh, I found my mistake. I named geolite city, geoipcity.dat.

  12. wasabi
    September 3rd, 2008 | 12:56 am

    Thank yo for this tutorial! Work Great!

    There is only one thing. Is it possible to display the full name of the states instead of the 2 first letter of the state?

    For instance: It’s the script displays “CA” instead of “California” or it displays “FL” instead of “Florida”

    Any way to fix that?

  13. September 4th, 2008 | 1:21 am

    @wasabi
    Not sure about that, but you can always write an array map with all us states like:

    $states['FL'] = ‘Florida’;
    $states['CA'] = ‘California’;

    and then get full name from it :)

  14. low
    October 4th, 2008 | 12:58 pm

    OMG, I love you… been trying to set up a redirect for 3 days…with you, it worked like a charm! I love youuuuuuuu! Thanksssssss! :worship:

  15. October 4th, 2008 | 1:36 pm

    Haha, you really make my day lol.

  16. low
    October 4th, 2008 | 2:53 pm

    just a quick question. I want to accept onyl visitors from 2 countries. How do I add another county?

    This doesn’t work :

    if($country_code == ‘CS’ || ‘FR’)

    Thanks!

  17. October 4th, 2008 | 4:17 pm

    Of course it doesn’t :)

    Your code should be like this:

    if($country_code == ‘CS’ || $country_code == ‘FR’)

    Or if you have bigger list you can do arrays like:

    $country_list = array(‘CS’, ‘FR’, ‘US’);
    if(in_array($country_code, $country_list))
    {
    //do redirection or whatever you plan to do
    }

  18. low
    October 4th, 2008 | 5:23 pm

    Dinke, you’re my hero! I refreshed your blog page every 5 min for your reply! Thank you! Twice! And twice again. Bookmarked! Keep up the great work!

  19. Ion
    October 10th, 2008 | 6:08 pm

    Hey, thank you for the tutorial. It is very useful, i just utilized in my site. Thank you again.

  20. November 29th, 2008 | 10:08 pm

    If you are doing city geoip detection in non-english web sites, you may have issues with city name spelling. For Beograd in Serbia, geoip_record_by_addr() will return Beograd, but for some ISPs it is Belgrade or even Novi Beograd.

  21. Michael
    April 18th, 2009 | 7:42 pm

    Thank you! Thank you! Thank you!

  22. Alex
    July 21st, 2009 | 3:39 pm

    Thanks for great tutorial. Really amazing.

    Using the redirection of depending country,
    Im redirecting visitor in Canada and other countries,
    But Im stayed in Canada.

    How to allow my ip address and 2-3 ip address in the using this code.

    Tried some codes.. Not works.

    Could you tell me the way solve this.

    Thank you for great code !!!!!!!

  23. alex
    November 16th, 2009 | 4:13 am

    Loooooovvvvveeeeeeeeeeeeeeeeeee yyyyoooouuuuuu!!!!!!!!!!
    I was about to throw my computer out the window until I found this!

    I just have a question, because I’m a noob. I have multiple websites and I want to use this for all of them from the same location of the api. For example:
    If I place the ‘geoip’ folder in this location “/public_html/website-no-1″ and I have the ‘redirect.php’ in the same location, it works great.
    But if I place the ‘geoip’ folder in “/public_html”, so that I can use it for ‘website-no-1′ and ‘website-no-2′ I get an error. I’m sure it is because of this line:
    require_once(“geoip/geoip.inc”);
    but I can’t figure out what to write there instead of ‘geoip’. I’ve tried ‘/public_html/geoip’ and it doesn’t work. Please help.

  24. November 16th, 2009 | 3:27 pm

    Use absolute path for that dir on your server. For example:

    require_once(‘/home/dinke/public_html/geoip/geoip.inc’);

  25. Sapan
    October 20th, 2010 | 4:01 am

    How to redirect users based upon state. For e.g i want visitors from California to land in one.php, Florida to two.php and rest all to default.php

  26. Jarv1nho
    October 25th, 2010 | 9:35 am

    This script works a charm. I’d like to use it so that if somebody enters the site at any point, they will be directed to the equivalent url on the target site. For example, if they enter on xyz.com/ipods, they will be redirected to xyz.com/redirect/ipods. If xyz.com/games, they will go to xyz.com/redirect/games. How can I use relative urls to accomplish this?

    Thanks!

  27. November 22nd, 2010 | 6:00 pm
  28. Jason M.
    May 24th, 2011 | 9:00 pm

    Hello, You are seriously awesome for providing this tutorial. It’s really helped me get in the right direction. One problem though, could you give an example of how to redirect users based on city/region using the GeoLiteCity.dat. Basically I want to redirect everyone on the east coast to an east coast version of the site, and redirect west coast visitors to a west coast site. If I can accomplish that I will scream at the top of my lungs with happiness!! Thanks again Dinke!

  29. May 24th, 2011 | 10:04 pm

    Hello Jason,

    For checking east vs. west cost you can either check based by zipcode (postcal code) and comparing it with some huge zipcode db but probably it’s much easier to set them up depending of Latitude/Longitude.

  30. Ivana
    May 31st, 2011 | 1:19 pm

    Hi,
    Thankyou for this tutorial, i have been looking for this forever :) You are Fantastic!
    i would like to redirect by region name
    is this possible using the free databases from maxmind?

    if not, is it possible by city?, i have tried the following but it is not working because i am obviously just guessing the code :)
    although i would prefer redirect by region name…

    <?php
    /**
    * Case Study – GeoIP Redirection
    *
    * @version $Id$
    * @package geoip
    * @copyright © 2006 Lampix.net
    * @author Dragan Dinic
    */

    require_once(“geoipcity.inc”);

    $gi = geoip_open(“GeoLiteCity.dat”,GEOIP_STANDARD);

    $city = geoip_city_by_addr($gi, $_SERVER['REMOTE_ADDR']);

    geoip_close($gi);

    if($city == ‘Sydney’)
    {
    header(“HTTP/1.1 301 Moved Permanently”);
    header(‘Location: http://www.example.net/1/‘);
    }
    else
    {
    header(“HTTP/1.1 301 Moved Permanently”);
    header(‘Location: http://www.example.net/2/‘);
    }
    ?>

  31. December 12th, 2011 | 7:52 am

    [...] wpmu?? I'm using wpmu subdomains, and I tried maxmind's tutorials using country lite version, http://www.dinke.net/blog/en/2006/11/30/introduction-to-geoip/ It's working for redirection for typical single site subfolders, but when i tested in my wpmu site [...]

  32. Norman
    October 15th, 2012 | 11:01 am

    In your example $ip = “89.216.226.174″; shows
    Your country is: Serbia and Montenegro
    Country Code is: CS

    Now it shows:
    Your country is: Serbia
    Country Code is: RS

    If this happened in a production version, we’d have change things all over.

    BTW: what other option are available when it comes to country data?
    Eg: geoip_country_name_by_addr gives u the country name. Are there any more things like this?

  33. October 15th, 2012 | 10:24 pm

    That is fine since there is no longer Serbia and Montenegro, only Serbia (Montenegro is now separate country).

Leave a reply