WebTecNote

[mootools&PHP] Ajax.Request でファイルの読み書きをする

mootoolsのRequestクラスを使うとXMLHttpRequestが簡単に行えます。
jQueryやprototype.jsもやり方は大体同じです。(クラスの名前からして似てる)
公式サイトのDemoにAjax.Requestのサンプルがいくつかありますが、
送受信だけでは面白くないので、簡単にファイルの読み書きをして掲示板っぽいものを作ってみようー。


直接見る »

▼用意するもの(カッコ内は説明とzipで使ってるサンプルの名前)

※文字コードは全てUTF-8にすること。

Step-by-Step形式で書いています。(全10ステップで2ページ分割)

Step1. XHTMLの作成

まずindex.htmlのヘッダにスクリプトタグとスタータースクリプトを入れておきます。

<script type="text/javascript" src="mootools.js"></script>
<script type="text/javascript">
//<!&#91;CDATA&#91;
window.addEvent('domready', function(){

});
//&#93;&#93;>
</script>

window.addEvent("domready")は、「DOMが読み込み終わったらfunction(){}の内容を実行する」 というメソッドです。

body以下にフォームとログ表示部分を適当に書いて、以下の要素を作ってください。

  1. idがcommentのテキストエリア
  2. idがsubmitのボタン
  3. idがpastlogのブロック要素(DIVなど)

サンプルファイルでは次のようにしました。

index.html

<p id="form"><input type="text" id="comment" size="40" /><button id="submit">Send</button></p>
<div id="pastlog"></div>

Form送信はしないのでformタグの有無はどっちでもいい。
valueやnameも動作には必要ないですが、lint先生に怒られるのが気になる場合は入れておいた方がいいかも。
ここでは分かりやすくIDにしていますが、セレクタを使うのもアリです。
CSSのスタイリングはお好みで。

Step2. ボタンイベントとフォームの値の取得

step1で書いたスタータースクリプトに、input#commentの値を取得するソースと、
button#submitを押した時に発生するイベントのソースを追加します。

「ボタン押す→テキストエリアの値を取得する」という流れになるので、
ボタンのinput#submitにaddEvent()でクリックイベントを監視させ、
クリックされたとき実行する関数の中で、input#commentの値を取得するソースを書きます。

index.html

$("submit").addEvent("click",function(e){
e.stop();
var comment = $("comment").value;
});

