BBClone + PukiWiki によるアクセス解析の文字化け対策

SEO対策としても使うことのできるフリー(GPL) の PHP 用のログ解析ソフトである BBClone と PHP ベースでフリーの Wiki クローン PukiWiki を連携動作させたのですが、 日本語の表示対応は一応されているのものの、日本語対応の不備が見受けられましたので適当ですが対応しました。 備忘録として、その作業ログを書いておきます。

これを書いたときに作業したバージョンは 0.4.8a です。0.4.8b 移行時に同様に作業しましたが、特に問題ありませんでした。(現在は 0.4.9 が最新版です)

BBClone 本体は http://bbclone.de/ で入手して解説サイト (例えば BBCloneでphpアクセス解析外部リンク] ) などを見ながらインストールしてください。

BBClone (アクセス解析ソフト) 本体の変更

対象となるバージョン

BBClone 0.4.8.a または 0.4.8.b / PukiWiki 1.4.5_1 , 1.4.6

グローバル統計・詳細統計における ページ名の文字化け

デフォルト設定のままだと、ページ名(EUC-JP) に「伸」「辞」など 0xAD を含むページになると文字化けが発生する。
内部のセパレータ文字に CHR(173) 0xAD が使用されていることに起因する。
セパレータを PukiWiki に習い ">>>>>>>>>>" にすると この部分の文字化け問題は解決する。(たぶん)

./constant.php
60 行目付近
// Global separator
//$BBC_SEP = chr(173);
$BBC_SEP = ">>>>>>>>>>";

検索キーワードの損失と全角スペースの区切り文字登録

検索文字に 'シングルバイト文字'+'ダブルバイト文字' 形式で指定されると ダブルバイト文字が削除されたりします。
また、全角スペースを区切り文字として扱わないで、そのままリファラに設定された場合に 1単語として扱われます。
さらにキャラクタセットを設定した場合 ($BBC_CUSTOM_CHARSET = "EUC-JP";など) 、大文字小文字を区別してしまいます。

変更内容

  1. 日本語に対応した正規表現置換関数がありますので、それを実行させるように変更
  2. 全角スペースを "+" 文字*1に変換するように追加
  3. キャラクタセットの指定によっては、大文字小文字が区別される可能性があったので、それを変更
