City-Level Geo IP Location Detection In PHP and Apache
Following is a quick set of instructions to set up city-level location detection using Maxmind’s GeoIP library using Apache/PHP.
There’re multiple ways to do it. Frankly the trickiest part is figuring-out the most appropriate one. I think the most efficient approach in cost/performance terms is to install C API and then let mod_geoip Apache module interface with it, getting parsed values as part of the $_SERVER variable on the PHP side. There’re some wrapper PHP libraries on top of C library, as well as pure-PHP libraries, but the former did not really work, while the latter is supposed to be much slower than C lib/mod_geoip.
So here we go:
Install GeoIP C API
$ mkdir ~/src
$ cd src
$ wget http://geolite.maxmind.com/download/geoip/api/c/GeoIP.tar.gz
$ tar xzvf GeoIP.tar.gz
$ cd GeoIP-1.4.8
$ ./configure
$ make
$ sudo make install
Install Apache GeoIP module
$ cd ..
$ wget http://geolite.maxmind.com/download/geoip/api/mod_geoip2/mod_geoip2_1.2.7.tar.gz
$ tar xzvf mod_geoip2_1.2.7.tar.gz
$ cd mod_geoip2_1.2.7
$ sudo /usr/sbin/apxs -i -a -L/usr/local/lib -I/usr/local/include -lGeoIP -c mod_geoip.c
At the very end, you should get an output like:
[activating module `geoip' in /etc/httpd/conf/httpd.conf]
Please note the Apache config file’s path and in that file, after the LoadModule instruction for geoip (which installation steps above will add automatically) add the following instruction:
<IfModule mod_geoip.c>
GeoIPEnable On
GeoIPScanProxyHeaders On
GeoIPDBFile /usr/local/share/geoip/GeoIP.dat
GeoIPDBFile /usr/local/share/geoip/GeoLiteCity.dat
</IfModule>
Now, let’s download the binary database (.dat) files indicated in the config in those locations:
$ cd /usr/local/share
$ mkdir geoip
$ cd geoip
$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
$ gunzip GeoIP.dat.gz
$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
$ gunzip GeoLiteCity.dat.gz
Once you are done setting up, restart Apache and configure a test script to inspect the contents of the new $_SERVER variable, you should see output like:
Array
(
[GEOIP_ADDR] => #CENSORED#
[GEOIP_CONTINENT_CODE] => NA
[GEOIP_COUNTRY_CODE] => US
[GEOIP_COUNTRY_NAME] => United States
[GEOIP_REGION] => VA
[GEOIP_REGION_NAME] => Virginia
[GEOIP_CITY] => #CENSORED#
[GEOIP_DMA_CODE] => #CENSORED#
[GEOIP_METRO_CODE] => #CENSORED#
[GEOIP_AREA_CODE] => #CENSORED#
[GEOIP_LATITUDE] => #CENSORED#
[GEOIP_LONGITUDE] => #CENSORED#
[GEOIP_POSTAL_CODE] => #CENSORED#
)
I put “#CENSORED#” for some values, but obviously there should be actual values present that you can use in your PHP app.
I believe that there’re instructions on the web for installing and configuring similar setup for Nginx and Light HTTPD as well. Approach should be very similar.
Enjoy.