Contents
前説
前回のCodeIgniter エラーログの出力とCodeIgniter SQLログの出力は、評判が良かったので、続いて、CodeIgniter アクセス(操作)ログの出力についても紹介したいと思います。
上記のCodeIgniter エラーログの出力とCodeIgniter SQLログの出力は、CodeIgniterフレームワークを改造して、ログを出力するようにしましたが、今回は、CodeIgniterのフック(hook)機能を使って、アクセス(操作)ログの出力を実現します。
CodeIgniterのフック(hook)機能と言えば、Java世界において、StrutsのfilterやSpringのadviceと同じように、一種のAOPに過ぎないです。設定作業や実装はJavaよりかなり簡単で、開発効率が非常に高いです。
前提
・CodeIgniterバージョン:3.1.3
※バージョン:3.1.6でも使えますので、3.X系はいけそうではないかと思います。
要件
・誰がいつ、どの画面、何を入力、どの操作をしたことを、アクセス(操作)ログに記録し、日単位で管理すること。→ログローテーションのこと
ここの
誰⇒ユーザーID
いつ⇒操作時のシステムタイム
どの画面⇒URL
何を入力⇒URLのパラメータ情報、POST情報
どの操作⇒URLとPOST情報
を出力すれば、運用時に、障害調査や操作履歴調査する際に、非常に助かります。大きなプロジェクトだけではなく、小さなECサイトでも、是非アクセス(操作)ログの出力を意識して、実装してみてください。
考え方
ユーザーがURLを叩いたり、画面のボタンを押下したりした時に、サーバー側のコントローラーを呼び出すタイミングで、URLとPOSTなどの情報を取得して、アクセス(操作)ログに出力すれば良いかと思います。
そのため、前説に紹介したCodeIgniterのフック(hook)機能を使って、コントローラーを呼び出すタイミングで、フックを掛けて、アクセス(操作)ログに出力します。
簡単にまとめて、説明しますと、ポイントが2つ、
1.アクセス(操作)ログを出力するクラスを実装する。
2.No.1のクラス情報をフック情報としてを設定する。
以上です。
が、順序が逆ですが、アクセス(操作)ログの出力方法を紹介する前に、まず、CodeIgniterのフック設定作業を説明します。
1.CodeIgniterのフック機能を有効にする
application/config直下のconfig.phpファイルを開いて、「enable_hooks」をTRUEに設定しますと、CodeIgniterのフック機能が使えるようになります。
1 2 3 4 5 |
$config['enable_hooks'] = TRUE; // config.phpファイルの103行あたり |
2.事前に用意したフッククラスを設定する。
上記と同じく、application/config直下のhooks.phpファイルを開いて、事前に用意したフッククラス情報を設定します。(フッククラスの中身は次に説明します。)
1 2 3 4 5 6 7 8 9 10 11 |
// セッション情報を使うため、フックのタイミングはコントローラーがインスタンスされた直後に(post_controller_constructor)実行するフッククラスを設定する $hook['post_controller_constructor'] = array( 'class' => 'FrontFilter', // フッククラス名、名称は任意です。 'function' => 'access_log', // 呼ばれるメソッド名、フッククラス名と同じく名称は任意です。 'filename' => 'FrontFilter.php', // フッククラスファイル名 'filepath' => 'hooks' // フッククラスファイルの格納場所です。余程なカスタマイズ以外に、基本的application/hooksフォルダの下です。 ); |
ここまでは、フック設定作業が完了しました。頭が痛いほどのJava設定作業より、簡単、簡単~~♪♪
3.アクセス(操作)ログの出力を実装
設定作業が完了したら、上記のフッククラスの実装を説明します。
フッククラスを作成
Javaと違って、フッククラスの継承は一切ない、クラス名を定義すれば、終わりです。簡単、簡単~~♪♪
application/hooksフォルダの下に、「FrontFilter.php」を新規に作成し、中身は下記の通りです。
1 2 3 4 5 |
class FrontFilter{} |
メソッドを作成
続いて、上記の定義に、「access_log」というメソッドを実装します。このメソッドで、URLとPOSTなどの情報を取得して、アクセス(操作)ログに出力します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public function access_log() { $post_info = ''; foreach( $_POST as $idx=>$val){ // 配列値を考慮して、print_rで各POST値をカンマで連結する $post_info .= $idx . ':' . print_r($val,TRUE) . ','; //改行を無くす $post_info = str_replace(array("\r\n", "\r", "\n"), '', $post_info); } // ログファイルに吐き出す $this->log($post_info); } |
上記のlogメソッドの実装方法は簡単です。詳しくは、PHP ログ出力機能 実装方法 で紹介しましたので、ご参考まで。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// 実際に共通関数として、外に出したほうが良いと思います private function log($msg) { date_default_timezone_set('Asia/Tokyo'); $userid = ''; if ( isset($_SESSION['userid']) ){ $userid = $_SESSION['userid']; } $datatime = explode('.' , microtime(true)); if( !isset($datatime[1]) ){ $datatime[1] = "0000"; } $loginfo = 'INFO' . ' ' . date('Y/m/d H:i:s,') . $datatime[1] // いつ⇒操作時のシステムタイム、ミリ秒まで . ' ' . $_SERVER['REMOTE_ADDR'] // リモートIP(ユーザー側のIP)、ロードバランサーがあった時に、別の方法で取得する . ' ' . gethostbyaddr($_SERVER['REMOTE_ADDR']) // インターネットホストのホスト名となり、実際に、ユーザー端末のホスト名の取得はほぼ不可能、 . ' ' . session_id() // セッションID . ' ' . $userid // 誰⇒ユーザーID . ' ' . $_SERVER['REQUEST_URI'] // どの画面、URLのパラメータ情報⇒URL . ' ' . $_SERVER['HTTP_USER_AGENT'] // WEBアプリケーションなので、ユーザーがどのブラウザを使って、操作するかという情報も出力 . ' ' . $msg; // 何を入力⇒POST情報(画面入力値) $loginfo = mb_convert_encoding($loginfo,'UTF-8','UTF-8'); $config =& get_config(); $filename = $config['log_path'] . DIRECTORY_SEPARATOR . 'access-' . date('Y-m-d') . '.log'; error_log( $loginfo . "\n", 3, $filename); } |
サンプル
実装はここまで、実際にアクセス(操作)ログの出力サンプルをあげます。
1 2 3 4 5 |
INFO 2019/08/09 01:53:11,31361 111.229.177.156 KD111239177166.au-net.ne.jp 03lld0saeln87fsf061j3gkhj012402q /sample/enroll/entry Mozilla/5.0 (Linux; Android 6.0.1; SO-02J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36 name1:テスト,name2:太郎,furigana1:テスト,furigana2:タロウ,birthday_y:1977,birthday_m:3,birthday_d:15,mailadress:info@sample.ne.jp, |
まとめ
いかがでしょうか。CodeIgniter アクセス(操作)ログの出力は簡単ですよね。ほかの方法もあるかと思います。皆さんもいろいろな方法で試してみてください。
それでは、以上です。
追記
CodeIgniterフレームワークのフック機能を利用して、アクセス(操作)ログの出力方法を紹介しましたが、この方法は欠点があることを後日の本番エラーの調査時に気づきました。
それは、ログアウトの状態で、URLを直接叩いたり、お気に入りから遷移した際に、そのアクションがアクセス(操作)ログに記録されなかったことです。
その原因はアクセス(操作)ログの出力タイミングです。ログアウトの状態で、URLを直接叩いた場合、コントローラがインスタンス化する最中に存在するセッション生死チェック機能に引かれて、ログイン画面へ強制的に遷移させるため、今回アクセス(操作)ログの出力するのに、使っていたCodeIgniterのフックポイント:post_controller_constructorがコントローラがインスタンス化された直後に、呼び出されるため、当然ながら、アクセス(操作)ログを出力するわけがないですね。
対策として、コントローラが呼び出される直前に呼び出される、フックポイント:pre_controllerを使えば、良いのです。
しっかり検証せずに、軽くアクセス(操作)ログの出力方法を紹介した僕が悪かった、すみませんでした。