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.