連載:AjaxとPHPでリッチクライアント(2)

Ajaxを使ったファイルマネージャをPHPで作ろう


上鍵 忠志
日本PHPユーザ会
2006/4/29

   Ajaxを用いた実装例

 それではこれをAjaxにしてみよう。

どこをAjaxにするか

 今回はAjaxの通信の様子を理解してもらうことが目的なので、なるべく簡単なことしかしないようにする。

 フォルダを移動すると、左のフォルダペインと右のエントリペインが書き換えられるが、この部分をAjaxでリロードなしに行われるようにする。

 また、Ajax部分ではディレクトリ名を動的に渡し、HTMLを取得し、単にそれを出力するようにする。Ajaxではフォルダ一覧とエントリ一覧を個別にサーバ側にリクエストし、処理を行う。今回はAjax部分の名前の由来の1つのXMLは使用しない。

 サーバからXMLで値を返し、クライアントでXMLの解析をする場合、クライアント側の負荷が大きくなる。

 多くの場合サーバから取得したデータは最終的にHTMLで出力するだけなので、単にHTMLを返してもらい、出力する方がコストは低くなるだろう。

改変部分

index.phpからserver.phpへの実装の移動

 いままではindex.phpでフォルダ一覧やエントリ一覧のHTMLを取得していたが、それをこれからはAjaxで生成することにする。よってその処理をindex.phpから削除し、同等のものを新たにserver.phpというスクリプトを作成し、そちらに移動した(ajax-version/index.phpserver.php)。

 サーバへのリクエストはフォルダ一覧とエントリ一覧の2種類あるので、GETパラメータとしてmodeを追加した。その結果、例えばこういうURLでserver.phpにはアクセスする。

http://www.example.com/file-manager/server.php?dir=%2Fpath%2Fto%2Fentry%2F&mode=folderlist

 実際の実装は下記のとおり。ちなみに2つのajaxのリクエストが非同期に行われ、順次処理されていくことを体感しやすくするために2行目にsleep()を入れている。遅いことが気になる場合はこれを削除しておくといいだろう。

<?php
sleep(1); // わざと1秒待つ。不必要なら削除する

require_once "common.php";

$mode = empty( $_GET[ "mode"]) == TRUE? "": $_GET[ "mode"];
$dir = empty( $_GET[ "dir"]) == TRUE? "": $_GET[ "dir"];

$vfs_target_dir = normalizationPathName( $dir.DIRECTORY_SEPARATOR);
$base_path_html = htmlspecialchars( $vfs_target_dir, ENT_QUOTES);

$entries_infos = generateEntriesInfo( $vfs_target_dir);

switch ( $mode) {
case "folderlist":
    echo showFoldersList( $entries_infos);
    break;
case "entrylist":
    echo showEntriesList( $entries_infos);
    break;
}
?>
リスト5 Ajaxを受けるサーバ側の実装

common.php

 common.phpは基本的に変わりはない。変わったところはいままで要素Aで普通に属性hrefを使ったリンクを作成していたが、JavaScriptでフォルダ移動をするため、属性onClickに対応した点だけだろう。

 なお、onClickで実行されるJavaScriptは関数loadDirectory()として実装し、XMLHttpRequestの準備をした後にサーバサイドにリクエストをする実装になっている。

ajax.js

 Ajaxの部分をajax.jsというJavaScriptのファイルでまとめた。これは最初に簡単に説明したAjaxの実装とあまり変わりはない。

 特徴でいうと、XMLHttpRequestオブジェクトを2つ使用し、1つ目をフォルダ一覧用(変数名ajax)、2つ目をエントリ一覧用(変数名ajax2)に割り当てた。

 ファイルマネージャはAjaxとして下記の流れで処理を行う。

  • まずクリックされるとJavaScriptの関数loadDirectory()が実行される
  • loadDirectory()から1つ目のXMLHttpRequestでサーバサイドにリクエストする
  • 1つ目のXMLHttpRequestの結果が返ってきたらフォルダ一覧関連のHTMLに反映し、すぐに2つ目のXMLHttpRequestを実行する
  • 2つ目のXMLHttpRequestの結果が返ってきたらエントリ一覧関連のHTMLに反映してAjaxとしての処理はすべて終了する

 今回注意すべき点はInternet Explorerはテーブル(要素table)のプロパティinnerHTMLを変更できないということだ。そのため、要素tableの中だけではなく、それ自体もサーバサイドで生成するようにした。

 なおloadDirectory()はAjaxの雰囲気を出すためにリクエスト前に「Loading...」という文字列を出力するようにしてみた。

index.php

 index.phpは先ほどserver.phpにいくつかの処理を移動したこととajax.jsを読み込む処理を追加した。そしてこのままでは画面全体は表示されてもフォルダ一覧もエントリ一覧も表示されないので、最後にJavaScriptでloadDirectory()を実行している。

   注意点

 今回未実装の部分も含め気を付けるべきことを書いておく。

ファイルマネージャの制限

マルチバイト文字のファイル名
 ファイルマネージャではマルチバイト文字のファイル名、いわゆる漢字や平仮名を含んだファイル名は正しく扱えないかもしれない。

 また、マルチバイト文字のファイル名に対応するには表示を文字エンコードUTF-8で行っているため、ファイル名の文字エンコード変換などを行う必要があるかもしれない。

