この記事の内容は、時間経過およびプログラムやシステムのバージョン アップなどの事情によって、現状に正しくそぐわない内容、またはそれどころか、場合によっては問題を引き起こす可能性があります。参考程度に留め、関連記事アーカイブを検索してみてください。

MovableType で人気記事のランキングを表示する PHP スクリプト:hottopic

Posted by
ぴろり
Posted at
2005/05/26 17:44
Trackbacks
関連記事 (7)
Comments
コメント (17)
Post Comment
コメントできます
Category
MovableType カテゴリ

 Movable Type で構築したサイトで、各記事ごとのアクセス数を集計できれば、"今週の人気記事 トップ 10"のような機能が実現できるでしょう。丁度、ここのホストでも Apache のアクセスログがユーザに解放されているので、これを利用することができそうです。
 結果、特にプラグインを追加せず、PHP を使用することで、サイトデザインの容易性、他ホストでの可搬性を高めつつ、これを実現することができました。また、記事のファイル名がエントリ ID 以外(日付やキーワード)で生成されている場合にも対応でき、cron による定期実行やブラウザからのランキング更新も可能です。

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

経緯

 先ずは、この人気記事ランキングを実現する方法について Web を検索したところ、"Masahiko Isshiki WEB SITE:MT で人気記事のランキングを表示する" という記事が大変参考になりました。ここでは Jeff Borlik 氏のT-MostVisited Pluginを使用してこれを実現する方法が、インストール手順から詳しく説明されています。このプラグインは MT の再構築時にアクセスログの集計と表示を行うためのもので、比較的簡単に導入し実現することができそうです。
 しかしながら、このプラグインでは記事ファイル名が記事 ID を含む必要があり、これ以外の書式、例えば日付を基に生成されている場合(/2005/1234_1234.html)などでは、このプラグインを使用することができません。これは単純に、アクセスログに残ったファイル名から記事 ID を特定できないことから、その記事のタイトルや投稿者といった情報にアクセスできないためだと思われます。
 また、ランキングのリアルタイム性を確保するために、これに続く"MTで人気記事ランキングの定期自動実行"で、Perl のスクリプトを別に用意し JavaScript を併用する方法が紹介してあります。このように MT 以外のところで様々なギミックが必要となり、結果的にランキング表示周りの複雑性が増すことになっているようでした。

 今回、紹介する方法は以下の点に重点が置かれています。

  • 記事ファイル名が、日付やキーワードなどから生成されていても対応できること
    … ここのサイトが日付による命名ルールになっているので必須
  • gzip 圧縮されたアクセスログにも対応
    … SAKURA Internetのサーバが(以下略
  • できる限り HTML 知識だけで HTML デザインが容易に行えること
    … ランキングは HTML で成形することになりますが、 この部分が PHP だの JavaScript だのソースコードと混合すると判りにくい&編集しにくいため
  • 設置と運用が簡単
    … 簡単に使えて、あとは手間いらずが理想的
  • 軽い
    … MT の再構築はかなり重い処理です。アクセスログの解析や再構築の負荷を上手に分散します。

動作要件

  • 今のところ Movable Type しか考えていません
  • PHP が稼動すること
    … スクリプトが PHP で書かれています。
  • Web サーバのアクセスログが使用できること
  • または CGI などによるアクセスログが使用できること
    … ログファイルは NCSA コモンログファイル形式に対応しています。 これ以外のログ形式でもスクリプトを編集すればおそらく対応できます。
  • (あれば楽チン) cron などの定期実行がサポートされていること

インストール

 先ずは次のファイルをダウンロードして適当な場所に解凍してください。 hottopic300.php.tmpl というファイルが 1 つ含まれているハズです。 [ダウンロード]

Step 1. ダウンロードしたテンプレートをインデックステンプレートに登録

 ダウンロードしたファイルは、 「『アクセスログの集計を行うための PHP スクリプト』のためのインデックステンプレート(あぁ、ややこしい)」のため、 このままでは実行できません。 このファイルを MT 管理画面から[テンプレート]-[インデックステンプレート]に登録します。 このテンプレートの構築を行って初めて、 "出力ファイル名"で指定されたファイルが実行可能な PHP スクリプトとなります。 また"再構築オプション"は"自動で再構築"でも構いません。 再構築時の負荷はマスターアーカイブの生成と同程度と思います。
 この段階で構築はできると思いますが、設定が済んでいないので実行はできないでしょう。 次の各種設定に続きます。

Step 2-1. 環境設定 - 動作設定

 スクリプトの動作設定を行います。テンプレートの 15〜30 行付近にある以下の項目を修正してください。

nDivDay
集計する期間を日単位で指定します。 スクリプトが実行された瞬間から過去 n 日間のアクセスを集計します。
nTopEntry
集計した結果のうち少なくとも上位 n 件(≠位)をランキングに出力します。 同順位に複数エントリがある場合、その全てを表示します。
szLogDir
サーバのアクセスログが保存されているディレクトリへのパスを指定します。 相対パス指定は実験していません。
szOutput
集計結果を出力するファイル名を指定します。相対パス指定は実験していません。

Step 2-2. 環境設定 - ログファイル名を指定する

 サーバによってアクセスログのファイル名が様々です。37 行付近の GetLogFileNames という関数内でアクセスログのファイル名を生成しているので、 お使いのサーバのアクセスログのファイル名に合わせて修正してください。毎日日付ファイル名でログを残すものや、過去ログを gzip 圧縮するもの、直近の数日のみ残すものなど様々です。
 ログファイルを一つも読めていないような場合は、szLogDir の設定とここの設定を疑ってみてください。

Step 2-3. 環境設定 - 集計対象とするファイル名を指定する

 お使いの MT のカスタマイズによって、個別アーカイブの生成ファイル名は様々かと思います。 76 行付近の IsTargetURL はアクセスログに残されたファイル名が ランキング集計対象か否かを判定するための関数です。 ランキング集計したいファイル名にマッチするよう Perl の正規表現を修正してください。
 スクリプト実行時の標準出力を見て、1 件も集計されいないような場合、 ここのパターンマッチングで失敗していることが考えられます。

Step 2-4. 環境設定 - 集計結果を成形する

 集計結果を成形して書き出すためにCreateEntryListItem(111 行付近) と CreateEntryList(126 行付近) のうち、それぞれ 2 つの /******** コメント ********/ で囲まれた範囲を修正してください。とりあえず動作を見たいという御仁は、このステップを飛ばされても構いません。
 1 つのエントリにつき CreateEntryListItem が呼び出されて、1 つ分の HTML を生成します。 次にこれが nTopEntry 回だけ繰り返されて、 CreateEntryList でその結果を含めた HTML が 生成されるようになっています。
 HTML 部分は HTML タグや MT のテンプレートタグをそのまま使うことができます。 またランキングの集計結果を使う場合は {$entry['キー名']} という記述で値を自由に埋め込むことができます。例えば、次のようにして記述できます。

・CreateEntryListItem の例
第 {$entry['Ranking']} 位:
<a href="{$entry['EntryPermalink']}">{$entry['EntryTitle']}</a>
   ({$entry['ReferCount']} Hits)<br />
<i>Posted by {$entry['EntryAuthorNickname']}
at {$entry['EntryDate']}</i>

・CreateEntryList の例
<h4>■ 過去{$entry['nDivDay']}日間の人気記事
   トップ{$entry['nTopEntry']}</h4>
{$entry_list}

Step 3. ランキングを集計する

 Step 2.までの設定が終わったら、テンプレートを再構築してランキング集計スクリプトを書き出します。そして、このランキング集計スクリプトを実行すれば、集計結果が szOutput に出力されます。ランキング集計はこのスクリプトが実行された瞬間に行われます。
 スクリプトを実行する手段として

  • シェルログインしてコマンドラインで実行する
  • cron を使って定期実行する
  • ブラウザから呼び出す

の何れかの方法が可能です。目的に合わせて適宜選択してください。

Step 4. 集計結果を利用する

 集計結果ファイルはそのまま表示することもできますし、PHP の include を利用してページに埋め込むこともできます。後々のメンテナンスのことを考えると、集計スクリプトで成形する HTML は最低限にし、それを取り込む側で本格的にデザインを施す方が簡単でしょう。

その他の機能 - エントリの他の情報が必要になった

 CreateEntryListItemCreateEntryList で HTML を成形する場合、 エントリについてさらに細かな情報が必要になることがあります。 88 行付近の GetEntryList では、HTML の生成に必要なエントリの各種情報のテーブルを作成しています。ここに任意の名前でキー名を登録し、テンプレートタグを駆使してエントリの情報を取得するようにします。

・エントリの最新のコメントの日付が必要な場合の例
:(GetEntryList の一部)
'EntryAuthorNickname' =>
		'<$MTEntryAuthorNickname encode_php="q"$>',
'EntryCategory' =>
		'<$MTEntryCategory encode_php="q"$>',

// ↓この行を追加します
'LastCommentedDate' =>
		'<MTComments lastn="1"><$MTCommentDate encode_php="q"$></MTComments>',
null));

 この部分は PHP スクリプトとして実行される部分になりますので、encode_php タグ・アトリビュートを指定して、文字列を安全にしてください。

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



