本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。プロフィールで選択した情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

Ajax と XML: 評価とコメントのための Ajax

Ajax 技術を使って、使いやすい評価機能とコメント機能をアプリケーションに追加する

Jack D. Herrington (jherr@pobox.com), Senior Software Engineer, Leverage Software Inc.
Jack D. Herrington は、20年以上の経験を持つシニア・ソフトウェア・エンジニアです。彼の著書には、『Code Generation in Action』、『Podcasting Hacks』、『PHP Hacks』の 3 冊があります。また、30 を超える記事も執筆しています。連絡先は jherr@pobox.com です。

概要: 人々によって Web が動かされるこの時代、読者がサイトのコンテンツにランクを付けたり、論評できるようにすることは必須です。Ajax を使えば、どんなに簡単に評価機能とコメント機能をサイトに追加できるのか、この記事を読んで理解してください。

このシリーズの他の記事を見る

日付:  2007年 7月 24日
レベル:  中級 この記事の原文:  英語
アクティビティー: 4275 ビュー
お気軽にご意見・ご感想をお寄せください: 


人は誰でも物事を評価したがります。この傾向はきっと、人間の 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 ページの任意の部分を指定した間隔で更新してくれます。


RSS フィードの追加

このサンプルを簡単に拡張するもう 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 articlex-ajaxxml5-code.zip22KBHTTP

ダウンロード形式について


参考文献

学ぶために

  • 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) の試用版をダウンロードしてください。

議論するために

著者について

Jack D. Herrington は、20年以上の経験を持つシニア・ソフトウェア・エンジニアです。彼の著書には、『Code Generation in Action』、『Podcasting Hacks』、『PHP Hacks』の 3 冊があります。また、30 を超える記事も執筆しています。連絡先は jherr@pobox.com です。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source, Web development
ArticleID=253223
ArticleTitle=Ajax と XML: 評価とコメントのための Ajax
publish-date=07242007
author1-email=jherr@pobox.com
author1-email-cc=dwxed@us.ibm.com