開発室ブログ

PHP

GeoLite2を使ってIPアドレスから国・地域情報を得る

業務用に限らず、WEBアプリケーションを制作していると、、、

  • 住んでいる国・地域によって、アクセスされたとき適切な言語の切り替えて表示したい
  • 住んでいる国・地域によって、アクセスされたときのランディングページの表示コンテンツを変えたい
  • アクセスしてきた人の国・地域属性を記録しておきたい。
  • いや、そもそも特定の国・地域からのアクセスを禁止したい

といった使用要求に出くわす事が多くあります。

どうやって実装するか?
住んでいる国の情報は、リクエスト時に得られる情報から判別することはできないので、単にアクセス元のIPアドレスを取得して、それを元に国・地域の情報を割り出す。というやり方になると思います。

この「IPから国・地域の情報を割り出す」ことを、GeoIPとか、IP GeoIP Geolocationとか言ったりします。

IPアドレスは、国・地域別に割当られていますので、それを得ればアクセス元の国・地域をある程度把握することが可能です。

そもそも、IPアドレスは誰が割当、管理してるのか?
WEBの世界は、色んな組織が絡んでいて魑魅魍魎な世界だったしますが、IPアドレスに関しては、RIR(Regional Internet Registry = 地域インターネットレジストリ)という団体が管理しているそうです。

地域インターネットレジストリ

wikiにもあるように、全世界でエリア別に5団体あり、その上位団体はNRO(Number Resource Organization)という団体で、国・地域別にJPINCのような下位団体がある。という構造になっている模様。

彼らがIPアドレス配分の実権を握っている模様ですが、一応、「どのIPアドレスがどの国に割り当てられているか?」は公開されています。

