• WEB

PHPでコマンドラインで使うGeoIPフィルタを作ってみよう

  • インゴットくん
    インゴットくん システムちーむ
  • このエントリーをはてなブックマークに追加
PHPでコマンドラインで使うGeoIPフィルタを作ってみよう

みなさんは、黒い画面は好きですか?

一日のほとんどの時間をLinuxコンソールで過ごしているので、私は黒い画面に対してはさほど抵抗はないのですが、最初からXampp環境であったりレンタルサーバであったり、コンソール画面に触れる必要が無い環境で過ごしてきた方にとっては、けっこうつらいようです。

しかし、今や世の中、仮想マシン立て放題。ぼやぼやしていると、後ろからバッサリOOM Killされますので、コンソールに入ってごにょごにょ仕事するのもやっていかなくてはならない場面だと思うわけであります。

さて、コンソールに入ってやることの代表例といえばログ調査だったりしますが、ログ調査といえば、テキストフィルタですよね。

テキストフィルタっていうのは、ある文字列を入れると特定の文字列に反応して別の文字列に置換したり、いらない行を取っ払ったりするプログラムのことです。

業務も高度に進化してくると、その会社独自のテキストフィルタプログラムを開発することもあります。かつては、テキストフィルタといえば、Unix使いのたしなみとも言わんばかりに当り前に使っていて、GNU Coreutilsに含まれているような基本コマンド(cat/head/tail/sort/uniq)はもちろんのこと、grep/sed/awk、さらにPerlなどを使って縦横無尽にログの海原を航海していたものでした。

しかし、ここはPHPの会社なので、PHPでテキストフィルタを書かないとプログラム資産として後世に残らないのです。

こうして、PHPでテキストフィルタを書く動機が発生したのでした……

今回は、CentOS 6.6でPHPが動いている環境を想定し、PECLからgeoipを入れたあとサポートされるgeoip_country_code_by_nameを使い、ログの中でIPアドレス風の文字列を、そのIPアドレスが所属する国名に置換するテキストフィルタプログラムです。

Filename ip2geo


#!/usr/bin/php
<?php

$fp = fopen("php://stdin", "r") or die("標準入力から読み込めません");

while( !feof($fp) ) {
  $line = fgets($fp);
  $line = preg_replace_callback(
    "/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/",
    function($matches) {
      return geoip_country_code_by_name($matches[0]);
    },
    $line
  );
  echo $line;
}
fclose($fp);

ファイルの置き場所は、一般ユーザにもrootにも共通で使わせるなら、/usr/local/binへ

一般ユーザが自分だけ使いたい場合は、~/bin
(例えばgonextユーザであれば ~は/home/gonextになるので、/home/gonext/bin になる)

rootユーザだけ使いたいなら /root/bin に置きます。

また、実行権限をつけておかないと動きません!(PHPユーザは実行権限を忘れがちなので注意)。

このフィルタプログラムで、


# tail /var/log/httpd/access_log | awk '{print $1,$2.$3,$4,$5}' | ip2geo
JP -- [25/Feb/2015:20:02:34 +0900]
JP -- [25/Feb/2015:20:02:34 +0900]
JP -- [25/Feb/2015:20:02:35 +0900]
JP -- [25/Feb/2015:20:02:35 +0900]
JP -- [25/Feb/2015:20:02:35 +0900]
JP -- [25/Feb/2015:20:02:35 +0900]
JP -- [25/Feb/2015:20:02:35 +0900]
JP -- [25/Feb/2015:20:02:35 +0900]
JP -- [25/Feb/2015:20:02:35 +0900]
JP -- [25/Feb/2015:20:02:35 +0900]
#

のように、IPアドレスの部分を国コードに置換することができます。


# \grep -e wp-login /var/log/httpd/access_log | awk '{print $1}' | ip2geo | sort | uniq -c | sort -r -n -k1
    252 US
    241 RO
    135 JP
      2 UA
      2 GB
      2 FR
      2 CN
      2 CA
      1 RU
      1 LV
      1 DE
      1 BE
#

とすると、WordPressのログインページへのアクセス状況がわかります。USの大半はGoogleBotやbingBotだったりしますが、ROで示されるルーマニアから241回のアクセスっていったいなんでしょうね、こわい!(対策はしています)

こんな感じで、PHPでも、役に立つテキストフィルタをたくさん作って、会社の技術資産になっていけばいいなあと思っています。

なお、PHP版のもとになったPerl版もソースコードを出しておきます。


#!/usr/bin/perl

# CentOS 6: yum --enablerepo=epel install geoip
# geoipのデータベース更新は自分で設置すること!

use strict;
use warnings;

my $dic = {
};

local $| = 1; # 出力強制Flush http://perldoc.jp/docs/perl/5.20.1/perlvar.pod

while(<>) {
  s/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/getcountrybyaddress($1)/eg;
  print;
}

exit;

sub getcountrybyaddress {
  my $ip = shift;
  if ( exists $dic->{$ip} ) {
    return $dic->{$ip};
  }
  my $res = _getcountrybyaddress( $ip );
  $dic->{$ip} = $res;
  return $res;
}

sub _getcountrybyaddress {
  my $ip = shift;
  my $country = `geoiplookup $ip`;
  if ( $country =~ m/GeoIP.+: (..),.+$/sgo ) {
    $country = $1;
  } else {
    $country = "??";
  }
  my $res = "$country"; //装飾付けるならここ
  return $res;
}

__END__

このエントリーをはてなブックマークに追加

インゴットくんが最近書いた記事

WRITERS POSTS もっと見る

他にもこんな記事が読まれています!

  • WEB
  • マーケティング
  • サーバー・ネットワーク
  • ライフスタイル
  • お知らせ