2
\$\begingroup\$

I have to deploy this code that will list all the directories, sub directories and files in it starting from the root. The code works but I am not sure if this is the correct way to list. It should not fail, though.

Also, in despite not allowing directories with the name . and .., they get printed. Why is that?

<?php

# Snippet that lists all the directories,sub directories and files under that directory
# recursive function

function directory_f_lister($root) {
    $dir_list = scandir($root);
    for($var=0;$var<count($dir_list);$var++) {
        if(is_readable($root.$dir_list[$var])) {
            if(is_dir($root.$dir_list[$var])) {
                if($dir_list[$var] === "." || $dir_list[$var] === "..") continue;
                echo "<h3>Name of directory $dir_list[$var]</h3>";
                echo "<br />";
                $dh = opendir($root.$dir_list[$var]);
                while(($name = readdir($dh)) !== false) {
                    if(is_dir($root.$dir_list[$var].$name)) {
                        if($dir_list[$var] === "." || $dir_list[$var] === "..") continue;
                        echo "Name of directory : <strong> $name </strong>";
                        echo "<br />";
                        directory_f_lister($root.$dir_list[$var].$name);
                    }else {
                        echo $name;
                        echo "<br/>";
                    }
                }
            }
        }
    }
}

directory_f_lister(DIRECTORY_SEPARATOR);
#end
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

well . and .. are not directories, thats are navigationpoints of directories, . means go inside a root directory, .. means go one folder back,

you might noticed this already in includes like include ../../../foo/bar.php

also instead of scandir and readdir php has classes for this purpose DirectoryIterator or FileSystemIterator

And if you wish to create reusable methods, dont do output there, instead return an array of folders/files something like

$directories = scanDirectories($rootDirectory); //create output array
foreach($directories as $directory){
    echo $directory.'<br/>';  
} 

this allowes you to modify the output without editing the sourcecode, you could also wrap the output within a function e.g. viewDirectories and reuse it on different places.

here is a small Example

    ini_set('html_errors', 'On');

function scanDirectory($path) {
    $path = realpath($path);

     return  new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);

}

foreach(scanDirectory('./') as $name=> $object){

    echo $name.'<br/>';
}

About your question:

$root.$dir_list[$var].$name //this is your directory name

but youre checking if this name is . and ..

$dir_list[$var]

so its never becomes true

\$\endgroup\$
1
\$\begingroup\$
  1. If you invert your if condition and continue with next loop entry then you can reduce your level of nesting.
  2. You will currently miss all files in the first $root (due do the outer is_dir condition).
  3. You should be able move the recursion further to the top. The shorted algorithm for recursively listing directories goes like this (pseudo code):

    func list(root)
        print "Directory: " + root
        foreach (entry in contentof(root))
            if (entry is directory)
                list(entry)
            else
                print "File: " + entry
    

    In your code that could look something like this:

    function directory_f_lister($root)
    {
         echo "<h3>Name of directory: $root</h3>";
         echo "<br>";
         for (scandir($root) as $current)
         {
             $currentFullPath = $root.$current;
             if (!is_readable($currentFullPath) || $current == "." || $current == "..")
                 continue;
             if (is_dir($currentFullPath))
             {
                 list($currentFullPath);
             }
             else
             {
                 echo $current;
                 echo "<br>";
             }
         }
     }
    
  4. Your approach intermingles the iteration of the structure (filesystem) with the actions of what to do for each item (printing). A better way would be to simply use the DirectoryIterator to iterate over the filesystem and print each item.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.