PHP: Directory ListingA common request is to be able to produce a list of files in a directory - similar to the default index page provided by most webservers but with more control over the content and formatting. In other cases the aim is to take some action on the files using PHP. In either case the first step is to query the file system to return a list of directories and files. The functions presented below provide the means to extract the file names and other properties from a single directory, or to explore subdirectories recursively. Note: PHP5 introduces the scandir function which will "List files and directories inside the specified path" but won't recurse or provide additional information about the listed files. Single Directory ListingTo get started, here is a simple function that returns a list of files, directories and their properties from a single directory (more advanced versions of this function can be found further down the page): function getFileList($dir)
{
# array to hold return value
$retval = array();
# add trailing slash if missing
if(substr($dir, -1) != "/") $dir .= "/";
# open pointer to directory and read list of files
$d = @dir($dir) or die("getFileList: Failed opening directory $dir for reading");
while(false !== ($entry = $d->read())) {
# skip hidden files
if($entry[0] == ".") continue;
if(is_dir("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry/",
"type" => filetype("$dir$entry"),
"size" => 0,
"lastmod" => filemtime("$dir$entry")
);
} elseif(is_readable("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry",
"type" => mime_content_type("$dir$entry"),
"size" => filesize("$dir$entry"),
"lastmod" => filemtime("$dir$entry")
);
}
}
$d->close();
return $retval;
}
You can use this function as follows: $dirlist = getFileList(".");
$dirlist = getFileList("./");
$dirlist = getFileList("images");
$dirlist = getFileList("images/");
$dirlist = getFileList("./images");
$dirlist = getFileList("./images/");
...
The return value is an associative array of files including the filepath, type, size and last modified date, except when a file is actually a directory, in that case the string "(dir)" appears instead of the filesize. The filenames take the same stem as the function call: Example 1: getFileList("images");
Array
(
[0] => Array
(
[name] => images/background0.jpg
[type] => image/jpeg
[size] => 86920
[lastmod] => 1077461701
)
...
)
Example 2: getFileList("./images");
Array
(
[0] => Array
(
[name] => ./images/background0.jpg
[type] => image/jpeg
[size] => 86920
[lastmod] => 1077461701
)
...
)
If you want the output sorted by one or more fields, you should read the article on PHP: Sorting Arrays of Arrays or try out one of our DHTML Sorting Algorithms. Finally, to output the results to an HTML page: echo "<table>\n";
echo "<tr><th>Name</th><th>Type</th><th>Size</th><th>Last Mod.</th></tr>\n";
foreach($dirlist as $file) {
echo "<tr>\n";
echo "<td>{$file['name']}</td>\n";
echo "<td>{$file['type']}</td>\n";
echo "<td>{$file['size']}</td>\n";
echo "<td>" . date("r", $file['lastmod']) . "</td>\n";
echo "</tr>\n";
}
echo "</table>\n\n";
You can of course easily modify this to make the output a list; make the file names actual links; replace the names with icons based on file type or extension and so on. Recursive Directory ListingNow that we've got this far, it's only a minor change to extend the function in order to recursively list any subdirectories. By adding a second parameter to the function we also retain the previous functionality of listing a single directory. # Original PHP code by Chirp Internet: www.chirp.com.au
# Please acknowledge use of this code by including this header.
function getFileList($dir, $recurse=false)
{
# array to hold return value
$retval = array();
# add trailing slash if missing
if(substr($dir, -1) != "/") $dir .= "/";
# open pointer to directory and read list of files
$d = @dir($dir) or die("getFileList: Failed opening directory $dir for reading");
while(false !== ($entry = $d->read())) {
# skip hidden files
if($entry[0] == ".") continue;
if(is_dir("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry/",
"type" => filetype("$dir$entry"),
"size" => 0,
"lastmod" => filemtime("$dir$entry")
);
if($recurse && is_readable("$dir$entry/")) {
$retval = array_merge($retval, getFileList("$dir$entry/", true));
}
} elseif(is_readable("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry",
"type" => mime_content_type("$dir$entry"),
"size" => filesize("$dir$entry"),
"lastmod" => filemtime("$dir$entry")
);
}
}
$d->close();
return $retval;
}
To make use of the new functionality, you need to pass a value of true (or 1) as the second parameter. # single directory
$dirlist = getFileList("./");
# include subdirectories
$dirlist = getFileList("./", true);
Before recursing the script first checks whether sub-directories are readable, and otherwise moves on to the next item so as to avoid permission errors. As before, the return value is an array of associative arrays. In fact the only change is that you have the additional option of opting for a recursive listing. Limited Depth RecursionThis final example adds another feature - the ability to specify how deep you want the recursion to go. The previous code would continue to explore directories until it ran out of places to go. With this script you can tell it to not go deeper than a fixed number of levels in the file system. # Original PHP code by Chirp Internet: www.chirp.com.au
# Please acknowledge use of this code by including this header.
function getFileList($dir, $recurse=false, $depth=false)
{
# array to hold return value
$retval = array();
# add trailing slash if missing
if(substr($dir, -1) != "/") $dir .= "/";
# open pointer to directory and read list of files
$d = @dir($dir) or die("getFileList: Failed opening directory $dir for reading");
while(false !== ($entry = $d->read())) {
# skip hidden files
if($entry[0] == ".") continue;
if(is_dir("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry/",
"type" => filetype("$dir$entry"),
"size" => 0,
"lastmod" => filemtime("$dir$entry")
);
if($recurse && is_readable("$dir$entry/")) {
if($depth === false) {
$retval = array_merge($retval, getFileList("$dir$entry/", true));
} elseif($depth > 0) {
$retval = array_merge($retval, getFileList("$dir$entry/", true, $depth-1));
}
}
} elseif(is_readable("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry",
"type" => mime_content_type("$dir$entry"),
"size" => filesize("$dir$entry"),
"lastmod" => filemtime("$dir$entry")
);
}
}
$d->close();
return $retval;
}
As before we've added a single new parameter and a few lines of code. The default value of the depth parameter, if not defined in the function call, is set to false. This ensures that all previous features remain and that any legacy code won't break when the function is changed. In other words, we can now call the getFileList function with one, two or three parameters: # single directory
$dirlist = getFileList("./");
# include all subdirectories recursively
$dirlist = getFileList("./", true);
# include just one or two levels of subdirectories
$dirlist = getFileList("./", true, 1);
$dirlist = getFileList("./", true, 2);
This is a good example of how a function can evolve over time without becoming unmanageable. Too often you see functions that were once useful become almost unusable because of all the patches and hacks applied to them. Related Articles
References |
|
|
© Copyright 2009 Chirp Internet
- Page Last Modified: 16 April 2009
|
|