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\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.