人は誰でも物事を評価したがります。この傾向はきっと、人間の DNA に組み込まれているのでしょう。私はよく娘と一緒に映画を観に行きます。昔はどんな映画でも気に入っていた彼女ですが、4 才になった今は遥かに好みにうるさくなっています。そこで私が彼女に教えたのが、Ebert and Roeper 式 (※訳注: 米国の映画評論番組) の「満足」か「不満足」かの評価システムです (娘によると、「シュレック 3」は満足という評価でした)。インターネットでの製品や記事などの評価やレビューがこれほどまでに人気なのも、人々の評価好きが理由なのでしょう。
この記事では、MySQL、PHP、Prototype.js、そして Ajax (Asynchronous JavaScript™ and XML) の組み合わせを使って単純な評価とコメントの機能をサイトに追加する方法を説明します。
私の娘は満足か、または不満足かというシステムを気に入っていますが、大抵の人々が使っているのはもう少し微妙な差をつけられる 5 つ星システムです。このシステムでは星 1 つで最低、星 5 つで最高、そして星 3 で平均という意味になります。この記事のサンプルでは、5 つ星の評価システムを映画に適用することにします。もちろん映画でなくても構いません。記事、製品、ポッドキャストなど、ご自分のニーズに合わせたものに何なりと変えてください。
リスト 1 は、このサンプルのスキーマです。最初にあるのは極めて単純な映画用のテーブル (movies) で、自動的にインクリメントされる映画の ID と映画の名前で構成されます。次にくるのは映画に対する各票を保持する評価用のテーブル (ratings) です。movie_id によって movies テーブルにバインドされるこの ratings テーブルには、もう 1 つのフィールドがあります。それが、1 から 5 の数値による評価です。
リスト 1. rating.sql
DROP TABLE IF EXISTS movies;
CREATE TABLE movies (
movie_id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR( 128 ) NOT NULL,
PRIMARY KEY ( movie_id )
);
DROP TABLE IF EXISTS ratings;
CREATE TABLE ratings (
movie_id INTEGER NOT NULL,
rating INTEGER NOT NULL
);
|
「一人一票」を実施するのであれば、ratings テーブルにユーザー ID も追加して、その個人が映画ごとに一票しか記録できないようにすることもできます。しかしこのサンプルは単純にしておきたいので、その部分については省略します。
スキーマをデータベースに組み込むには、まずデータベースを作成してからスキーマを追加しなければなりません。それにはコマンド・ラインで以下のように指示します。
% mysqladmin create comments % mysql comments < ratings.sql |
お使いの MySQL システムによっては、ログイン・クリデンシャルを追加しなければならない場合があります。
作業を進めるには、選択可能な映画を表示して映画ごとの評価ページに移動するページが必要となります。この索引ページは、リスト 2 のとおりです。
リスト 2. index.php
<html>
<body>
<?php
// Install the DB module using 'pear install DB'
require_once 'DB.php';
$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$res = $db->query( 'SELECT * FROM movies' );
while( $res->fetchInto( $row ) )
{
?>
<a href="rate.php?id=<?php echo($row[0]) ?>"><?php echo($row[1]) ?></a><br/>
<?php
}
?>
</body>
</html>
|
作業を簡単にするため、SQL (構造化照会言語) 文を使って、movies テーブルに有名な映画をいくつか追加しました (「ダウンロード」から入手できます)。索引ページには、図 1 のように映画が表示されます。
図 1. 映画リスト
サンプル・コードでこのリストが表示されない場合は、おそらく PEAR リポジトリーからまだ DB モジュールをインストールしていないことが原因だと考えられます。DB モジュールは、コマンド・ラインで以下のコマンドを実行するだけでインストールできます。
% pear install DB |
映画のリストが表示されたら、映画をランク付けできると同時に現在の票集計と平均評価を表示できるページを実装します。リスト 3 に、rate.php ページでのこの一連の作業を示します。
リスト 3. rate.php
<?php
// Install the DB module using 'pear install DB'
require_once 'DB.php';
$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$id = $_GET['id'];
$title = '';
$res = $db->query( 'SELECT name FROM movies WHERE movie_id=?', array( $id ) );
while( $res->fetchInto( $row ) ) { $title = $row[0]; }
?>
<html>
<head>
<title><?php echo($title); ?></title>
<script src="prototype.js"></script>
<script>
function rate( value ) {
new Ajax.Updater( 'rating', 'ratemovie.php?id=<?php echo($id)?>&v='+value );
}
</script>
</head>
<body>
<h1><?php echo($title); ?></h1>
<div id="rating">
<img src="star_off.gif" onclick="rate(1)"></img>
<img src="star_off.gif" onclick="rate(2)"></img>
<img src="star_off.gif" onclick="rate(3)"></img>
<img src="star_off.gif" onclick="rate(4)"></img>
<img src="star_off.gif" onclick="rate(5)"></img>
<br/><br/>
<?php
$res2 = $db->query(
'SELECT count( rating ), sum(rating ) FROM ratings WHERE movie_id=?',
$id
);
while( $res2->fetchInto( $row ) )
{
?>
Votes: <?php echo($row[0]); ?><br/>
Average Rating: <?php echo($row[1]/$row[0]); ?>
<?php
}
?>
</div>
</body>
</html>
|
ファイルの最初のほうでは、パラメータとして渡した ID を持つ映画のタイトルを取得しています。スクリプトの中央では、prototype.js ライブラリーを組み込み、この Prototype ライブラリーを使用して Ajax で ratemovie.php ページを呼び出す rate() JavaScript 関数を作成しています。その後に追加している一連の星の画像のそれぞれには、星がクリックされると rate() 関数を呼び出すスクリプトがあります。
ファイルの最後では簡単なクエリーを実行して、投票数と指定の映画に対する票の集計結果を取得しています。そのデータを表示して、読者に該当する映画がどのように評価されているかを知らせるというわけです。
リスト 4 の ratemovie.php スクリプトの役目は、評価をデータベースに追加した後、元のページでの星とレビュー・カウントを置換するハイパーテキスト・マークアップ言語 (HTML) コードを返すことです。
リスト 4. ratemovie.php
<?php
// Install the DB module using 'pear install DB'
require_once 'DB.php';
$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$v = $_GET['v'];
$id = $_GET['id'];
$sth = $db->prepare( 'INSERT INTO ratings VALUES ( ?,? )' );
$db->execute( $sth, array( $id, $v ) );
?>
<img src="star_<?php echo( ($v>0)?'on':'off' ) ?>.gif"></img>
<img src="star_<?php echo( ($v>1)?'on':'off' ) ?>.gif"></img>
<img src="star_<?php echo( ($v>2)?'on':'off' ) ?>.gif"></img>
<img src="star_<?php echo( ($v>3)?'on':'off' ) ?>.gif"></img>
<img src="star_<?php echo( ($v>4)?'on':'off' ) ?>.gif"></img>
<br/><br/>
<?php
$res2 = $db->query(
'SELECT count( rating ), sum(rating ) FROM ratings WHERE movie_id=?',
$id
);
while( $res2->fetchInto( $row ) )
{
?>
Votes: <?php echo($row[0]); ?><br/>
Average Rating: <?php echo($row[1]/$row[0]); ?>
<?php
}
?>
|
実際の評価ページを図 2 に記載します。
図 2. 評価ページ
星のいずれかをクリックすると、票がデータベースに追加されます。つまり、星、投票数 (Votes)、そして平均評価 (Average Rating) の HTML コードが変更されて票の追加が反映されるということです。
理想としては、すべての映画の得点をホーム・ページで確認できるようにしたいものです。この目標を達成するのが、リスト 5 の新しいバージョンの索引です。
リスト 5. index2.php
<html>
<body>
<table>
<?php
require_once("DB.php");
$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$res = $db->query( 'SELECT * FROM movies' );
while( $res->fetchInto( $row ) )
{
$res2 = $db->query(
'SELECT count( rating ), sum(rating ) FROM ratings WHERE movie_id=?', $row[0]
);
$rating = 0.0;
while( $res2->fetchInto( $row2 ) ) { $rating = $row2[1] / $row2[0]; }
?>
<tr><td align="center">
<?php echo( $rating > 0 ? $rating : 0 ) ?>
<td><td>
<a href="rate2.php?id=<?php echo($row[0]) ?>"><?php echo($row[1]) ?></a>
</td></tr>
<?php
}
?>
</table>
</body>
</html>
|
図 3 に示す新しいバージョンの索引には、映画ごとの評価が表示されています。
図 3. 更新された映画ページ
Ajax、PHP、MySQL、そして極めて便利な Prototype.js JavaScript ライブラリーを使って投票の仕組みを実装するのに必要なことはこれだけです。
このサンプルの次の段階では、映画のコメント (レビュー) を実装します。
Web でのコメント・システムは、大抵のブログ・コメント・システムなどのようにブログ・エントリーにコメントのストリングを付けただけの極めて単純なものから、Slashdot にあるようなスレッド化されたコメント・システムなどのように極めて高度なものまで千差万別です。
この記事では単純なほうのコメント・システムを使いますが、必要に合わせて調整してください。
まず、既存のデータベース・スキーマにテーブルを追加するところから取り掛かります。リスト 6 を見てください。
リスト 6. comments.sql
DROP TABLE IF EXISTS comments;
CREATE TABLE comments (
movie_id INTEGER NOT NULL,
email VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
comment TEXT NOT NULL
);
|
movie_id フィールドによって映画に結び付けられるのはコメント用のテーブル (comments) です。その後に E メール・アドレス、コメント投稿者の名前、そしてコメントのテキストがあります。これは至って初歩的なコメント・システムで、WordPress や MoveableType などのブログ・ソフトウェアに用意されているものと似ています。
スレッド化されたコメント・システムをお望みであれば、オート・インクリメント ID をテーブルに追加してから、それぞれのコメントの親コメントを指定する NULL 可能 parent_id フィールドを設定することになります。このフィールドが NULL の場合、そのコメントは最上位レベルのコメントだということになります。
コメント機能を評価ページに追加するには、ページの最後に追加スクリプトを組み込むだけです。リスト 7 に、この新しい PHP コードを示します。
リスト 7. rate2.php
...
<h2>Comments</h2>
<div id="comments">
<?php
$res3 = $db->query(
'SELECT * FROM comments WHERE movie_id=?',
$id
);
while( $res3->fetchInto( $row3 ) )
{
?>
<div>
<a href="mailto:<?php echo($row3[1]) ?>"><?php echo($row3[2]) ?></a> says:
'<?php echo($row3[3]) ?>'
</div>
<?php
}
?>
</div>
<div style="margin-top:20px;">Add your own comment:</div>
<form id="cform">
<input type="hidden" name="id" value="<?php echo($id)?>">
<table>
<tr><td>Name:</td><td><input type="text" name="name"></td></tr>
<tr><td>Email:</td><td><input type="text" name="email"></td></tr>
<tr><td>Comment:</td><td><textarea name="comment" id="comment_text"></textarea></td></tr>
</table>
</form>
<button onclick="addcomment()">Add Comment</button>
<script>
function addcomment()
{
new Ajax.Updater( 'comments', 'addcomment.php',
{
method: 'post',
parameters: $('cform').serialize(),
onSuccess: function() {
$('comment_text').value = '';
}
} );
}
</script>
</body>
</html>
|
上記のスクリプトは、"comments" という <div> タグに、データベースから該当する映画に関する現在のコメントを設定するところから始まります。その下の標準 HTML <form> タグには、コメント投稿者の名前とその E メール・アドレス、そしてコメント用のフィールドが含まれます。このフォームには隠し値 (現在表示中の映画の ID) も含まれ、コメント追加スクリプトがどの映画にコメントを割り当てるのかを判断できるようになっています。
フォームの下のほうに配置される Add Comment ボタンが呼び出すのは、addcomment() JavaScript 関数です。この関数は Prototype.js ライブラリーの Ajax.Updater オブジェクトを使って、addcomment.php スクリプトを呼び出します。このスクリプトは、同じく Prototype.js によって提供される極めて便利な serialize() 関数を使用して、名前、E メール・アドレス、コメントをパッケージ化します。
このコードでは、コードが正常に受け付けられた場合にはコメント・フィールドのテキストがリセットされ、ユーザーが名前と E メール・アドレスを再入力しなくても好きなだけコメントを追加できるように設定しています。
リスト 8 に、addcomment.php スクリプトを記載します。
リスト 8. addcomment.php
<?php
require_once("DB.php");
$id = $_POST['id'];
$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$sth = $db->prepare( 'INSERT INTO comments VALUES ( ?, ?, ?, ? )' );
$db->execute( $sth, array( $id,
$_POST['email'], $_POST['name'], $_POST['comment' ] ) );
$res = $db->query('SELECT * FROM comments WHERE movie_id=?', $id );
while( $res->fetchInto( $row ) )
{
?>
<div>
<a href="mailto:<?php echo($row[1]) ?>"><?php echo($row[2]) ?></a> says:
'<?php echo($row[3]) ?>'
</div>
<?php
}
?>
|
まずスクリプトがデータベースに追加しているのは、POST データに指定されたコメントです。次にすべてのコメントを HTML コードとして出力します。ここまでは元のページでの内容とまったく同じですが、今回はユーザーが提供したコメントも表示されます。
図 4 は、新しい評価ページです。
図 4. コメントを表示するように更新された評価ページ
このコメント・システムによる閲覧者へのフィードバックは瞬時に行われ、ユーザーが Add Comment をクリックすると、コメントが更新されて新しいコメントが所定の位置に表示されます。このシステムはまた、他の閲覧者がそれまでに送信して追加されたコメントも表示します。
お望みとあれば、このサンプルを拡張してサーバーを定期的にポーリングし、コメントのセクションを新しいコメントで更新することも可能です。その場合はもちろん、addcomment.php を呼び出すことはできません。代わりに、新しいコメントを追加せずに単にコメントを返すだけのスクリプトが必要になります。このスクリプトを簡単に作成できるように Prototype.js で用意しているのが、Ajax.PeriodicalUpdater クラスです。ID、更新間隔、そして URL を指定すると、このクラスが Web ページの任意の部分を指定した間隔で更新してくれます。
このサンプルを簡単に拡張するもう 1 つの方法は、映画のリストをそれぞれのランキングと併せて RSS フィードとしてエクスポートすることです。リスト 9 に、そのためのコードを記載します。
リスト 9. rss.php
<?php
header( "content-type:text/xml" );
?>
<rss version="0.91">
<channel>
<title>Movie rankings</title>
<link>http://localhost/comments/rss.php</link>
<?php
require_once("DB.php");
$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$res = $db->query( 'SELECT * FROM movies' );
while( $res->fetchInto( $row ) )
{
$res2 = $db->query(
'SELECT count( rating ), sum(rating ) FROM ratings WHERE movie_id=?', $row[0]
);
$rating = 0.0;
while( $res2->fetchInto( $row2 ) ) { if ( $row2[0] > 0 ) $rating = $row2[1] / $row2[0]; }
?>
<item>
<title><?php echo($row[1]) ?> -
<?php echo( $rating > 0 ? $rating : 0 ) ?> stars</title>
<link>http://localhost/commentsts/rate2.php?id=<?php echo($row[0]) ?></link>
<description><?php echo($row[1]) ?></description>
</item>
<?php
}
?>
</channel>
</rss>
|
リスト 9 のコードは、HTML フォーマットでデータを作成する代わりの手段でしかありません。<table> 、<tr> 、<td> タグの代わりに <title> 、<description> 、<link> タグを使ってそれぞれの映画ページを指定しています。Firefox ブラウザーでこのページを指定すると、図 5 のように表示されます。
図 5. ブラウザーでの RSS フィード
至って簡単なものです。このように、PHP から XML フィードを取り出すのは難しいことではありません。
このコードをローカルで実行するには、以下のコマンド・ラインを使います。
% php rss.php |
これで、RSS XML が直接表示されます。リスト 10 はこの RSS の抜粋です。
リスト 10. RSS の抜粋
<rss version="0.91">
<channel>
<title>Movie rankings</title>
<link>http://localhost/comments/rss.php</link>
<item>
<title>Star Wars - 4.5 stars</title>
<link>http://localhost/commentsts/rate2.php?id=1</link>
<description>Star Wars</description>
</item>
<item>
...
|
ユーザーによって生成されるコンテンツや、それが Web 2.0 の駆動力となる仕組みについては多くの誇大広告を目にすると思いますが、この記事のサンプルを見ておわかりのように、Prototype.js ライブラリーのような優れたツールを使えば簡単に Ajax アプリケーションをビルドすることが可能になります。閲覧者が簡単にサイトの内容にランクを付けたり、コメントできるようにする機能で、ユーザー生成による素晴らしいコンテンツを提供してください。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Source code for this article | x-ajaxxml5-code.zip | 22KB | HTTP |
学ぶために
-
PHP ホーム・ページ: PHP プログラマーのための貴重な情報源にアクセスして、この広範に使われているスクリプト言語に関する情報を入手してください。
-
Prototype ライブラリー: 動的 Web アプリケーションの開発を簡易化するために設計された JavaScript フレームワークについて調べてください。
-
Scriptaculous JavaScript ライブラリー: この Prototype ベースのフレームワークで、Web サイトを成功させるための表示支援機能と効果を見つけてください。
-
Prototype.js 資料ページ: Prototype JavaScript ライブラリーについての詳細を調べてください。ここには、正式な Prototype ブログをはじめとする多彩な資料へのリンクが記載されています。
-
jQuery: Prototype.js と同様の機能を提供するもう 1 つの JavaScript ライブラリーです。
-
Yahoo UI Library: Yahoo! の Ajax 対応ツールキットです。
-
developerWorks XML ゾーン: developerWorks XML ゾーンで XML のすべてについて学んでください。
-
IBM XML 認証: XML や関連技術の IBM 認定開発者になる方法について調べてください。
-
XML technical library: 広範な技術に関する記事とヒント、チュートリアル、標準、そして IBM レッドブックについては、developerWorks XML ゾーンを参照してください。
-
developerWorks technical events and webcasts: これらのセッションで最新情報を入手してください。
-
Ajaxian: この優れた情報源で、Ajax、そして Ajax を使用するフロント・エンドのウィジェットについての最新開発情報を入手してください。
製品や技術を入手するために
- IBM®
DB2® Enterprise 9: DB2 Express 9 データ・サーバーの無料バージョン、DB2 9 (DB2 Express-C 9) の試用版をダウンロードしてください。
議論するために
-
XML ゾーンのディスカッション・フォーラム: XML を中心としたフォーラムに参加してください。
Jack D. Herrington は、20年以上の経験を持つシニア・ソフトウェア・エンジニアです。彼の著書には、『Code Generation in Action』、『Podcasting Hacks』、『PHP Hacks』の 3 冊があります。また、30 を超える記事も執筆しています。連絡先は jherr@pobox.com です。