・2GB超えのファイル
 PHPの制限で2GBを超えたファイルは扱えない。

・キャッシュ制御を行っていない
 今回キャッシュ制御を行っていないため、ファイルマネージャとは無関係なところでファイルの更新など行われた場合、画面表示やダウンロード時にそれが反映されない場合がある。

   ウェブメールやRSSリーダー、FTPクライアント、画像管理の
 基礎完成

 今回は一般的なPHPアプリケーションを作成し、それを簡単にAjaxにしてみた。

 そもそもAjaxへ対応することを意識した実装になっているため、一般的にはもっと難しい部分が出てくるだろう。

 しかしこの2つを対比することで、AjaxがJavaScriptを用いてどうやってサーバサイドと通信を行うか、それを画面に反映させるにはどうしたらいいかという最低限理解すべきところを説明できたと思う。

 実はこのファイルマネージャは多くのアプリケーションの基礎になるといえる。例えばウェブメールやRSSリーダー、FTPクライアント、画像管理アプリケーションなど「カテゴリ」と「内包物」のセットを扱うアプリケーションだ。

   次回は一歩発展したPHPアプリに拡張予定

 次回はこのファイルマネージャをベースにより高度な実装を行ってみようと思う。

 世間では(@ITでも)prototype.jsなどのJavaScriptライブラリを用いた高度なJavaScriptの実装の紹介をしている。

 しかしそれは「JavaScriptの使い方やPHPの使い方」ではなく「prototype.jsなどのライブラリの使い方」の説明になってしまう。

 このコーナーはあくまでPHPを前提にしているので、基本的にはそういったライブラリを使わないようにしたいと思う(当然題材によっては使う場合もあるだろう)。

   Ajaxを用いたオープンソースのPHPアプリケーション

 PHPとAjaxを使ったアプリケーションの紹介のリクエストもあったので、ここではオマケ的にAjaxを用いたオープンソースのPHPアプリケーションを紹介しよう。

phpFreeChat

 phpFreeChatはAjaxを用いたメッセンジャーライクなウェブチャットアプリケーションだ。これはPHPのAjaxフレームワークであるxajaxを使用して実装されている。

画面1 PHP FREE CHAT - Free PHP + AJAX chat server

xajax PHP Class Library - The easiest way to develop asynchronous Ajax applications with PHP
http://www.xajaxproject.org/

 phpFreeChatはチャットシステム自体はライブラリ化されているため、既存のコンテンツに組み込みやすくなっている。下記は付属のREADME.enにあるPHPスクリプト部分だ。

<?php

require_once "src/phpfreechat.class.php"; // adjust to your own path
$params["serverid"] = md5(__FILE__); // used to identify the chat
$chat = new phpFreeChat($params);

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title>phpFreeChat demo</title>
    <?php $chat->printJavascript(); ?>
    <?php $chat->printStyle(); ?>
  </head>
  <body>
    <?php $chat->printChat(); ?>
  </body>
</html>
リスト6 phpFreeChatを実行するサンプル

 このサンプルを見ればおおよその処理は予想できるだろう。下記は関連部分だけを抜き出したものである。

<?php
require_once "src/phpfreechat.class.php"; // phpFreeChatのシステムの読み込み
$params["serverid"] = md5(__FILE__); // ID生成
$chat = new phpFreeChat($params); // システムオブジェクトのインスタンス
?>
    <?php $chat->printJavascript(); ?> // JavaScript部分の生成
    <?php $chat->printStyle(); ?> // スタイルシートの生成
    <?php $chat->printChat(); ?> // チャットを表示する部分のHTMLの生成
リスト7 PHPの実装部分(hellolib.lzx)

 これが分かれば後は自分のコンテンツにphpFreeChatをコピーし、設置したい部分に上記ロジックをコピーすればチャットを置くことができる。

 Ajaxの利点の1つに実行中にリロードが基本的に必要ないため、多くの場合既存コンテンツに新しい機能を容易に追加できることがある。

 phpFreeChat()の引数の$paramsは配列を渡す場合、連想キー「debug」を渡すことでデバッグ処理を追加することができるようだ。

 その他phpFreeChatConfigのインスタンスオブジェクトを渡すことでより柔軟な設定ができる。phpFreeChatConfigで設定できる項目はsrc/phpfreechatconfig.class.phpを参照するといいだろう。

3/3 次回もお楽しみに

 INDEX

Ajaxを使ったファイルマネージャをPHPで作ろう
  Page1<JavaScriptとPHPの通信>
JavaScriptでの実装例/XMLHttpRequestを扱うオブジェクトのインスタンス/サーバとの通信準備/状態監視関数の作成、登録/HTTPリクエストの送信/PHPでの実装例
  Page2<Ajaxを使わずにファイルマネージャを作ろう>
Ajaxを使わないでPHPファイルマネージャの概要と実装スタイル
  Page3<Ajaxを使ってファイルマネージャを作ろう>
どこをAjaxにするか/改変部分/注意点/ファイルマネージャの制限/Ajaxを用いたオープンソースのPHPアプリケーション/phpFreeChat/自前WebにphpFreeChatをコピーしてみよう


HTML5 + UX フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日 月間