名前を入れて送信ボタンを押してください。 名前は非同期にサーバに送られ,サーバからは挨拶と現在のUNIX時刻(1970年元旦からの秒数)が返されます。 ページ全体を読み直すわけではないので,たいへん高速です。
まずはこのページのソースをご覧ください(エンコーディングはUTF-8です)。headの中の
<script type="text/javascript"> // <![CDATA[ // ]]> </script>
の部分がJavaScriptのプログラムです。 ここでは,そのずっと下のformの部分から見ていきましょう。
<form action="#" onsubmit="doit();return false;"> <p><label for="user">お名前:</label><input type="text" name="user" id="user" /> <input type="submit" value="送信" /></p> </form> <div id="result"></div>
このformに書き込んで「送信」ボタンを押すと,onsubmit
で指定されている doit(); return false; が実行されます。
ここで return false; はブラウザの標準の動作(この場合formのsubmitボタンの動作)をさせないための常套手段です。
doit() の定義は次のようになっています(多少簡略化しましたが後で説明します)。
function doit() {
var req = new XMLHttpRequest();
if (req == null) {
document.getElementById("result").innerHTML = "<p>未対応ブラウザです。<\/p>";
} else {
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) {
document.getElementById("result").innerHTML = req.responseText;
}
};
var u = encodeURIComponent(document.getElementById("user").value);
req.open("POST", "ex1.php", true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send("user=" + u);
}
}
まず,新しい XMLHttpRequest
オブジェクト(サーバと非同期通信するための仕組み)を生成し,それを req
という変数に代入しています。
これに失敗すれば(req == null なら),<div id="result"></div>
の中に <p>未対応ブラウザです。</p>
というHTMLを書き込むだけで終わります。
失敗しなければ,req というオブジェクトの onreadystatechange
というプロパティ(JavaやC++の用語ではフィールド)に無名の関数を代入しています。
この関数はコールバック関数と呼ばれ,何かイベントが発生すると呼ばれます。
ここでは req というオブジェクトが作業を遂行するにつれ,その状態 req.readyState
が0→1→2→3→4と変化するのですが,その変化のたびに呼ばれる関数を定義しています。
作業が完遂されたなら req.readyState == 4
になりますが,そのときのHTTPステータスコード req.status
が200(OK)ならば,サーバから送られたテキスト req.responseText
を <div id="result"></div>
の中に表示します。
続いて,<input type="text" name="user" id="user" />
の値(つまりユーザが打ち込んだお名前)を取り出し,これをURLエンコード(アスキー以外の文字を %
に続く16進2桁に直すこと)して,それを変数 u に代入しています。
続いて,req.open で,POSTメソッドでサーバの ex1.php
を呼び出しています(最後の true は非同期呼出しを意味します)。
このPOSTメソッドでは Content-Type: application/x-www-form-urlencoded
というヘッダを使います。
最後に,user= に続けてさきほどのURLエンコードした値を送ります。
これで doit() 関数は終わりますが,コールバック関数が設定されていますので,上に述べたように,状態が変わればそちらのほうが呼び出されることになります。
ところで,上のプログラムは実は単純化されています。
XMLHttpRequest()
が定義されていないInternet Explorerのために,次のような関数を作って,場合分けしています。
function newRequest() {
var x = null;
if (window.XMLHttpRequest) { // Firefox, Opera, Safari, ...
x = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
x = new ActiveXObject("Msxml2.XMLHTTP"); // IE6
} catch (e) {
try {
x = new ActiveXObject("Microsoft.XMLHTTP"); // IE5
} catch (e) {
x = null;
}
}
}
return x;
}
実際の doit() ではこれを呼び出しています:
req = newRequest(); // var req = new XMLHttpRequest(); の代わり
サーバ側には,この ex1.html と同じディレクトリに次の ex1.php というファイルがはいっています:
<?php
header('Content-Type: text/html; charset=UTF-8');
if ($_POST['user']) {
echo '<p>', htmlspecialchars($_POST['user']), 'さんこんにちは。</p>';
}
echo '<p>だたいまのUNIX時刻は ', time(), ' 秒です。</p>';
?>
これは,POSTメソッドで受け取った user の値を htmlspecialchars()
で無害化(< を < に直すなど)してから挨拶に直して,現在のUNIX時刻(1970年元旦からの秒数)とともに送り返します。
この場合 if ($_POST['user']) は user=...
がセットされていて,なおかつ空文字列 "" でも "0"
でもないことを意味します。
もし 0 と打ち込まれたら空欄と判断されてしまいますので,厳密には if (isset($_POST['user']) && $_POST['user'] != '') とすべきかもしれません。
user=hoge&password=himitsu
のようにして複数の値を送ります。
値のエンコードにはJavaScriptの encodeURIComponent() 関数を使います。
encodeURI() では & や = がエンコードされません。setRequestHeader(...) をしないとブラウザによってはうまくいきません。htmlspecialchars()
を使うことがクロスサイトスクリプティング対策として必要です。charset=UTF-8
を付ければ化けないように思います。req.open
から req.send までの3行を次の2行にします:
req.open("GET", "ex1.php?user=" + u, true);
req.send(null);
innerHTML()
はW3CのDOM標準に含まれていませんが,IE4,Netscape 6以降,Mozilla,Safari等で使えます。
innerHTML() は document.write() とともにW3CのWCAGでは推奨されていません。
Client-side Scripting Techniques for WCAG 2.0
参照。
でもとっても便利。Last modified: 2007-07-30 12:39:14