MaxMind seem to be the only company that offer some level of free geolocation. You do, however, have to delve into their site (or google it) to find the Open Source section where you can download the free binary database and look at the documentation. To give MaxMind some credit though their documentation is excellent and examples are offered in many programming languages.
So why this blog post?
Well firstly to promote MaxMinds service and willingness to provide a free database to all (even if it is a cunning ploy to sign people up to the paid version) and secondly to extend the PHP example somewhat and help others to understand what’s going on.
The database is essentially a huge lookup table and the associated PHP file will parse the binary file into something a little more searchable. They release a new version of this database monthly so in theory if you have a CRON job setup to fetch the file (or a reminder if you want something a little simpler) then staying up to date couldn’t be easier.
So… A code example and integration information
With any system like this, Integration is the hardest part. Getting their code sample shoehorned into place within your code and making sure that the database is updated regularly are things that might put some people off a bit.
The result of having the PHP include and the database (free version is 1 megabyte) is that you can then pass an IP address into a function and it will return the country in which the user resides. The following block of code is a class based version of the sample.php file that maxmind have supplied in their PHP examples section.
define ('GEOIP_BIN_PATH', '/path/to/GeoIP.dat');
$geoip = new geoip_class();
class geoip_class {
private $gi = false;
function __construct($bin_path = GEOIP_BIN_PATH) {
require_once('geoip.include.php');
$this->gi = geoip_open($bin_path, GEOIP_STANDARD);
}
function __destruct() {
$this->gi = geoip_close($this->gi);
}
function country_code($ip) {
return geoip_country_code_by_addr($this->gi, $ip);
}
function country_name($ip) {
return geoip_country_name_by_addr($this->gi, $ip);
}
function where_am_i_name() {
return $this->country_name($_SERVER['REMOTE_ADDR']);
}
function where_am_i_code() {
return $this->country_code($_SERVER['REMOTE_ADDR']);
}
function where_am_i() {
$return = array();
$return['name'] = $this->country_name($_SERVER['REMOTE_ADDR']);
$return['code'] = $this->country_code($_SERVER['REMOTE_ADDR']);
return $return;
}
}
The class has a few more helper methods inside it but it is still essentially what maxmind had intended from their example. Using the above code will do nothing at present except for instantiate a new version of the geoip_class class. However the advantage of using a class like this is that it will always work when used in a situation where you can’t control the other code that might be running at the same time.
For example, if this were to be used within a WordPress plugin then technically the blog owner could be using another plugin that declares and uses the same functions which would cause a fatal error thus killing the site.
Usage
Adding this code into yours now couldn’t be simpler because all you need to do is update the define (at the top of my example), download the latest DAT file, and use the following ‘Where am I’ example as a guide.
$geoip = new geoip_class(); echo $geoip->where_am_i_name();
Updating the database file
There are a couple of ways to do this but here is a simple bash script (again an updated version of MaxMinds WGET example) to update the file (only when necessary) every time it’s called.
#!/bin/bash UNGZIPPED_FILE=GeoIP.dat GZIP_FILE=GeoIP.dat.gz REMOTE_PATH=http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/ LOCAL_PATH=/tmp/ LOCAL_FINAL_PATH=/www/vhtdocs/geo_ip/ #update this to your directory of choice cd $LOCAL_PATH wget -N -q $REMOTE_PATH$GZIP_FILE gunzip $GZIP_FILE cp -f $UNGZIPPED_FILE $LOCAL_FINAL_PATH$UNGZIPPED_FILE exit
The above example will get the file from MaxMind and copy it to a path of your choice updating any existing files that are there or adding it if it isn’t. It could do with having some error checking adding for example if the file failed to download or the permissions are incorrect on the copy path. However, use it as an example and extend as appropriate but as long as you run it as a root user and all destination directories exist then you will be fine.
It could be simply added to your CRONTAB on a daily or monthly schedule and you can forget about it forever (or at least until either the location of your local DAT file changes or they relocate the remote version). Make sure that if you do use CRONTAB to add it onto that of a priviledged user who has access to all the locations specified in the file.
Resources
Here are a few key pages on MaxMinds site that I used to compile this tutorial
http://www.maxmind.com/app/php
http://geolite.maxmind.com/download/geoip/api/php/
http://www.maxmind.com/app/geolitecountry
http://www.maxmind.com/app/installation
