DB連携Accessアナライザー

 「PHPの小部屋」で公開・解説しているAccessアナライザーをデータベース連携版に移行・改良しました。データ解析処理は全てSQL文で行っていますので、ファイルベース版に比べ処理が簡単で見易くなっています。

テーブル構造

 ファイルベース版と同じ項目をテーブル構造に組み込みます。

[テーブル作成文]

create table db_ana (code int4, date_now varchar(20), host varchar(50), agent varchar(100), href varchar(100), hour int2, primary key (code));

インデックス番号

列名

データ型

0 code int4
1 date_now varchar(20)
2 host varchar(50)
3 agent varchar(100)
4 href varchar(100)
5 hour int2

プログラム内容

<?php
//=================初期設定==================
$db_user = "komonet"; //データベースのユーザー名(自分の環境に合わせて変更の事)
$db_name = "komodb"; //データベース名(自分の環境に合わせて変更の事)
$title = 'KOMOアナライザー';
$date_now = date("Y/m/d(D)"); //日付の取得
$hour = date("G"); //時刻の取得。頭に0を付けない。0〜23。
$gazou = './komo_ana.jpg';
$graph_img = './cnt.gif';
$graph_img2 = './cnt2.gif';
$data_max = 1000; //最大記録数
$hostview = 30;
$agentview = 50;
$hrefview = 50;
$graphview = 100;
$date_max = 30;
$time_max = 24;
//===========================================
PHPの開始。

