In Linux we trust!

GeoIP resolving guide

In this article i'm going to describe solution based on GeoLite2 database from MaxMind.

Let's download the database itself:

$ gl=https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz
$ wget -O- "$gl" >_.tar.gz
$ tar xvf _.tar.gz
$ mv GeoLite2-*/*.mmdb GeoIP.mmdb
$ rm -rf GeoLite2-* _.tar.gz

Keep in mind that GeoIP.mmdb should not be kept under version. Next step is to fetch PHP library that provides API:

$ curl -sS 'https://getcomposer.org/installer' | php
$ php composer.phar require geoip2/geoip2

Test it:

include 'vendor/autoload.php';

$geoReader = new \GeoIp2\Database\Reader('GeoIP.mmdb');
$record = $geoReader->country('8.8.8.8');
$country = $record->country->isoCode ?? '';
// $country => "US"

Till now everything is pretty simple. Let's install C extension for PHP in order to increase the performance of lookups in databases. First step is to install system library libmaxminddb the extension works with:

$ git clone --recursive https://github.com/maxmind/libmaxminddb
$ cd libmaxminddb
$ ./bootstrap
$ ./configure
$ make
$ sudo make install
$ sudo ldconfig

Install extension:

$ git clone https://github.com/maxmind/MaxMind-DB-Reader-php
$ cd MaxMind-DB-Reader-php/ext
$ phpize
$ ./configure
$ make
$ sudo make install

Make sure you have PHP development package installed (in my case php7.2-dev). After all correct your php.ini to load this extension.

$ echo extension=maxminddb.so | \
>   sudo tee -a /etc/php/7.2/{cli,fpm}/php.ini >/dev/null
$ php -m | grep maxminddb
maxminddb

Your path to php.ini can differ from mentioned above.

In order to benchmark your GeoIP module you can use following script:

<?php // benchmark.php

include 'vendor/autoload.php';

$geoReader = new \GeoIp2\Database\Reader('GeoIP.mmdb');

foreach (range(1, 10000) as $ip) {
    try {
        $record = $geoReader->country(long2ip(crc32($ip)));
        $country = $record->country->isoCode ?? '';
    } catch (Exception $e) {
    }
}
$ time php benchmark.php
real    0m1.545s
user    0m1.252s
sys     0m0.060s

I figured out that C extension works at least 20 times faster. Good luck!