./lib/referer.php 32 行目付近 (変更点 1)
function bbc_get_sep($query, $array) {
 // puts the query into an array
 foreach ($array as $match) {
   $has_sep = (strpos($query, $match) !== false) ? true : false;
   $pool = $has_sep ? explode($match, $query) : array($query);
 
   for ($i = 0, $max = count($pool); $i < $max; $i++) {
     // Characters which usually aren't needed at the beginning or end of a keyword
     // ↓ preg_replace の使用部分を下の内容に置き換える。 (1)
     // $pool[$i] = preg_replace("%^\W*(\b.{2,}\b)\W*$%", "\\1", $pool[$i]);
     $pool[$i] = (defined("_BBC_MBSTRING")) ?
                 mb_ereg_replace("%^\W*(\b.{2,}\b)\W*$%", "\\1", $pool[$i]) :
                 preg_replace("%^\W*(\b.{2,}\b)\W*$%", "\\1", $pool[$i]);
     // ↑ ここまで
 
同 ./lib/referer.php 125行目付近 (変更点 2 および 3)
  // Conversion of keywords, if applicable
  $from = defined("_BBC_MBSTRING") ? bbc_get_encoding($raw_search) : false;
  $raw_search = (($from !== false) || defined("_BBC_RECODE"))
                ? bbc_convert_lang($raw_search, $from, $char) : $raw_search;
  // ↓↓ 全角スペースを区切り文字(+)へ変換する (2)
  $raw_search = defined("_BBC_MBSTRING") ?
                mb_convert_kana($raw_search,"aKV") : $raw_seach;
  $raw_search = defined("_BBC_MBSTRING") ?
                mb_ereg_replace(' ','+',$raw_search) : $raw_seach;
  // ↑↑
  $raw_search = bbc_get_sep($raw_search, $word_sep);
 
  for ($i = 0, $j = count($raw_search); $i < $j; $i++) {
    // strtolower messes up UTF-8 so we leave things case sensitive if it's
    // requested as charset
    // ↓↓ 日本語対応 小文字変換関数を使用する (3)
    // $tmp = !$char ? strtolower(bbc_clean($raw_search[$i])) :
                       bbc_clean($raw_search[$i]);
    $tmp = defined("_BBC_MBSTRING") ? mb_strtolower(bbc_clean($raw_search[$i])) :
                                      strtolower(bbc_clean($raw_search[$i]));
    // ↑↑

リファラーの文字化け (0.4.8b では不要)

ポータルサイトによりエンコード済のものを再エンコードすることによる文字化け
信頼できる検索サイトからのリファラの場合、Javacriptによる ジャンプを行わないように変更しました。
(まだ、Shift_JISで指定してくるケースでの文字化けが残っています。)

./show_detailed.php 54 行目付近
   case "referer":
     if ($connect[$field] == "ignored") return " ".$_['misc_ignored'];
     if (strpos($connect[$field], "://") === false) return " ";
 
     $url = substr(strstr($connect[$field], "://"), 3);
     $str = (($slash = strpos($url, "/")) !== false) ? substr($url, 0, $slash) : $url;
     $str = (strlen($str) > 50) ? "...".substr($str, -47) : $str;
 
// ↓ 追加($engines に 信頼できるサーチエンジンだけを登録しておく)
     $trusted_engines = array("www.google.co.jp", "www.google.com", "search.yahoo.co.jp",
                      "search.goo.ne.jp", "www.infoseek.co.jp");
     if (in_array($str, $trusted_engines)){
       return "<div align=\"left\"> \n"
           ."<a href=\"http://$url\")\" target=\"_blank\" rel=\"nofollow\" "
           ."title=\"$str\">&lt; $str &gt;</a>\n"
           ."</div>\n";
     }
// ↑ 追加終了
     return "<div align=\"left\">&nbsp;\n"
           ."<script type=\"text/javascript\">\n"
           ."<!--\n"
           ......................

PukiWiki 連携に関する変更

PukiWiki 使用時の USER_AGENT 情報の損失

PukiWiki は 初期化時に USER_AGENT 情報を取り出したのち 削除している。
このため、BBClone に ログ解析させるタイミングには、この情報を保持していないため記録できない。
といって、最初に BBClone にログ解析をさせると、PukiWiki名 を取り出すのがやっかいである。(XSSなど回避による変更範囲広くなり、メンテナンスも面倒になると判断しました)
(リスクの低そうな(※) PukiWiki の USER_AGENT情報をクリアしないように変更することで対応しました。
わざわざ消してあるということは残しておくとプラグインか、何かしら経由での問題がある可能性を想定していると思われます。

(※)このサイトは更新が不可能な状態での運用のため問題点はなさそうなのですが、一般利用者に書き換えを許可している PukiWikiサイトを運用している方は慎重に検討した上で対応してください。
この変更による具体的なリスクについては、詳しくないので残念ながらわかりません。 しかし、基本認証を利用している場合、プラグインからログイン名とパスワードを参照することは可能です。

PukiWiki バージョン 1.4.5_1
./lib/init.php
120 行目付近
/////////////////////////////////////////////////
// INI_FILE: $agents:  UserAgentの識別
 
$ua = 'HTTP_USER_AGENT';
$user_agent = $matches = array();
 
$user_agent['agent'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
// unset(${$ua}, $_SERVER[$ua], $HTTP_SERVER_VARS[$ua], $ua);	// safety
↑↑↑  この行をコメントアウト

PukiWiki 1.4.6 追記

Pukwiki 1.4.6 から 終了処理が組み込まれているため  require(LIB_DIR . 'pukiwiki.php'); 以降の処理が実行されなくなっている。その処理を削除する。

./lib/pukiwiki.php
最終行
// Output
catbody($title, $page, $body);
// exit;   ← ここをコメントアウト
?>

PukiWiki 使用時のグローバル統計の訪問ページの URL の変更

強引な変更です。PukiWiki専用になります。(confファイルを読み込んでいないため、直接埋め込みました)
さらにコマンド、プラグインの訪問履歴には、対応してませんので念のためクリックしない方がよいです。

./show_global.php 260 行目付近
function bbc_show_top_pages() {
  global $_, $access, $BBC_MAXPAGE;
 
  $page_tab = isset($access['page']) ? $access['page'] : array();
 
  for ($page_total = 0;
       list(, $page_elem) = each($page_tab); $page_total += $page_elem['count']);
 
  uasort($page_tab, "bbc_sort_page_count");
  reset($page_tab);
 
  $str = bbc_rank_head($BBC_MAXPAGE, "gstat_pages", 1);
 // ↓↓ 追加
  $BBC_PUKIWIKI_SITE = "http://サイト名/index.php?";
 // ↑↑ 追加
 
  for ($k = 0; (list($page_name, $page_elem) = each($page_tab))
                 && ($k < $BBC_MAXPAGE); $k++) {
 // ↓↓変更
 //    $page_name = ($page_name == "index") ? $_['navbar_Main_Site'] : $page_name;
 //    $str .= bbc_list_item("", "<a href=\"".$page_elem['uri']."\">$page_name</a>",
               $page_elem['count'], $page_total);
    $str .= bbc_list_item("", "<a href=\"". $BBC_PUKIWIKI_SITE . rawurlencode($page_name) .
            "\">$page_name</a>", $page_elem['count'], $page_total);
 // ↑↑変更
  }

PukiWiki の設置例

PukiWiki の中身を良く理解してないため手抜きですが、それでもよければ。
とりあえず、動いていますが。すべてハンドリングできていないかもしれません。$non_script を適当に追加してください。

./index.php
12 行目あたり
/////////////////////////////////////////////////
// Directory definition
// (Ended with a slash like '../path/to/pkwk/', or '')
define('DATA_HOME',	'');
define('LIB_DIR',	'lib/');
 
/////////////////////////////////////////////////
require(LIB_DIR . 'pukiwiki.php');
 
// BBClone begin ログ解析開始
$script = $vars['cmd'] . $vars['plugin'];
$script = ($script == "") ? "read?" : $script;
$raw_page = isset($vars['page']) ? $vars['page'] : "no page";
$cook_page = isset($page) ? $page : "no title";
 
//$non_script ="^$";
//$non_raw_page   = "^$";
//$non_cook_page   = "^$";
 
$non_script  ="^attach|^backup|^diff|^edit|^freeze|";
$non_script .="^list|^new|^ref($|erer)|^rename|^rss|^template";
$non_raw_page   = $non_list;
$non_cook_page = "^単語検索";
 
if (! mb_ereg_match($non_script, $script) and ! mb_ereg_match($non_raw_page, $raw_page)
 and ! mb_ereg_match($non_cook_page, $cook_page)) {
	$cook_page = ($script == "read") ? $cook_page : "$script($cook_page)";
	define("_BBC_PAGE_NAME", $cook_page);
	define("_BBCLONE_DIR", "〜/bbclone/");  // ← ここは自分の環境用にあわせて
	define("COUNTER", _BBCLONE_DIR."mark_page.php");
	if (is_readable(COUNTER)) include_once(COUNTER);
}
// BBClone end ログ解析終了
exit;


日本オラクル
■ 日本オラクル 株式会社
■ オラクルマスター資格 (オラクルマスターとは
■ Oracle のライセンスがわからない…
Oracle Direct (ネットで聞いても最後はここで要確認)

*1 サーチエンジンにより"+"が区切り文字でない場合には誤解釈されます。