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

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


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

   いままでのスタイルのPHPアプリケーションの実装例

アプリケーションの概要

 これから一般的なファイルマネージャを実装する。このファイルマネージャはまずは一般的なPHPスクリプトと同等のものだが、後にAjax版にすることを意識した実装にしておく。

 ファイルマネージャは下記の機能を持つ。見てのとおり非常にシンプルなものである。

  • 2ペイン形式
  • リスト形式のフォルダビュー(ツリー形式ではない)
  • リスト形式のエントリビュー
  • ファイルのダウンロード(フォルダのまとめダウンロードはない)

実装スタイル

 実装は目的ごとに複数のファイルに分ける。

index.php 実際に通常アクセスされるスクリプト
config.php 設定関連
common.php 各機能の関数群
download.php ファイルのダウンロードを行う
entries.css
folders.css
各種スタイルシート

 基本的な設定はすべてconfig.phpに、基本的な機能はcommon.phpに実装している。それではそれぞれのファイルの要点を説明していく。

index.php

 非常に簡単なものである。common.phpを読み込み、HTTPヘッダーでContent-Typeを出力し(文字化け軽減のため)common.phpで用意した関数群からフォルダ一覧、エントリ一覧のHTMLを取得し、最後にHTML全体を出力しているだけだ。この処理に特に難しいポイントはないだろう。

 1つだけ特徴があるのは、スタイルシートで画面全体がスクロールしないようにしていることだ。CSSで画面を2分割し、表示位置や幅と高さを固定し、中に実際のコンテンツを出力している。

 ただしブラウザによっていわゆるCSSファイルだけでは実現できないものもあるので、今回はJavaScriptで描画エリアの大きさを取得しプロパティを設定することで実現している。

<script language="JavaScript" type="text/javascript">
<!--
  clientWidth = document.documentElement.clientWidth;
  clientHeight = document.documentElement.clientHeight;
  folders_list = document.getElementById( "folders-list");
  entries_list = document.getElementById( "entries-list");
  folders_list.style.height = ( parseInt( clientHeight) - 40) + 'px';
  entries_list.style.width = ( parseInt( clientWidth) - 190) + 'px';
  entries_list.style.height = ( parseInt( clientHeight) - 80) + 'px';
//-->
</script>
リスト3 レイアウトを調整するJavaScript

config.php

 これも非常に簡単なものである。要は設定をPHPの定数として定義していっているだけである。ここでは下記の定数を定義している。

BASE_DIR ファイルシステムとしてのファイルマネージャが存在する基準ディレクトリ
BASE_URL URLとしてのファイルマネージャが存在する基準URL
BASE_DATA_DIR ファイルマネージャが扱うファイル、ディレクトリの基準ディレクトリ
DATE_TIME_FORMAT エントリの更新日時を出力するフォーマット
CHARSET
HTML出力時に使用する文字エンコード(ファイル名など)

common.php

 ここではFSとVFSという概念を仮に導入することにした。FSはいわゆるファイルシステムで、実際にシステムで使用されているファイルパスを指す。

 VFSはファイルマネージャ上での仮想ファイルシステムで、FSへの変換はconfig.phpで指定されたBASE_DATA_DIRを補完したものをFSとする。

string normalizationPathName( string $vfs_path_name)

 引数のVFSファイルパスを正規化する。ウェブアプリケーションの場合、特に不当なパラメータを渡される可能性が高く、渡された値をそのまま使用すると例えばシステムパスワードファイルを不当入手されたりする場合がある。

 この関数はその対策として、指定のファイルパスがconfig.phpのBASE_DATA_DIR内に必ず収まるファイルかどうかを調べ、その結果を返す。

array generateEntriesInfo( string $vfs_target_dir)

 指定のVFSパスをディレクトリと見なし、内包されるエントリ(ファイルやディレクトリなど)の一覧を配列で取得する。

string showFoldersList( string $entries_infos)

 generateEntriesInfo()で取得したエントリ一覧を基にフォルダ一覧のHTMLを生成し、返す。 この関数はクライアントへのHTMLの出力を直接行わない。

string showEntriesList( string $entries_infos)

 generateEntriesInfo()で取得したエントリ一覧を基にエントリ一覧のHTMLを生成し、返す。

  ントリはエントリ名やサイズと最終変更日時を含んだテーブルで、ディレクトリなら移動用のリンクが、それ以外はダウンロード用のリンクが生成されている。この関数もクライアントへのHTMLの出力を直接行わない。

download.php

  ファイルをダウンロードするだけのスクリプトである。ファイルが存在するディレクトリをパラメータdirとして、ファイルをentryとしてGETで受け取る。それ以外は特に変わった処理は行われていない。

<?php
require_once "common.php";

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

$full_path = $dir.DIRECTORY_SEPARATOR.$entry;
$vfs_target_path_name = normalizationPathName( $dir.DIRECTORY_SEPARATOR.$entry);
$target_file_name = basename( $vfs_target_path_name);
$enc_target_file_name = urlencode( $target_file_name);

header( "Content-Type: application/octet-stream");
header( "Content-Disposition: attachment; filename=$enc_target_file_name");
readfile( BASE_DATA_DIR.$vfs_target_path_name);
?>
リスト4 ファイルをダウンロードする実装 
header( "Content-Disposition: attachment; filename=$enc_target_file_name");の行は2行になっているが実際は1行

entries.css
folders.css

 ただの各種スタイルシートである。筆者の好みで作られている部分もあるが、難しいことは一切行っていないと思う。

2/3

 INDEX

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


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

注目のテーマ

HTML5+UX 記事ランキング

本日 月間