初期設定部分です。
$php_v = PHP_VERSION; //PHPバージョンの取得
if($php_v > "4.1.0"){ //スーパーグローバル変数対応なら
 $PHP_SELF = $_SERVER["PHP_SELF"];
 //フォームデータの取得
 $action = $_GET['action'];
 $timeflag = $_GET['timeflag'];
 $Cookie_ana2 = $_COOKIE['Cookie_ana2'];
}
スーパーグローバル変数対策。PHPのバージョンから判断。標準設定を仮定しています。
//データベースに接続
$conn = pg_connect("user=" . $db_user . " dbname=" . $db_name) or die("接続エラー");
データベースに接続します。
//データ分析
if($action == 'view'){
 $sql = "select * from db_ana";
 $result = pg_query($conn, $sql) or die("データ抽出エラー");
 $row_all = pg_numrows($result); //データの総数
 pg_freeresult($result);
 $sql = "select * from db_ana where date_now = '" . $date_now . "'";
 $result = pg_query($conn, $sql) or die("データ抽出エラー");
 $row_today = pg_numrows($result); //データの総数
 pg_freeresult($result);
変数$actionの値がviewであれば、データ解析を行います。まずSQL文でデータの総数と当日データの合計数とを求めます。
 //HTML出力
 echo "<html><head><META HTTP-EQUIV=Content-Type CONTENT=text/html;CHARSET=Shift-JIS><title>$title</title></head>\n";
 echo "<body bgcolor=#ffffff text=#000000 link='red' vlink='red'>\n";
 echo "<center>\n";
 echo "<img src=./banner.gif><br>\n";
 echo "<font color='green'><b><最新 $data_max アクセスの解析結果></b></font>\n";
 echo "<p>現在のサンプル数 $row_all アクセスです。<BR><FONT SIZE=2><<a href=smp_page.htm>解析ページに戻る</a>></FONT></p>\n";
ここからHTML出力を開始します。
 echo "<table border=1 cellspacing=0 width=90%>\n";
 //本日の時間別統計
 if($timeflag > 0){
  echo "<caption>本日 $date_now の時間別統計<br>\n";
  echo "<font size=2>[<a href=$PHP_SELF?action=view&timeflag=0>データ全体を見る</a>]</font></caption>\n";
 }else{
  echo "<caption>データ全体の時間別統計<br>\n";
  echo "<font size=2>[<a href=$PHP_SELF?action=view&timeflag=1>本日のデータを見る</a>]</font></caption>\n";
 }
時間別統計部分です。

テーブルのcaptionに、データ全体と本日のデータとの表示を切り替えるリンクを貼っています。
 echo "<tr><td bgcolor=#ffccff><font size=2>グラフ</font></td>\n";

 if($timeflag){
  $sql = "select hour, COUNT(hour) from db_ana where date_now = '" . $date_now . "' group by hour order by COUNT(hour) DESC";
 }else{
  $sql = "select hour, COUNT(hour) from db_ana group by hour order by COUNT(hour) DESC";
 }
 $result = pg_query($conn, $sql) or die("データ抽出エラー");
 $max_row = pg_fetch_row($result, 0);
 $max_count = $max_row[1]; //最大カウント数
 $row = pg_numrows($result);
 for($i=0; $i<$row; $i++){
  $arr = pg_fetch_row($result, $i);
  $hr = $arr[0];
  $hour_count[$hr] = $arr[1];
 }
 for($i=0; $i<24; $i++){
  if($hour_count[$i]){
   if($timeflag){
    $chrlen = $hour_count[$i] / $max_count * $graphview;
   }else{
    $chrlen = $hour_count[$i] / $max_count * $graphview;
   }
  }else{
   $chrlen = 0;
  }
  echo "<td align=center valign=bottom><img src=$graph_img2 width=10 height=$chrlen></td>\n";
 }
 echo "</tr>\n";
グラフ表示部分です。

変数
$timeflagの値によってデータ集計のSQL文を選択します。本日のデータを集計する場合は、where文で集計するデータを本日分に絞ります。

最大カウント数
$max_countを求めているのは、最大値のデータのグラフの長さを一定に保つ為です。

時間毎のアクセスデータは、一旦配列変数
$hour_countに放り込んで、一覧表の時刻に合致した場合にカウントデータを抽出してグラフ表示するようにしています。
 echo "<tr><td bgcolor=#ffccff><font size=2>カウント</font></td>\n";
 for($i=0; $i<24; $i++){
  if($hour_count[$i]){
   $c = $hour_count[$i];
  }else{
   $c = 0;
  }
  echo "<td>$c</td>\n";
 }
 echo "</tr>\n";
カウント数の表示部分です。

これも前項と同じく、一覧表の時刻に合致した場合に配列変数
$hour_countからカウントデータを抽出して表示しています。
 echo "<tr><td bgcolor=#ffccff><font size=2>ポイント(%)</font></td>\n";
 for($i=0; $i<24; $i++){
  if($hour_count[$i]){
   $per = $hour_count[$i] / $row_all * 100;
  }else{
   $per = 0;
  }
  echo "<td>\n";
  printf("%d", $per);
  echo "%</td>\n";
 }
 echo "</tr></table><br>\n";
 pg_freeresult($result);
ボイントの表示部分です。

ここも処理は前項と同じです。パーセンテージ表示に直しています。
printf()関数は指定した書式に従ってデータを表示させます。

最後に
pg_freeresult()関数で、次の処理の為にメモリを一旦開放します。
 echo "<table border=0 cellpadding=0 cellspacing=0 width=90%>\n";
 echo "<tr><td valign=top width=49%>\n";
表組みの外枠部分です。
 //日別統計
 echo "<table border=1 cellspacing=0 width=100%>\n";
 echo "<caption>日別統計(最大 $date_max 日)</caption>\n";
 echo "<tr><td align=center bgcolor=#ffccff><font size=2>日付</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>カウント</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>ポイント</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>グラフ</font></td></tr>\n";

 $sql = "select date_now, COUNT(date_now) from db_ana group by date_now order by COUNT(date_now) DESC";
 $result = pg_query($conn, $sql) or die("データ抽出エラー");
 $max_row = pg_fetch_row($result, 0);
 $max_count = $max_row[1]; //最大カウント数
 $row = pg_numrows($result);

 if($date_max > $row){ $date_max = $row; }
 for($i=0; $i<$date_max; $i++){
  $arr = pg_fetch_row($result, $i);
  if($row_all){
   $per = $arr[1] / $row_all * 100;
   $chrlen = $arr[1] / $max_count * $graphview;
  }else{
   $per = 0; $chrlen = 0;
  }
  echo "<tr><td>$arr[0]</td>\n";
  echo "<td align=right>$arr[1]</td>\n";
  echo "<td align=right>\n";
  printf("%d", $per);
  echo " %</td>\n";
  echo "<td><img src=$graph_img width=$chrlen height=10></td></tr>\n";
 }
 echo "</table>\n";
 pg_freeresult($result);
日別統計部分です。

ここからはカウント数の多い順にデータを表示します。処理内容は時間別統計部分とほぼ同じです。
 echo "</td><td width=2%></td><td valign=top width=49%>\n"; 表組みの外枠部分です。
 //ホスト別統計
 echo "<table border=1 cellspacing=0 width=100%>\n";
 echo "<caption>ホスト別統計(最大 $hostview 件)</caption>\n";
 echo "<tr><td align=center bgcolor=#ffccff><font size=2>ホスト名</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>カウント</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>ポイント</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>グラフ</font></td></tr>\n";

 $sql = "select host, COUNT(host) from db_ana group by host order by COUNT(host) DESC";
 $result = pg_query($conn, $sql) or die("データ抽出エラー");
 $max_row = pg_fetch_row($result, 0);
 $max_count = $max_row[1]; //最大カウント数
 $row = pg_numrows($result);

 if($hostview > $row){ $hostview = $row; }
 for($i=0; $i<$hostview; $i++){
  $arr = pg_fetch_row($result, $i);
  if($arr[1]){
   if($row_all){
    $per = $arr[1] / $row_all * 100;
    $chrlen = $arr[1] / $max_count * $graphview;
   }else{
    $per = 0; $chrlen = 0;
   }
  }
  echo "<tr><td>$arr[0]</td>\n";
  echo "<td align=right>$arr[1]</td>\n";
  echo "<td align=right>\n";
  printf("%d", $per);
  echo " %</td>\n";
  echo "<td><img src=$graph_img width=$chrlen height=10></td></tr>\n";
 }
 echo "</table>\n";
 echo "</td></tr></table><br>\n";
 pg_freeresult($result);
ホスト別統計部分です。

ここも処理内容は前項部分とほぼ同じです。ファイルベース版スクリプトに比べて、処理内容が大変見易く簡単になっています。
 //ブラウザ別統計
 echo "<table border=1 cellspacing=0 width=90%>\n";
 echo "<caption>ブラウザ別統計(最大 $agentview 件)</caption>\n";
 echo "<tr><td align=center bgcolor=#ffccff><font size=2>ブラウザ名</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>カウント</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>ポイント</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>グラフ</font></td></tr>\n";

 $sql = "select agent, COUNT(agent) from db_ana group by agent order by COUNT(agent) DESC";
 $result = pg_query($conn, $sql) or die("データ抽出エラー");
 $max_row = pg_fetch_row($result, 0);
 $max_count = $max_row[1]; //最大カウント数
 $row = pg_numrows($result);

 if($agentview > $row){ $agentview = $row; }
 for($i=0; $i<$agentview; $i++){
  $arr = pg_fetch_row($result, $i);
  if($arr[1]){
   if($row_all){
    $per = $arr[1] / $row_all * 100;
    $chrlen = $arr[1] / $max_count * $graphview;
   }else{
    $per = 0; $chrlen = 0;
   }
  }
  echo "<tr><td>$arr[0]</td>\n";
  echo "<td align=right>$arr[1]</td>\n";
  echo "<td align=right>\n";
  printf("%d", $per);
  echo " %</td>\n";
  echo "<td><img src=$graph_img width=$chrlen height=10></td></tr>\n";
 }
 echo "</table><br>\n";
 pg_freeresult($result);
ブラウザ別統計部分です。

ここも又、処理内容は前項部分とほぼ同じです。
 //リンク元別統計
 echo "<table border=1 cellspacing=0 width=90%>\n";
 echo "<caption>リンク元別統計(最大 $hrefview 件)</caption>\n";
 echo "<tr><td align=center bgcolor=#ffccff><font size=2>リンク元</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>カウント</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>ポイント</font></td>\n";
 echo "<td align=center bgcolor=#ffccff><font size=2>グラフ</font></td></tr>\n";

 $sql = "select href, COUNT(href) from db_ana group by href order by COUNT(href) DESC";
 $result = pg_query($conn, $sql) or die("データ抽出エラー");
 $max_row = pg_fetch_row($result, 0);
 $max_count = $max_row[1]; //最大カウント数
 $row = pg_numrows($result);
 if($hrefview > $row){ $hrefview = $row; }
 for($i=0; $i<$hrefview; $i++){
  $arr = pg_fetch_row($result, $i);
  if($arr[1]){
   if($row_all){
    $per = $arr[1] / $row_all * 100;
    $chrlen = $arr[1] / $max_count * $graphview;
   }else{
    $per = 0; $chrlen = 0;
   }
  }
  echo "<tr><td>\n";
  if($arr[0]){
   echo "<a href=$arr[0] target=_blank>" . $arr[0] . "</a>";
  }else{
   echo "none";
  }
  echo "</td>\n";
  echo "<td align=right>$arr[1]</td>\n";
  echo "<td align=right>\n";
  printf("%d", $per);
  echo " %</td>\n";
  echo "<td><img src=$graph_img width=$chrlen height=10></td></tr>\n";
 }
 echo "</table></center><br>\n";
 echo "<div align=right><font size=-1>Powered by <a href=\"http://www.komonet.ne.jp/\">KOMONET</a></font></div>\n";
 echo "</body></html>\n";
 pg_freeresult($result);
リンク元別統計部分です。

ここも又、処理内容は前項部分とほぼ同じです。ただ、リンク元情報の部分は直接ジャンプできるようリンクを貼る処理を施しています。
}else{
 //クッキー書き込み
 $cookie = $date_now;
 setcookie("Cookie_ana2","$cookie");
アクセス解析をしたいページを開いた時に呼び出される処理部分です。まず本日の日付データをクッキーに書き込みます。
 //データ書き込み
 if($Cookie_ana2 != $date_now){
二重登録を避ける為にクッキーに保存された日付データと照らし合わせます。
  //ホスト名を取得
  $host = getenv("REMOTE_HOST");
  $addr = getenv("REMOTE_ADDR");
  if($host == "" || $host ==$addr){
   $host = gethostbyaddr($addr);
   if($host != $addr){
    if(eregi(".+\.(.+)\.(.+)\.(.+)$", $host, $regs)){
     $host = "*." . $regs[1] . "." . $regs[2] . "." . $regs[3];
    }elseif(eregi(".+\.(.+)\.(.+)$", $host, $regs)){
     $host = "*." . $regs[1] . "." . $regs[2];
    }elseif(eregi(".+\.(.+)$", $host, $regs)){
     $host = "*." . $regs[1];
    }else{
     $host = "on the internet";
    }
   }else{
    $host = $addr;
   }
  }
  //訪問者のブラウザを取得
  $agent = getenv("HTTP_USER_AGENT");
  //リンク元を取得
  $href = getenv("QUERY_STRING");
記録するアクセスデータをそれぞれ取得します。

取得したホスト情報をドメイン毎に分類する為、
eregi()関数を使ってパターン別に分類します。

こういったデータは環境変数から読み取るのが常です。
  //現在のマイクロ秒数を取得
  $code = time();
  $sql = "insert into db_ana values ($code,'$date_now','$host','$agent','$href',$hour)";
  if(!pg_query($conn, $sql)){
   $code++;
   $sql = "insert into db_ana values ($code,'$date_now','$host','$agent','$href',$hour)";
   pg_query($conn, $sql) or die("データ登録エラー");
  }
テーブルデータには必ずキーとなるデータ項目が必要です。ここでは項目codeがそれです。

同時書き込み対策として一回だけ回避措置を取っています。
  //データ最大記録数を調整
  $sql = "select * from db_ana order by code DESC";
  $result = pg_query($conn, $sql) or die("データ抽出エラー");
  $row = pg_numrows($result); //データ数を取得
  if($row > $data_max){
   $arr = pg_fetch_row($result, $data_max);
   $max_arr = $arr[0];
   $sql2 = "delete from db_ana where code <= $max_arr";
   pg_query($conn, $sql2) or die("データ削除エラー");
  }
 }
データ保存数の調整部分です。掲示板スクリプトなどでもお馴染みの処理です。
 header("Content-type: image/jpg");
 readfile($gazou);
}
?>
アクセス解析用ページにリンクバナーを呼び出し表示する部分です。画像ファイルを読み込んでいます。

このスクリプトはKOMONETサイトで配布しています。サンプルもあります。

*上の内容をこのまま複写しても動きません。何故なら、表示を見やすくする為コード中に全角スペースが入っているからです。実際にお使いになる時は、この点を修正してからサーバにアップして下さい。

DB連携ダイアリー 前へ

HOME

次へ