Rewish

ウェブデザイン、XHTML、CSS、PHP、WordPress、Movable Typeなど、Web制作で役立つかも知れないBlog.

PHPとjQueryでCometっぽいモノを実装する

カテゴリー
JavaScript, PHP/MySQL
タグ
Ajax, Comet, jQuery

クライアントからのリクエストに対してすぐに応答せず溜めておき、何らかのタイミングを見計らって応答(レスポンス)を返す技術、Comet

例えばチャットなんかで使うと、相手が発言したタイミングでレスポンスが返ってくるので、リアルタイムに会話が出来たりする訳です。

ただ、"本物のComet"は実装にはやや知識的なコストが掛かるので、今回はPHPとjQueryを使ってもう少し簡単に実装してみたいと思います。

※あくまでも実装の一例なので、このままでは利用シーンがかなり限定される事をご留意下さい。

注意事項

以下の実装方法は、知識的なコストがあまり必要ない替わりに、サーバー的なコストを多く消費します。

共有レンタルサーバーなんかで使うと、アカウント制限・停止などの処置がとられる場合があるので、共有で使うスペースなどでの使用は避け、専用サーバーや自前のサーバーなどで使用して下さい。

ダウンロード

comet.zip [2008/12/10]

偽Comet動作の流れ

大まかな流れはこんな感じです。

  1. Ajax(XMLHttpRequest)を利用してサーバー(PHP)にリクエストを送る
  2. リクエストを受けたPHPはトリガーイベントが発生するまで待機(ループ)
  3. PHPはトリガーイベントが発生したらレスポンスを返し終了
  4. クライアント側はレスポンスを受け取り、必要ならば再度リクエスト(1へ)

2はwhileで無限ループして仮想待機状態にし、sleep()で若干負荷を軽減する感じ。

PHPのサンプルコード

取り敢えず表示確認できればいいので簡単に。
<?php
if (isset($_GET['mode'])) {
	// データを書き込むファイル
	define('DATA_FILE', 'data.log');
	// モードの振り分け
	switch ($_GET['mode']) {
		// データを取得
		case 'view':
			$data = getUpdate();
			break;
		// 更新チェック
		case 'check':
			$data = checkUpdate();
			break;
		// データを保存
		case 'add':
			$data = addUpdate($_POST['str']);
			break;
	}
	// 結果を表示
	echo nl2br(htmlspecialchars($data, ENT_QUOTES));
}

/**
 * データを取得
 */
function getUpdate()
{
	return file_get_contents(DATA_FILE);
}


/**
 * 更新チェック
 *
 * 対象データに変化が無ければループし続ける。
 * 変化が有れば新しいデータ追加した全てのデータを返す。
 */
function checkUpdate()
{
	$data = file_get_contents(DATA_FILE);
	$temp = $data;
	while ($temp === $data) {
		$temp = file_get_contents(DATA_FILE);
		sleep(1);
	}
	return $temp;
}

/**
 * データ追加
 *
 * 新しいデータを追加して全てのデータを返す。
 */
function addUpdate($str)
{
	if (!empty($str)) {
		$str = str_replace(array("\n", "\r"), '', $str);
		$str = $str . ' [' . date('c') . ']' . PHP_EOL;
		file_put_contents(DATA_FILE, $str, FILE_APPEND|LOCK_EX);
	}
	return getUpdate();
}

jQueryのサンプルコード

これまた簡単に。
/**
 * 偽Comet開始
 */
$(document).ready(function()
{
	getUpdate();
	addUpdate();
});

/**
 * データ取得
 */
function getUpdate()
{
	$.post('/comet.php?mode=view', {}, function(data)
	{
		$('dd#view').html(data);
		checkUpdate();
	});
}

/**
 * 更新チェック
 */
function checkUpdate()
{
	$.post('/comet.php?mode=check', {}, function(data)
	{
		$('dd#view').html(data);
		checkUpdate();
	});
}

/**
 * データ追加
 */
function addUpdate()
{
	$('form#add').submit(function()
	{
		var param = $('input[name="str"]').val();
		$.post('/comet.php?mode=add', {str:param}, function(data)
		{
			$('input[name="str"]').val("");
			$('dd#view').html(data);
		});
		return false;
	});
}

IEのキャッシュ対策のためにPOSTでリクエスト。

HTMLのサンプルコード

<dl>
	<dt>データ<dt>
	<dd id="view">ここにデータ</dd>
</dl>

<form id="add" action="comet.php?mode=add" method="post">
	<p>
		<input type="text" name="str" value="" />
		<input type="submit" value="追加" />
	</p>
</form>

利用シーン

社内システムや小規模会員制システムなど、リクエスト数が把握出来る時などにサクっと組み込むと幸せ。