団体名(担当地域) データURL
ARIN(北米) ftp://ftp.arin.net/pub/stats/arin/delegated-arin-extended-latest
RIPE(欧州、中東、中央アジア ftp://ftp.ripe.net/pub/stats/ripencc/delegated-ripencc-latest
APNIC(アジア、太平洋地域) ftp://ftp.apnic.net/pub/stats/apnic/delegated-apnic-latest
LACNIC(中南米カリブ海 ftp://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-latest
AFRINIC(アフリカ) ftp://ftp.afrinic.net/pub/stats/afrinic/delegated-afrinic-latest

ファイルの中身を見てもらえばわかりますが、フォーマットが特殊・・・
1行ごとのレコードはパイプで区切られていて、

registry|cc|type|start|value|date|status[|extensions...]

RIR statistics exchange format – APNIC

という並びらしいですが、これをそのままデータベースとするような感じじゃないですね~IPv6も混ざってますし。

そこで、何か「サービス」を利用することになると思いますが、オンラインサービスで有名なのが「IPひろば」ですかね。

IPひろば:メイン

しかしながら当然、開発の現場で利用するにはAPIが必要なわけで・・・

GeoLite2

そこで、有料なものを中心にいろいろな会社・団体・個人がIP Geoサービスを展開してますが、日本ではあまり見聞きしないですね・・・

日本語なのは一部ページだけですが、王手にこんな会社があります。

2002 年に設立された MaxMind 社は、IP 情報収集とオンライン詐欺検出ツールの業界リーディングプロバイダのひとつです。

MaxMind は、GeoIP ブランドで IP 情報を提供しています。5,000 社を超える企業が GeoIP データを利用して、ウェブサイトへの訪問者の特定、関連性のあるコンテンツや広告の表示、分析の実行、デジタル著作権の行使、およびネットトラフィックの効率的な経路調整などを行っています。事業者の方々は、GeoIP データの使用により、顧客の接続速度、ISPやその他情報などへの、更なる見識を得ることが出来ます。

なんと、MaxMidさん、主力商品のGeoIP2サービスで使用されているデータベースと同等の「GeoLite2」というデータベースを 「無料」 で公開してくれています!
大事なことなのでもう一度いいます。 「無料」 で利用可能です!

GeoLite2 « MaxMind Developer Site

バイナリとCSVがあります。
CSVの方がファイルサイズが大きいですけど、汎用性がありそうですね。

ライセンス

先程「無料」で利用可能と言いましたが、ちゃんとソフトウェアライセンスが定義されています。

GeoLite2 データベースは、クリエイティブ・コモンズ 表示-継承 3.0 非移植ライセンスの下に配布されています。表示要件は、このデータベースの機能もしくは使用に言及するすべての広告および資料に、次の文を含めることで満たされます:

この製品には MaxMind が作成した GeoLite2 データが含まれており、http://www.maxmind.com から入手いただけます。

クレジットすれば、商用利用でもOKという事ですね。

API

「バイナリのデータベースとか、どうやって利用するんだよ?」という事になりますが、MaxMind社ではちゃんとAPIを用意してくれています!

GeoIP2 Downloadable Databases « MaxMind Developer Site

公式なものだけでも、

なるほど~RESTとかのWEB APIじゃない分、クライアントアプリとかにも利用できるし、組み込みでも利用可能なわけか・・・

サードパーティ製になりますが、NodejsRuby用のAPIもありますね。

因みにこれらは、元々有料版用のAPIですが、無料版のデータベースでもそのまま利用が可能でした。

利用方法(LAMP

先程のバイナリ版データベース(GeoLite2 City)をダウンロードしましたか?
してなければ、しなくていいです(笑)。
勘の良い人なら気づくと思いますが、リモートサーバ上で落としたほうが良いので。

今回もLAMP前提で書き進めます。

APIダウンロード

素直にComposerを使うべし。

$ sudo composer require geoip2/geoip2:~2.0

データベースダウンロード

$ cd /usr/local/share
$ sudo mkdir GeoIP
$ cd  GeoIP
$ sudo wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
$ sudo gunzip GeoLite2-City.mmdb.gz

ダウンロードして解凍です。
/usr/local/shareに置きましたが、場所はどこでもいいような気がします・・・
※ 因みにこのデータベースは月一度の頻度で更新されているそうです。

サンプルコード

GitHubに掲載してあったものを元に、サンプルコードを書きました。

maxmind/GeoIP2-php: PHP API for GeoIP2 webservice client and database reader

<?php
require_once '../vendor/autoload.php';
use GeoIp2\Database\Reader;
$reader = new Reader('/usr/local/share/GeoIP/GeoLite2-City.mmdb');
$record = $reader->city('1.0.16.1');
$result = [
'Country ISO Code' => $record->country->isoCode, // ISOコード(ISO 3166-1のalpha2が返ってくる)
'Country Name' => $record->country->name, // 国名(英語)
'Country Name Localization' => $record->country->names['ja'], // 国名(ローカライズ)
'Most Specific Subdivision Name' => $record->mostSpecificSubdivision->name, // アメリカなら「州」、日本なら「県」
'Most Specific Subdivision ISO Code' => $record->mostSpecificSubdivision->isoCode, // 上記のISOコード (日本の場合、ISO 3166-2:JPではなく、JIS X 0401 が返ってきた)
'City' => $record->city->name, // 都市名
'Zip Code' => $record->postal->code, // 郵便番号
'LatLng' => [
'lat' => $record->location->latitude, // 緯度
'lng' => $record->location->longitude // 経度
]
];
var_dump($result);

上記の実行結果:

array(8) {
["Country ISO Code"]=>
string(2) "JP"
["Country Name"]=>
string(5) "Japan"
["Country Name Localization"]=>
string(6) "日本"
["Most Specific Subdivision Name"]=>
string(5) "Tokyo"
["Most Specific Subdivision ISO Code"]=>
string(2) "13"
["City"]=>
string(5) "Tokyo"
["Zip Code"]=>
string(8) "190-0031"
["LatLng"]=>
array(2) {
["lat"]=>
float(35.685)
["lng"]=>
float(139.7514)
}
}

スゲー

緯度経度も返してくれちゃうとか・・・

因みに、無料版と有料版の違いは 「精度」 だそうです。 いろいろなIPで試してみましたが、郵便番号は確かに微妙~な感じでした。

所感

一番多い使われ方として、(多分)「某国」からのアクセスを禁止する為~とかでしょうが、位置情報を利用するWEBアプリで、スマホじゃなくて、PCからのアクセスされた時のデフォルト位置情報情報として利用するとか、考えられますね。

今回は、開発者として知っておくと便利なサービスの紹介でした!

RecentPost