Fedora 29のGeoLite2を使って、アクセス元に応じてページの表示内容を微妙に変えるようにしてみた。

By | 2018年12月9日

はじめに

本Webサイトは日本語で記述されているサイトなんですが、画像やYouTubeのチャンネルの動画を貼り付けていることもあってか、日本国外からのアクセスもそれなりにあります。

特にYouTubeのチャンネルの動画を貼っておくと、言いたいことは(少なくとも文章だけで書くよりは)伝わるので、YouTubeのチャンネルは重宝しております。

日本国外からのアクセスは50%には程遠いレベルではありますが、少しずつ増えてきてはいますので、GeoLite2を使ってアクセス元の国を調べ、それがわかる場合には各ページの表示内容を微妙に変えてみることにしました。

この記事ではGeoLite2の簡単な使い方からWordpressへの組み込みの方法について書いていきます。

スポンサーリンク

GeoLite2のセットアップ

パッケージのインストール状況の確認

まず、GeoLite2が本Webサイトを運用中のサーバにインストールされているかどうかを確認します。

以下のコマンドを実行します。

[panda@pantenote.info ~]$ rpm -qa | grep geolite2 geolite2-country-20181002-1.fc29.noarch geolite2-city-20181002-1.fc29.noarch

 
インストールされているようです。(`・ω・´)

これがこの記事を最初に書いた時点(2018年12月)における最新版のようです。

インストールされている場所及びその状況の確認。

次に、インストールされている場所と、その状況を確認します。

以下のコマンドを実行します。

[panda@pantenote.info ~]$ rpm -ql geolite2-country /usr/share/GeoIP /usr/share/GeoIP/GeoLite2-Country.mmdb /usr/share/licenses/geolite2-country /usr/share/licenses/geolite2-country/COPYRIGHT.txt /usr/share/licenses/geolite2-country/LICENSE.txt

 
データベースの本体は/usr/share/GeoIPの下にインストールされているようです。

PHP用のAPIのインストール

データベースのインストールの状況が確認できたところで、Fedora 29がインストールされているPC上において、以下の手順でPHP用のAPI(GeoIP2-php)をインストールします。GeoLite2を公開しているMaxMind社は有償版であるGeoIP2も開発していますが、PHP用のAPIについてはGeoIP2用のものが使用できるようです。

  1. 適当なところにcomposer.pharを置くためのディレクトリを作ります。ここでは仮に”GeoIP2-php-test”という名前のディレクトリを作成したものとします。
  2. 手順1で作成したディレクトリの下で以下のコマンドを実行し、composite.pharをダウンロードします。
    [panda@pantenote.info ~]$ curl -sS https://getcomposer.org/installer | php

     

  3. GeoIP2-phpをインストールしたいディレクトリの下でroot権限で以下のコマンドを実行します。インストール先は/usr/share/php/GeoIP2-phpの下としました。

    スポンサーリンク

    なお、composer.pharはroot権限では実行しない方がよいとのことだったので、上記のディレクトリのownerを一般ユーザに変更してからインストールを行っています。

    # mkdir -p /usr/share/php/GeoIP2-php # chown panda:panda /usr/share/php/GeoIP2-php # exit [panda@pantenote.info ~]  php <GeoIP2-php-test directory>/composer.phar require geoip2/geoip2:~2.0

     

  4. すると、以下のメッセージが出力されてインストールが完了します。
    [panda@pantenote.info ~]$ php <GeoIP2-php-test directory>/composer.phar require geoip2/geoip2:~2.0 ./composer.json has been created Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 4 installs, 0 updates, 0 removals – Installing composer/ca-bundle (1.1.3): Loading from cache – Installing maxmind/web-service-common (v0.5.0): Loading from cache – Installing maxmind-db/reader (v1.4.0): Loading from cache – Installing geoip2/geoip2 (v2.9.0): Loading from cache maxmind-db/reader suggests installing ext-bcmath (bcmath or gmp is required for decoding larger integers with the pure PHP decoder) maxmind-db/reader suggests installing ext-maxminddb (A C-based database decoder that provides significantly faster lookups) Writing lock file Generating autoload files

     

  5. …が、「ext-bcmath及びext-maxminddbをインストールするよう」にお勧めされていますので、root権限で以下のコマンドを実行し、インストールします。Fedora 29ではphp-bcmath及びphp-maxminddbが相当するパッケージのようです。
    # dnf install php-bcmath php-maxminddb

     

これでインストールは完了です。

試しに使ってみる。

Revised City Example

ここまでできたところで、動作確認のためにGeoIP2-phpのサイトにある”City Example”のコードを本Webサイトが稼働している環境に合わせてちょっと変更したものを作ってみます。

<?php
require_once '/usr/share/php/GeoIP2-php/vendor/autoload.php';
use GeoIp2\Database\Reader;
// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader('/usr/share/GeoIP/GeoLite2-City.mmdb');
// Replace "city" with the appropriate method for your database, e.g.,
// "country".
reader->city('128.101.101.101');
print($record->country->isoCode . "\n"); // 'US'
print($record->country->name . "\n"); // 'United States'
print($record->country->names['ja'] . "\n"); // 'アメリカ合衆国'
print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'
print($record->city->name . "\n"); // 'Minneapolis'
print($record->postal->code . "\n"); // '55455'
print($record->location->latitude . "\n"); // 44.9733
print($record->location->longitude . "\n"); // -93.2323
?>

実行してみると…

[panda@pandanote.info GeoIP2-php-test]$ php GeoLite2-city-example-test.php US United States アメリカ合衆国 Minnesota MN Minneapolis 55455 44.9733 -93.2323

 
といった感じになります。

Country Example


スポンサーリンク

この記事でやろうとしているWordpressへの組み込みのためにはアクセス元の国の情報があれば十分なので、上記のコードを元に”Country Example”を作ってみました。

以下のような感じになります。

<?php
require_once '/usr/share/php/GeoIP2-php/vendor/autoload.php';
use GeoIp2\Database\Reader;
// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader('/usr/share/GeoIP/GeoLite2-Country.mmdb');
// Replace "city" with the appropriate method for your database, e.g.,
// "country".
reader->country('128.101.101.101');
print($record->country->isoCode . "\n"); // 'US'
print($record->country->name . "\n"); // 'United States'
print($record->country->names['ja'] . "\n"); // 'アメリカ合衆国'
?>

コードの量がかなり少なくなりました。(´・ω・`)

