Search code examples
phparraysdirectory-tree

Recursively adding all sub directories and files from a directory into an array


I have a function that will obtain all directories and files from a given directory, however the way it obtains them makes it a little more complicated to work with:

function getFileLists($dir, $recursive=FALSE) {
    // retrieve an array of all the directories and files in a certain directory
    $retval = [];
    if (substr($dir, -1) !== "/") {
        $dir .= "/";
    }
    $d = @dir($dir) or die("unable to open {$dir} for reading, permissions?");
    while(FALSE !== ($entry = $d->read())) {
        if ($entry{0} === ".") { continue; }
        if (is_dir("{$dir}{$entry}")) {
            $retval[] = [
                'name' => "{$dir}{$entry}",
                'last_modified' => filemtime("{$dir}{$entry}")
            ];
            if($recursive && is_readable("{$dir}{$entry}/")) {
                $retval = array_merge($retval, getFileLists("{$dir}{$entry}/", TRUE));
            }
        } elseif (is_readable("{$dir}{$entry}")) {
            $retval[] = [
                'name' => "{$dir}{$entry}",
                'last_modified' => filemtime("{$dir}{$entry}")
            ];
        }
    }
    $d->close();
    return $retval;
}

When you run this on a given directory it will produce the following results:

array(14) {
  [0]=>
  array(2) {
    ["name"]=>
    string(15) "./kb_data/admin"
    ["last_modified"]=>
    int(1543591247)
  }
  [1]=>
  array(2) {
    ["name"]=>
    string(28) "./kb_data/admin/testfile.txt"
    ["last_modified"]=>
    int(1543591238)
  }
  ...
}

Which is great but this makes it pretty difficult to work with seeing as how I want to display this directory as a tree. What I'm actually wanting to do is the produce something along the lines of the following:

array(14) {
  [0]=>
    array(3) {
    ["name"]=>
    string(16) "./kb_data/shared"
    ["last_modified"]=>
    int(1543591258)
    ["files"] => array(#) {
        ["name"]=>
        string(29) "./kb_data/shared/testfile.txt"
        ["last_modified"]=>
        int(1543591238)
     }
  }
  ...
}

As you can see, I want each file thats in the directory to be inside of the directory. How can I go about refactoring this function in order to obtain the output I desire?


Solution

  • What about (SPL) Directory Iterator

    function getFileLists($dir) {
        $rec = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::SELF_FIRST);
        $ar = array();
        foreach ($rec as $splFileInfo) {
           $path = $splFileInfo->isDir()
                 ? array($splFileInfo->getFilename() => array())
                 : array($splFileInfo->getFilename());
    
           for ($depth = $rec->getDepth() - 1; $depth >= 0; $depth--) {
               $path = array($rec->getSubIterator($depth)->current()->getFilename() => $path);
           }
           $ar = array_merge_recursive($ar, $path);
        }
        return $ar;
    }
    print "<pre>";
    print_r(getFileLists("/Library/WebServer/Documents/am-web/"));