2008年4月14日月曜日

PHPでAJAXをやってみる

PEARにHTML_AJAXというパッケージがあるが、それを使わずにいわゆるAJAXをやってみるということです。
とりあえずということで、基本的なことだけかもしれませんが、いちおう動いているコードを書いてみます。PHPとかいっている割には、大半がJavascriptな内容かもしれません。

AJAXとはなにか?ということは、世の偉い人があちこちで解説されているので、ここでは説明しませんが、基本的には「非同期でサーバーから情報を取る」というのと、 「サーバーがXMLドキュメントを送る」、「XMLドキュメントをJavascriptで処理をしてブラウザに表示」という3つであると思って書きます。

非同期でサーバーから読み出す

まずは、Javascriptの「XMLHttpRequest」のオブジェクトを作成して、それを使ってデーターを読み込むという手順になります。XMLHttpRequestを作成するコードは以下のような感じ(どこかのコードのパクリかもしれないが…)。

function createHttpRequest(){
 if(window.ActiveXObject){
  try {
   return new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
   try {
    return new ActiveXObject("Microsoft.XMLHTTP");
   } catch (e2) {
                return null;
            }
         }
    } else if(window.XMLHttpRequest){
        return new XMLHttpRequest();
    } else {
  return null;
    }
}

という関数を定義して、var request = createHttpRequest();とすれば、XHTMLRequestのオブジェクトが得られる。

次にデータを取得するわけだが、クラス化されたJavascriptで処理をするために以下のような関数を作ってみた。

function sendRequest(obj, callback, url) {
 var request = createHttpRequest();
 if (request == null) return false;
 request.onreadystatechange = function() {
  callback.call(obj, request);
 }
 request.open('GET', url, true);
 request.send(null);
 return true;
}

データーの受信は、非同期で行われるため、コールバック関数を用意して、読み込みが完了したら、コールバック関数が呼び出されて、そこからデーターを読み取るという処理になる。
この関数を使うためのクラスは、以下のようになる。

function MyClass(){
 this.callback = function(request) {
  if (request.readyState == 4) {
   if (request.status == 200) {
    var xmlDoc = request.responseXML;
    //このxmlDocから情報を読み取る
   }
  }
 }
}

ちなみにrequest.readyStateというのは、1から4までが設定されて呼び出されるのだが、4というのが完了したということになる。あと、request.statusを確認するも必須で、これはHTTPのリザルトコードになっている。すなわち、200で正常に通信したということであり、そのほかはなんだかのエラーということになる(エラー処理はここでは省略…)。このクラスと先ほどの関数を使ったコードは以下の通り。

var url;//データーを持ってくるためのURL
var obj = new MyClass();
sendRequest(obj, obj.callback, url);

この関数は、MyClassの中で定義してしまってもよいかと思います。そのときは、objはthisになります。

サーバー側の処理

サーバーから送るデーターはXMLになっていれば、Javascriptで値が取り出せるということになるわけだが、例えばa=1とt=testというデーターを送りたいのであれば、

<?xml version="1.0"?>
<result>
 <a>1</a>
 <t>test</t>
</result>

というXMLを送ればよいということになる。ちなみにコード系がUTF-8以外ならば、versionのあとにcharsetを設定しなければならないだろう。
要するに、このようなXMLを返すのであれば、なんでもいいのであるが、PHPでなんだかの処理をして返すということにした場合、PHPのソースのどこかで、HTTPヘッダを設定しなければならず、header("Content-Type: text/xml");と書けばよいということになる(application/xmlというタイプもあるが、使い分けはよくわかってません…)。

XMLドキュメントをPHPでどう生成するかということになるわけだが、ごりごりと自分で上記のようなXMLを出力するコードを書いて、送るのでもよい。そのへんは規模にもよるとは思うが、PHPに組み込まれている関数を使ったほうがよい場合もあると思う。
ここでは、本来の使い方ではないかもしれないが、「DOM XML 関数」というPHPの組み込み関数を使うことにする。具体的には「DOMDocument」というクラスのオブジェクトを生成して、そこにXMLのデーターをセットして、saveXML();というメソッドでXMLの文字列を得る。それをechoして、クライアントに送るという手順になる。
先ほどのXMLと同じ内容を出力するコードは以下のようになる。

header("Content-Type: text/xml");
$doc = new DOMDocument();
$resultElement = $doc->createElement('result');
$doc->appendChild(resultElement);
$aElement = $doc->createElement('a');
$aElement->appendChild($doc->createTextNode('1'));
$resultElement->appendChild($aElement);
$tElement = $doc->createElement('t');
$tElement->appendChild($doc->createTextNode('test'));
$resultElement->appendChild($tElement);
echo $doc->saveXML();

Javascriptでデーターを得る

まず、いきなりいい訳だが…、以下の手順はちゃんと動いているものの正しいかどうかはあまり自信がない。ネットでいろいろ調べてみたものの、いくつかのコードが見受けられた。
とりあえずは、取得したXMLドキュメントに同じタグ(エレメント)が存在しない(上記の例では<a>1</a>という'a'タグがひとつしかない)というのを前提とする。

以下のようなJavascriptの関数を用意してみた。

function getElement(parent, name) {
 return parent.getElementsByTagName(name).item(0);
}
function getNodeValue(element) {
 return element.childNodes.item(0).nodeValue;
}

この関数を使って、先ほどのXMLドキュメントのオブジェクト(xmlDocという変数)から"a"という値を得るコードは以下の通り。

var aElement = getElement(xmlDoc, 'a');
var a = getNodeValue(aElement);

あとは、これらの得られたデーターをブラウザ上に表示するわけだが、これはいわゆるDOMといわれている仕組みを使って表示するのだが、ここではさらに長くなりそうなので割愛させていただく。

というわけで、とりあえずながらも、PHPを使ってAJAXをやってみた。あとは、いわゆる配列のようなデーターをJavascriptのXMLDocumentから取得できるようにする必要があると思う。これについては、いずれ書きたいと思う。

0 件のコメント: