ディレクトリーツリー
ディレクトリの中身を、Explorer のツリーような形で表示させたいのだ!なんとか簡単に出来る仕組みを考えてみました。
配列によるディレクトリのモデル
先ずはデータ型。デレクトリの下にはファイル又はデレクトリがありその中にまたファイルやデレクトリが存在します。このように入れ子になった関係を保持できるデータ型といえば『配列』です。配列を使えばディレクトリーツリーを表現できそうです。
配列は、「添え字 => 値」 という関係になっていて、値にはどんなデータでも入れることが出来ます。ディレクトリ内部を獲得しようとした時、「ディレクトリ」であれば添え字に「ディレクトリ名」を格納し、値には下位の内容を配列で格納します。「ファイル」ならば添え字に「ファイル名」を格納し、値に「パス」を格納することにします。
ディレクトリ内を配列に格納した時のイメージです。
Array (
'edithead.php' => './sumple/edithead.php',
'conf.txt' => './sumple/conf.txt',
'file.html' => './sumple/file.html',
'strings.html' => './sumple/strings.html',
'data' => Array (
'template' => Array (
'file.data' => './sumple/data/template/file.data',
'file.data.bak' => './sumple/data/template/file.data.bak',
'readme.txt' => './sumple/data/template/readme.txt',
),
'log.txt' => './sumple/data/log.txt',
),
)
ディレクトリの中を調べる
ディレクトリの中を獲得するには、opendir() でディレクトリのハンドルを獲得後、readdir() で次々とファイル名を読み出し、読み終えたところで、closedir() でディレクトリハンドルを閉じるという流れになります。
ディレクトリ内のファイルを獲得する処理例
if ($handle = opendir($dir)) { // ディレクトリハンドルを獲得
while (false !== ($file = readdir($handle))) { // ファイル名獲得
echo $file; // 何らかの処理(ここで配列に格納すれば出来そう)
}
closedir($handle); // ディレクトリハンドルを閉じる
}
ディレクトリの場合は、再び同じ処理の繰り返し(再帰関数)
処理例の echo $file; の部分を $dirtree[] = $file; とすれば、ファイル名の一覧を配列に格納できます。これがディレクトリだった場合はどうでしょう。再びディレクトリハンドルを獲得して、readdir() で読み出し、ディレクトリハンドルを閉じるという、まったく同じ処理の繰り返しを行なうことになります。ディレクトリ階層が何段になっているか事前に知ることは出来ませんので、この処理を何回繰り返せばいいのやら困ります。こんな時は「再帰関数」を使用します。
再帰関数とは、関数内で自分自身を呼び出す関数のことです。入れ子になったデータに対して同じ処理を施すのに適した手法です。
ディレクトリ内を走査し、ファイルならばファイル名を配列に格納し、ディレクトリだった場合には自分自身を呼び出して戻り値を配列に格納するようにします。
ディレクトリ内のファイル一覧を配列で獲得する関数
<?php
/*
function getdirtree ( $dir )
--------------------------------------------------
指定したディレクトリ以下のファイル一覧を獲得する。
--------------------------------------------------
引 数:ディレクトリを示す文字列
戻り値:ファイル一覧を格納した配列
*/
function getdirtree ( $path )
{
if (!is_dir($path)) { // ディレクトリでなければ false を返す
return false;
}
$dir = array(); // 戻り値用の配列
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
if ('.' == $file || '..' == $file) {
// 自分自身と上位階層のディレクトリを除外
continue;
}
if (is_dir($path.'/'.$file)) {
// ディレクトリならば自分自身を呼び出し
$dir[$file] = getdirtree($path.'/'.$file);
} elseif (is_file($path.'/'.$file)) {
// ファイルならばパスを格納
$dir[$file] = $path.'/'.$file;
}
}
closedir($handle);
}
return $dir;
}
?>
ツリーを表示させる
上記の、getdirtree() で得た配列を print_r() で表示させただけでは、まだはじめのデータモデル図と同じでかっこ良いツリーではありません。もっとツリーらしく表示させるためには、ツリーらしく表示する処理も必要です。
配列の値を順番に走査し、値が配列ならば再び配列内を走査する・・・?!これって「再帰」と思った方は正解!この処理も関数化し、再帰呼出を使ってオートマティックに済ませましょう。
ツリーのインデントやアンカータグなどの処理を盛り込んだ関数が下のコードです。
配列の中身をツリー状に表示する関数
<?php
/*
function showdirtree ( $tree )
--------------------------------------------------
配列の中身をツリー状に表示する。
--------------------------------------------------
引 数:$tree = 表示させる配列
戻り値:true=成功、false=失敗
*/
function showdirtree ( $tree )
{
if (!is_array($tree)) { // 配列でなければ false を返す
return false;
}
static $count = 0; // インデントの階層の深さ
$indent = ($count) ? str_repeat(' ', $count) : '';
$count++;
foreach ($tree as $key => $value) {
if (is_array($value)) {
// 配列の場合ディレクトリ名を表示し再帰呼出
print($indent. '+ '. $key. "<br>\n");
showdirtree($value);
} elseif (preg_match('/\.(html|txt|php)$/i', $value)) {
// HTMLとTEXTとPHPのみアンカーをつけてファイル名を表示
print($indent. '- <a href="'. $value. '" target="view">'. $key. "</a><br />\n");
}
}
$count--;
return true;
}
?>
上記関数を使ったサンプルコード
<?php // 上記関数部省略 // function getdirtree() // function showdirtree() $dir = './sample'; $tree = getdirtree($dir); ?> <html> <head> <meta http-equiv="content-type" content="text/html;charset=Shift_JIS"> <title>ディレクトリ表示:tree.php</title> </head> <body> <p>ディレクトリ:<?php echo $dir; ?></p> <?php showdirtree($tree); ?> <hr> <p>こちらは print_r による表示</p> <pre><?php print_r($tree); ?></pre> </body> </html>
フレームを使ってます。左が tree.php の出力結果です。
このスクリプトは、ディレクトリ内のファイルの獲得手順や配列の使い方・再帰関数の手法を紹介するためのサンプルです。使い方を間違えればサーバ内のファイル構成を誰もが知ることが出来てしまいますのでこのまま使わないでくでください。