関連記事/トラックバック (全 7 件中、最新 5 件まで表示しています)

blog Boreal Kiss のスクリーンショット
タイトル
人気記事ランキング設置メモ
Trackbacked at
2007/10/04 16:30
from
blog Boreal Kiss
概要
<概要> MovableTypeの各記事の人気ランキングを表示する方法。MTのラ...

BITMAP のスクリーンショット
タイトル
人気エントリーのランキングを表示
Trackbacked at
2007/06/04 23:36
from
BITMAP
概要
当ブログの各エントリーへのアクセスをカウントし、そのランキングを表示させてみた。...

とあるアフィリエイターカップルのおはなし のスクリーンショット
タイトル
人気記事ランキングの追加
Trackbacked at
2006/11/12 02:01
from
とあるアフィリエイターカップルのおはなし
概要
明日はちぃやんのスピーチの本番なのに、僕は風邪をひきました。 最近は寒くなってきていたので、ちょっと危ないなぁと思っていた矢先に風邪を・・・ (^0^;) 体の...

Project MultiBurst のスクリーンショット
タイトル
人気記事ランキングを設置(再び)
Trackbacked at
2006/10/19 17:34
from
Project MultiBurst
概要
以前、 「Project MultiBurst:EUCでの人気記事ランキング」 というのをやりましたが、このランキングだとある一定期間のランキングが表示できませ...