実行してみると…

[panda@pandanote.info GeoIP2-php-test]$ php GeoLite2-country-example-test.php US United States アメリカ合衆国

 
といった感じになります。

上記のコードにちょっと追加したプログラムをFedora 29上で実行すると以下のような感じになります。

WordPressへの組み込み。

組み込んだコード例

スポンサーリンク

動作が確認できたところで、Wordpressに組み込みます。

GeoLite2のAPIはサーバに置かれたデータベースのファイルから検索を行いますので、パフォーマンス的には悪くはないと思います。

そうはいっても、結果のわかっている同じ処理を繰り返すのは効率が悪いので、1回のアクセスあたりのデータベースのファイルへの検索はできるだけ少ない回数になるようなプログラムにしておくと、国名を調べることによるWebページのレスポンスへの影響を最小限とすることができます。

上記のことに留意しつつ、functions.phpに以下のコードを追加します。

<?php
require_once '/usr/share/php/GeoIP2-php/vendor/autoload.php';
use GeoIp2\Database\Reader;
function get_country_isocode() {
global $country_isocode;
if (empty($country_isocode)) {
$reader = new Reader('/usr/share/GeoIP/GeoLite2-Country.mmdb');
reader->country($_SERVER["REMOTE_ADDR"]);
record->country->isoCode;
}
return $country_isocode;
}
?>

上記のコードを追加した上で、functions.phpの他の部分で以下のように書くと、アクセス元の国に応じて表示内容を変えることができます。

if (get_country_isocode() !== ‘JP’) { // 日本国内向けの処理 } else { // 日本国外向けの処理 }

 
本Webサイトでは、以下のような表示内容の切り替えを行っています。Amazonアソシエイトの広告は日本国外からのアクセスに対しては表示をしても意味がなさそうなので、Google AdSenseのバナー広告に切り替えることにしました。

  • 日本国内向け: Amazonアソシエイトのバナー広告
  • 日本国外向け: Google AdSenseのバナー広告

動作の確認。

動作確認は海外からアクセスしないとできない…

ということはなくて、上記のfunctions.phpへの追加用のコードのうち、9行目の引数を日本国外のIPアドレスに置き換えて、表示が切り替わることを確認しました。

あとは、$_SERVER[’REMOTE_ADDR’]変数を全面的に信頼するしかありません。(´・ω・`)

まとめ

この記事で書いたようなIP Geolocation的なことは精度を上げようとするとそれなりのリソースと労力が必要ですが、広告の種類を切り替えるといったような厳密さを求められない用途であれば、GeoLite2程度の精度で十分なのではないかと思います。

また、アクセス元の国を知る目的としては「守りを固める」的な用途の方が多数派かとは思いますが、それ以外の用途も考えてみるのもまた一興なのではないかと思いました。

この記事は以上です。

References / 参考文献