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.