りえすけ島ナンデモ日誌 のスクリーンショット
タイトル
人気記事ランキング
Trackbacked at
2006/06/03 02:35
from
りえすけ島ナンデモ日誌
概要
ここ数日、人気記事ランキングというのをつけようとしてmt-mostvisited...

この記事にトラックバックを送るには?

寄せられたコメント (全 17 件中、最新 5 件まで表示しています)

Posted by
ぴろり ◆OLEEi.VOX.ぴろり ◆OLEEi.VOX.
at
2015/04/16 15:52
ID
Jkw0x5DQ
Google Analytics のデータを集計する方法がサーバに依存せず汎用的です。
人気記事の一覧を Google Analytics から取得する:GADGET
http://www.magicvox.net/archive/2012/05101046/
Posted by
まぶおまぶお
at
2011/04/17 10:17
ID
.fXLrHDM
回答ありがとうございます!
自分はIDではなく、特定のファイル名を設定していたので、
&ltMTEntries lastn="0"&gt
'/map/tokyo/furugi/&lt$MTEntryID$&gt.html' => &lt$MTEntryID$&gt,
&lt/MTEntries&gt
で取得する事ができました!
最期に質問と言うか、要望?みたいなのになっちゃうのですが・・・(・∀・;)
hottopic300.phpをそれぞれ違うディレクトリに配置して、$szOutputと$gAllEntriesの設定値を変更し、
それぞれのカテゴリの集計結果をとろうと思っているのですが、まとめてhottopic300.phpを実行する方法は
ありますでしょうか?背景として、レンタルサーバ側のcronの個数が限られているので、複数のhottopic300.phpを
実行するのは難しいかなと思いまして。
このスクリプトは軽いのがメリットですので、そういった動作は想定されてないと思いますし、
本スクリプト機能以上の質問しているかもしれませんが、もし何か良い案がありましたら教えてください。
よろしくお願いします。
Posted by
ぴろり ◆OLEEi.VOX.ぴろり ◆OLEEi.VOX.
at
2011/04/16 19:07
ID
pjDLEdrY
>2.00で『 return (preg_match ("/^/map/tokyo/furugi/w+.html/", $url));』
2.x で preg_match を使って集計対象の URL か否か判別していましたが、集計対象の URL だった場合には、更にその URL からブログ記事 ID を取得していました。正規表現は便利ですが複雑ですので、それならいっそ、集計対象の URL を羅列してしまえ、というのが 3.x の $gAllEntries 変数です。
ですので、$gAllEntries のキー文字列は末端のファイル名までのパスを含まなければなりません。まぶおさんの場合ですと、例えば
<MTEntries lastn="0"&gt;
    '/map/tokyo/furugi/<$MTEntryID$&gt;.html' => <$MTEntryID$&gt;,
</MTEntries&gt;
のようになると思います(HTML のファイル名は適当です)
Posted by
まぶおまぶお
at
2011/04/16 13:36
ID
GMoWnvJ6
すみません、3.00で
$gAllEntries = array (
<MTEntries lastn="0">
    '/map/tokyo/furugi/' => '<$MTEntryID$>',
</MTEntries>
    null);
と記述して出力されませんでした。
原因がお分かりでしたら教えてください。
Posted by
まぶおまぶお
at
2011/04/16 13:31
ID
GMoWnvJ6
回答ありがとうございます!
1、なるほど、$gAllEntries内で複数のディレクトリを指定し、集計する事が可能というわけですね!
ここで質問なんですが、3.00から$gAllEntriesは正規表現は使わないようになっているように見えます。
2.00で『 return (preg_match ("/^/map/tokyo/furugi/w+.html/", $url));』
と設定して、対象のカテゴリ記事を取得する事ができたのですが、
3.00で『    '/map/tokyo/furugi/' => '<$MTEntryID$&gt;',』
と設定してもファイルを取得する事ができませんでした。
他に確認する箇所はありますでしょうか?

コメントを投稿する

 
 (必須, 匿名可, 公開, トリップが使えます)
 (必須, 匿名可, 非公開, Gravatar に対応しています)
 (必須)
スパム コメント防止のため「投稿確認」欄に ランダムな数字 CAPTCHAについて を入力してから送信してください。お手数ですがご協力のほど宜しくお願いいたします。