skip to content

PHP: Directory Listing

A common request is to be able to produce a list of some or all of the files in a directory - similar to the default index page provided by most web servers, but with more control over the content and formatting.

Another goal might be 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.

PHP 5 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.

If you are using PHP 5 or higher check out our new article on Directory Listing using SPL classes for a much neater approach.

Single Directory Listing

To 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):

<?PHP 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:

<?PHP // examples for scanning the current directory $dirlist = getFileList("."); $dirlist = getFileList("./"); // examples for scanning a directory called images $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:

<?PHP $dirlist = getFileList("images"); echo "<pre>",print_r($dirlist),"</pre>"; /* sample output Array ( [0] => Array ( [name] => images/background0.jpg [type] => image/jpeg [size] => 86920 [lastmod] => 1077461701 ) [1] => ... ) */ ?>

Example 2:

<?PHP $dirlist = getFileList("./images"); echo "<pre>",print_r($dirlist),"</pre>"; /* sample output Array ( [0] => Array ( [name] => ./images/background0.jpg [type] => image/jpeg [size] => 86920 [lastmod] => 1077461701 ) [1] => ... ) */ ?>

If you want the output sorted by one or more fields, you should read the article on Sorting Arrays of Arrays or try out one of our DHTML Sorting Algorithms using JavaScript.

We also have an article on Directory Listing using SPL classes (DirectoryIterator and SplFileInfo) which introduces many new options for filtering and sorting the output.

Displaying File List in HTML

To output the results to an HTML page we just loop through the returned array:

<?PHP // output file list in HTML TABLE format echo "<table border=\"1\">\n"; echo "<thead>\n"; echo "<tr><th>Name</th><th>Type</th><th>Size</th><th>Last Modified</th></tr>\n"; echo "</thead>\n"; echo "<tbody>\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 "</tbody>\n"; echo "</table>\n\n"; ?>

This code can be easily modified to: make the output a list instead of a table; make the file names actual links; replace the names with icons based on file type or extension; etc.

Display PNG images in a TABLE:

For example, to display only PNG files, just add a condition to the output loop:

<?PHP // output file list as HTML table echo "<table border=\"1\">\n"; echo "<thead>\n"; echo "<tr><th></th><th>Name</th><th>Type</th><th>Size</th><th>Last Modified</th></tr>\n"; echo "</thead>\n"; echo "<tbody>\n"; foreach($dirlist as $file) { if(!preg_match("/\.png$/", $file['name'])) continue; echo "<tr>\n"; echo "<td><img src=\"{$file['name']}\" width=\"64\"></td>\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 "</tbody>\n"; echo "</table>\n\n"; ?>

Here you can view the complete source code for this example.

This will have the effect of skipping all files whose name does not end with .png. You could also apply conditions based on the file type, size, or last modified timestamp.

List PDF files with links:

One last example, listing only PDF files and having the file name link to the file:

<table border="1"> <thead> <tr><th>Name</th><th>Type</th><th>Size</th><th>Last Modified</th></tr> </thead> <tbody> <?PHP // output file list as table rows foreach($dirlist as $file) { if($file['type'] != 'application/pdf') continue; echo "<tr>\n"; echo "<td><a href=\"{$file['name']}\">",basename($file['name']),"</a></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"; } ?> </tbody> </table>

Here you can view the complete source code for this example.

If you want to display, for example, a thumbnail as a link to a larger image, or even a video, just give the two files the same name and in the script above use str_replace or similar function to modify either the link href or the link contents. See our article on listing images for examples.

Using the SPL DirectoryIterator and FilterIterator classes we can now specify a pattern to match when accessing the file list so only matching files are returned. More on that here.

Recursive Directory Listing

Now 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.

<?PHP // 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) { $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.

<?PHP // 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 a recursive listing.

Limited Depth Recursion

This 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.

<?PHP // 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) { $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:

<?PHP // 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 unusable because of parameter bloat.

References

< PHP


Send Feedback

Use this form to send a message to The Art of Web:


used only for us to reply, and to display your gravatar.

CAPTCHA refresh

<- copy the digits from the image into this box

press Esc or click outside this box to close

Load Feedback Form

User Comments and Notes

29 July, 2014

Would it be possible to share a working example of files with this? This looks like it is exactly what i have been trying to do but cannot seem to get it to work...

10 June, 2012

Very nice this function. So here, a small correction for doing it with php5.3
$path_info = pathinfo("$dir$entry");
$retval[] = array(
"name" => "$dir$entry",
"type" => $path_info['extension'],
"size" => filesize("$dir$entry"),
"lastmod" => filemtime("$dir$entry")

11 May, 2012

I suppose this:

"type" => mime_content_type("$dir$entry"),

can be changed to this:

"type" => substr("$dir$entry",-3),

25 February, 2012

is the sorting of the list completely random? seems like alot of work to make it sort by either date or alphabetical order. (im a php rookie )

It varies depending on the OS, but you can sort the files how you want using PHP. See Sorting Arrays of Arrays.

26 September, 2011

@Jason Anderson

Change
mime_content_type(
to
filetype(
and it will work just fine!

10 February, 2011

I am running PHP 5.3.0 and I get an error trying to use the mime_content_type() function. It mentions that it is an undefined function. The PHP manual says that it is deprecated and to use finfo instead. So, when I try that I get an error saying that the class 'finfo' could not be found. Any ideas?

8 February, 2011

Excellent! Just what I was looking for - and with clickable links. Being newish to PHP I would welcome some downloadable examples. For now its copy, paste, edit and hope for the best!!

20 October, 2010

I am looking for a way to parse my directories and then list all the pdf's as clickable links. Do you think this is possible?

I've added an example now for display PDF files as clickable links

19 November, 2009

Just found your script for directory-listing. Seems pretty powerful.
Yet: Some samples, of how to use it would be pretty helpfule, at least for beginners.
How to list just the directories, or just the JPG-files etc.

Thanks for your feedback. I've added some more examples

top