10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

みんな大好きディレクトリ一覧をソートしつつ再帰的に表示する実装

Last updated at Posted at 2014-05-23

ディレクトリ一覧(再帰的)を表示する

Symfony2になら便利なファイル操作関数が用意されてるが、プレーンなPHPにはそんなの無いのでつくってみた

見ため的にはWindowsのCMDにあるTREEコマンドのようになる

方法

おやくその再帰処理をするだけな簡単な実装

  1. パスを指定してファイル一覧を取得
  2. 1件毎にディレクトリか調べてディレクトリなら1へ
  3. ファイル一覧からディレクトリが無くなればソートを行う
  4. すべてのファイルを取得するまで1-3を繰り返す
注意

このコードは.(ドット)から始まるファイル名は表示しません。
.(ドット)から始まるファイルを表示させる為には以下のように「GlobIterator」の部分を
「RecursiveDirectoryIterator」クラスを使用するとフィルタされなくなります。
この部分についてはコメント頂いた RecursiveTreeIteratorでtreeコマンドを実装 を参考にさせていただきました。

サンプルコード
//    $targetPath = realpath($path) . DIRECTORY_SEPARATOR . '*';
//
//    //ファイル一覧を生成する
//    $glob = new GlobIterator($targetPath, FilesystemIterator::CURRENT_AS_FILEINFO);
//    $tree = array();
//    foreach ($glob as $item) {

//上記の部分を以下に書き換え

    //ファイル一覧を生成する
    $allFileIterator = new RecursiveDirectoryIterator($path);
    $tree = array();
    foreach ($allFileIterator as $item) {

クロージャを使用してますが投稿者の趣味です。
クラス/メソッドで実装したほうがスマートな気がします。

<?php

header('Content-Type: text/plain');

$path = dirname(__FILE__);


$directorySearcher = function ($path) use(&$directorySearcher) {
    if (is_file($path)) {
        //Pathがファイルを指していたらファイルだけのリストを返す
        return array('leaf' => new SplFileInfo($path));
    }
    if (is_dir($path) === false) {
        //ディレクトリ以外なら処理終了
        return false;
    }
    $targetPath = realpath($path) . DIRECTORY_SEPARATOR . '*';

    //ファイル一覧を生成する
    $glob = new GlobIterator($targetPath, FilesystemIterator::CURRENT_AS_FILEINFO);
    $tree = array();
    foreach ($glob as $item) {
        //ファイルシステム操作関数のSplFileInfoクラスを生成
        $tree[$item->getRealPath()] = array('leaf' => $item->getFileInfo());
        if ($item->isDir()) {
            //ディレクトリなら再帰処理
            $tree[$item->getRealPath()]['node'] = $directorySearcher($item->getRealPath());
        }
    }
    //末端のノードに達したらノード一覧をソートする
    //ソートのルールは動的に変更可能以下はディレクトリファイルの順且つ、ファイルネームの昇順
    foreach ($tree as $node => $leaf) {
        $sortIndex1st[$node] = $leaf['leaf']->isDir();
        $sortIndex2nd[$node] = $leaf['leaf']->getFilename();
    }
    if (count($tree) > 0) {
        array_multisort($sortIndex1st, SORT_DESC, $sortIndex2nd, SORT_ASC, $tree);
    }
    return $tree;
};

//実装例
$printScript = function($dir, $head = '')use(&$printScript) {
    foreach ($dir as $leafItems) {
        $leaf = $leafItems['leaf'];
        echo $head, ($leaf->isDir()) ? '├' : '│';
        echo $leaf->getFilename();
        if ($leaf->isFile()) {
            echo ':', floor($leaf->getSize() / 1024), '.', ($leaf->getSize() % 1024), 'kb';
        }
        echo PHP_EOL;
        if ($leaf->isDir()) {
            $printScript($leafItems['node'], $head . '│');
        }
    }
};

//実行
$directorys = $directorySearcher($path);
if ($directorys !== false) {
    $printScript($directorys);
}


表示例

試しにPEARのテストディレクトリを表示させてみる

├Console_Table
│├tests
│││assoziative_arrays.phpt:0.538kb
│││colors.phpt:0.673kb
│││filters.phpt:0.717kb
│││multibyte.phpt:0.511kb
│││multiline.phpt:1.579kb
│││no_header.phpt:0.364kb
│││no_rows.phpt:0.441kb
│││rules.phpt:1.502kb
├Mail
│├tests
│││13659.phpt:0.651kb
│││9137.phpt:0.1001kb
│││9137_2.phpt:1.202kb
│││rfc822.phpt:2.802kb
│││smtp_error.phpt:0.720kb
│││validateQuotedString.php:0.640kb
├Net_SMTP
│├tests
│││auth.phpt:0.859kb
│││basic.phpt:0.785kb
│││config.php.dist:0.488kb
│││quotedata.phpt:1.771kb
├Structures_Graph
│├tests
││├testCase
││││BasicGraph.php:8.905kb
│││AllTests.php:3.268kb
├XML_Util
│├tests
│││AllTests.php:3.560kb
│││testBasic_apiVersion.phpt:0.449kb
│││testBasic_attributesToString.phpt:3.559kb
│││testBasic_collapseEmptyTags.phpt:1.771kb
│││testBasic_createCDataSection.phpt:0.494kb
│││testBasic_createComment.phpt:0.471kb
│││testBasic_createEndElement.phpt:0.696kb
│││testBasic_createStartElement.phpt:3.701kb
│││testBasic_createTag.phpt:5.796kb
│││testBasic_createTagFromArray.phpt:9.89kb
│││testBasic_getDocTypeDeclaration.phpt:1.492kb
│││testBasic_getXmlDeclaration.phpt:1.143kb
│││testBasic_isValidName.phpt:1.386kb
│││testBasic_raiseError.phpt:0.502kb
│││testBasic_replaceEntities.phpt:3.176kb
│││testBasic_reverseEntities.phpt:3.161kb
│││testBasic_splitQualifiedName.phpt:0.983kb
│││testBug_4950.phpt:0.675kb
│││testBug_5392.phpt:1.73kb

10
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?