Element.valueという書き方はjavascriptの基本のものです。(参考
変数eにはイベントのオブジェクトが入ります。(参考
関数の中にreturn false;かEvent.stop()がないとイベントが止まらずに伝播してしまうので、e.stop();を先頭に書いておきます。

次のように書くと、テキストエリアに入力した内容がdiv#pastlogに表示され、value値が取得されているのが確認できます。

index.html

$("submit").addEvent("click",function(e){
	e.stop();
	var comment = $("comment").value;
	$("pastlog").set("html",comment);
});

Step3. Requestメソッドを追加

本エントリーの主役、Requestクラスの構文は次の通りです。

var myRequest = new Request([options]);

オプションで重要なものだけ以下に説明を添えます。

イベントはFx等とだいたい同じです。

button#submitのクリックイベントで、Requestクラスのインスタンスを作成します。
クリックして直ぐ実行したいのでインスタンスに直接send()を付ける。

index.html

window.addEvent('domready', function(){
	
	$("submit").addEvent("click",function(e){
		e.stop();
		var comment = $("comment").value;
		new Request({
			url:"sample.php",
	      	method: 'post',
		data:{"mode":"post","comment":comment},
		onSuccess: function(txt) {
 			$("pastlog").set('html',txt);
		},
	        onFailure: function() {
	           $("pastlog").set('html', 'エラーが発生しました');
	        }
  		}).send();
	});
});

“data”はHash形式で書いてますが、GETの時と同じ書き方(key=valueを&で繋ぐ)でもいいです。

data:"mode=post&comment="+comment,

ボタン押して何も表示されなければOK。
ここまで書けばPHPファイルへ送信出来てます。

ここまでの動作の流れをまとめると次のようになります。

  1. button#submitをクリックする
  2. input#commentの値を取得する
  3. Requestクラスのインスタンスを作成する
  4. オプションで指定されたURLへデータを送信する

Step4. PHPでPOSTされたデータを返す

とりあえず、Step2と同じように入力された値を表示するようにPHPファイルを編集してみます。

Step3で書いたソースでは、送信するデータが次のようになっていましたが

data:{"mode":"post","comment":comment}

これをPHPで表すと

$_POST["mode"]="POST";
$_POST["comment"]="入力された値";

になります。オプションのメソッドがGETなら$_GETです。
HTMLフォームから送信したときと同じようにPOST変数やGET変数に格納されます。(» スーパーグローバル変数

なので、sample.phpには次の様に書きます。

<?php
if($_POST&#91;"mode"&#93; == "post"){
  print $_POST&#91;"comment"&#93;;
}
?>

printの行だけでもいいんですが、後の事を考えてif文で「modeがpostの時だけ表示する」という処理にしておきます。
returnではなくprint(またはecho)であることに注意してください。

このレスポンス(printの部分)はRequestのonSuccess()イベントの引数に返されるので、index.htmlで以下のように

onSuccess: function(txt) {
	 $("pastlog").set('html', txt);
}

引数txtをset(“html”)またはset(“text”)でdiv#pastlogにセットすれば、
Step3で表示されなかった送信内容が表示されるようになります。

上記ソースを保存して実行してみてください。Step2と同じ結果になればOK。

Step5.投稿日時を付け加えて整形

前のステップの段階で既にデータを受け取るところまで出来てるので、

if($_POST["mode"] == "post"){
  print $_POST["comment"];
}

この$_POST[“comment”]の中身をファイルに書き込めばいいわけです。
値があるときだけ実行するようにしたいので、sample.phpのif文に条件を追加して空送信では無効になるようにしときます。

if($_POST["mode"] == "post" && $_POST["comment"] != "")

保存するデータが送信された値だけではちょっと寂しいので、送信日時も付け足すことにします。
date関数とtime関数についてはマニュアルとか見てください。

sample.php

if($_POST["mode"] == "post" && $_POST["comment"] != ""){
 $savedata = $_POST["comment"].",".date("Y/m/d H:i:s",time());
 print $savedata;
}

保存されるときに送信された内容と送信日時をカンマで区切るようにしています。
この時点で実行したときに、保存される形式がそのまま出力されたらOK。
ああああ,2009/03/10 01:31:20

Step6.送信されたデータの保存

保存はファイルシステム関数の組み合わせなんですが、説明面倒なのでサンプルの保存関数をそのままコピペしてください。
簡単に流れをコメントで書いてあります。

まずsample.phpの先頭に以下の定数を追加

define("FILE","data.txt");//保存先のファイル名

次に保存関数。場所は上でも下でもどこでもいいです。

sample.php

//保存
function new_save($data)
{
	//ファイルサイズをチェックして0でなければ内容を保存します
	if(filesize(FILE) != "0"){
		$contents = file(FILE);//配列形式で読み込む
	}
	$fp = fopen(FILE, "w");//ファイルオープン
	fwrite($fp, $data);//送信されたデータの書き込み
	if(is_array($contents)){
		for($i=0;$i < count($contents) ;$i++){
			fwrite($fp, $contents&#91;$i&#93;);//ログの書き込み
		}
	}
	fclose($fp);//ファイルクローズ
	return true;
}
&#91;/php&#93;
この関数は引数で渡された文字列をファイルに書き込むものです。
文字列は前のステップで作ってますので、関数の実行はprintの行の下になります。

<strong>sample.php</strong>
[php]
if($_POST["mode"] == "post" && $_POST["comment"] != ""){
 $savedata = $_POST["comment"].",".date("Y/m/d H:i:s",time());
 print $savedata;
 new_save($savedata."\n");
}

"\n"は改行コードです。これが無いと全部一行になってしまうので必須。

適当になんか送信して、data.txtに保存されていたらOK。

Step7. エフェクトをつけて表示する

今のところ表示されるのがただの文字列なので、Fxでエフェクトを付けていかにもAjaxしてますな感じにする。
クリックイベント内にあるRequestインスタンスのonSuccess()内を変更します。

まず、返ってきたデータをカンマで分割。

var data = txt.split(",");

変数dataは配列になり、data[0]には送信したテキスト、data[1]に送信日時が格納されます。

エフェクトはフェードインだけなので、ショートカットメソッドfade()で直接エレメントに追加して、初期を非表示状態にしときます。
ログを入れる要素はまあ段落でもリストでも何でもいいんですが、とりあえずpタグにして日時はspanに入れることにしました。
要素はnew Element()で作成します。

var element = new Element("p",{html:data[0]+"<span>["+data[1]+"]</span>"}).fade("hide").inject("pastlog","top");
element.fade("in");

inject()でdiv#pastlogの先頭に追加したあと、fade(“in”)する。

実行してフェードインして表示されればOK。

ここまでの動作の流れをまとめると次のようになります。

  1. button#submitをクリックする
  2. input#commentの値を取得する
  3. Requestクラスのインスタンスを作成する
  4. オプションで指定されたURLへデータを送信する
  5. 送信されたデータを受け取る(PHP)
  6. 送信日時を追加する(PHP)
  7. 送信データに日時を付け加えたデータを返す(PHP)
  8. 返された結果を出力
  9. ファイルに保存する(PHP)

Step8. ログを取得する

ここまでの段階だと過去ログが見れないので
ページを表示したりリロードした時にもログを表示するようにします。

新しいRequestクラスのインスタンスをwindow.addEvent(‘domready’)直下に追加します。
クリックイベントの前後どこでもいいです。

index.html

new Request({
	url:"sample.php",
	method:"get",
	data:"mode=load",
	onSuccess: function(txt) {
		$("pastlog").set('html',txt);
	},
    onFailure: function() {
       $("pastlog").set('html', 'エラーが発生しました');
    }
}).send();

methodはまあどっちでもいいんですが、GETにしときます。

PHPにログを取得する関数とif文を追加します。
これもまた説明が面倒なのでサンプルをコピペしてみてください。
まずはロードの関数。場所はどこでもいいです。

sample.php

//ロード
function get_data(){
	$logdata = file(FILE);
	print trim(implode("\t",$logdata));
}

file()は配列形式でファイルを読み込む関数です。
タブで配列をくっつけた後、文字列前後の改行コードを取り除くためにtrim関数を通して返します。

上記の関数をコピペしたら、実行するif文を追加します。
dataでmode=loadを渡しているので、if文の条件は次のようになります。

if($_GET["mode"] == "load"){
	get_data();
}

リロードしてずらーっと文字列が出ればOK。

Step9. ログのスタイリング

文字列じゃアレなので、送信したデータを表示した時みたいにタグで整形することにします。
手順はStep7と大体同じです。

onSuccess()で実行される関数のソースを変更します。
まずくっつけた文字列(タブ)で分割して配列に戻す。

var log = txt.split("\t");

変数logには保存されているログの行が配列形式で格納されます。

これをeach()で処理する。

log.each(function(item,i){
	var data = item.split(",");
	new Element("p",{html:data[0]+"<span>"+data[1]+"</span>"}).inject("pastlog");
});

カンマで分割したログをpタグにいれた後、inject()でdiv#pastlogに追加していく。

まとめると次のようになります。

new Request({
	url:"sample.php",
	method:"get",
	data:"mode=load",
	onSuccess: function(txt) {
		var log = txt.split("\t");
		log.each(function(item,i){
			var data = item.split(",");
			new Element("p",{html:data[0]+"<span>"+data[1]+"</span>"}).inject("pastlog");
		});
		},
    onFailure: function() {
       $("pastlog").set('html', 'エラーが発生しました');
    }
}).send();

Step10. ソースのまとめ

javascriptとphpの全文を以下に載せます。

index.php

window.addEvent('domready', function(){
	
	new Request({
		url:"sample.php",
		method:"get",
		data:"mode=load",
		onSuccess: function(txt) {
			var log = txt.split("\t");
			log.each(function(item,i){
				var data = item.split(",");
				new Element("p",{html:data[0]+"<span>"+data[1]+"</span>"}).inject("pastlog");
			});
			},
	    onFailure: function() {
	       $("pastlog").set('html', 'エラーが発生しました');
	    }
	}).send();

	$("submit").addEvent("click",function(e){
		e.stop();
		var comment = $("comment").value;
		new Request({
			url:"sample.php",
	      	method: 'post',
			data:{"mode":"post","comment":comment},
			onRequest:function(){
				$("comment").value ="";
			},
			onSuccess: function(txt) {
				
				var data = txt.split(",");
				var element = new Element("p",{html:data[0]+"<span>"+data[1]+"</span>"}).fade("hide").inject("pastlog","top");
				element.fade("in");

			},
	        onFailure: function() {
	           $("pastlog").set('html', 'エラーが発生しました');
	        }
  		}).send();
	});
});

sample.php

define(“FILE”,”data.txt”);

if($_POST[“mode”] == “post” && $_POST[“comment”] != “”){
$savedata = $_POST[“comment”].”,”.date(“Y/m/d H:i:s”,time());
print $savedata;
new_save($savedata.”\n”);
}

if($_GET[“mode”]==”load”){
get_data();
}
//ロード
function get_data(){
$logdata = file(FILE);
print trim(implode(“\t”,$logdata));
}
//保存
function new_save($data)
{
//ファイルサイズをチェックして0でなければ内容を保存します
if(filesize(FILE) != “0”){
$contents = file(FILE);//配列形式で読み込む
}
$fp = fopen(FILE, “w”);//ファイルオープン
fwrite($fp, $data);//送信されたデータの書き込み

if(is_array($contents)){
for($i=0;$i Demo »
ダウンロード:[download#51#nohits]

なんとなくTwitterに似てますよね。
ローディングや完了メッセージとか付け足したら、似たような掲示板が作れると思います。
サンプル過ぎて実用には耐えないので、もうちょっと本格的にしたいなーという場合は
SlimBBSのPHPファイルを使うといいかもしれません。

モバイルバージョンを終了