The following is a guest post by Keith Knittel. Keith used a tutorial on this site to build his own customized file directory. I was like, hey, that oughta be a better-explained tutorial on this site. So here we are.
You likely know that if there is an “index.html” file in a directory on a server, it’s like to serve that file if the URL matches that directory. Like:
httpdocs
- my_folder
- index.html
- cool_mountain.jpg
So if you went to:
http://thatwebsite.com/my_folder/
It would render `index.html`. But what if `index.html` (or the like) was missing? You can configure that behavior. You can configure it to deny access to that directory. Or you can allow it and have it spit out a browseable file directory (sort of like FTP).
That can be useful. Just upload files and they immediately appear, no code changes. But a bit boring.

They all look the same: an unstyled, sortable list. To build a directory that looks a little better, we’re going to use:
- sortable.js
- a line of code in our HTAccess
- a little bit of PHP
- and of course, some CSS
We’ll also use an easy way to “hide” certain files in our directory to keep them from showing up in our final file list. For context, here is a demo.
Preflight Check
First we’ll make sure the server is configured to show hidden files. We’ll be using file names like `.index.php` (Note the “.” at the start of the file name). An operating system-specific Google search will likely find you an answer. We’ll be using hidden files to make this work, so we’ll need to be able to see them to work with them. Having them be hidden means they ultimately won’t show up in the directory listing, which is generally preferable.
.htaccess
In our `.htaccess file`, we would could use Options +Indexes
to display a directory, but we want to use a hidden index file so we can build our own page. We’ll use this instead to define the exact file we want to be responsible for displaying the file directory:
DirectoryIndex .index.php
It would be a good idea to add error redirects, but for the sake of this quick tutorial we’ll only add a 404. Aside: You can add any page in your directory in place of “.index.php” or “.404-error.php” and it will load that page. Neat.
ErrorDocument 404 .404-error.php
.index.php
Our `.index.php` file links up some assets. For instance, a script and a stylesheet. Even a favicon, if you’d like. All these files will start with a `.` so they don’t show up in the directory listing. Stuff in the head will be like:
<link rel="shortcut icon" href=".favicon.ico">
<link rel="stylesheet" href=".style.css">
<script src=".sorttable.js"></script>
A <table>
element is a fair choice for a list of files and metadata, so we’ll go for that. That’s what sortable.js is for, anyway. Sortable is such an easy library to use, we just have the class of sortable
on the table and it works. And here’s the basic PHP that reads all the files, loops through them, and outputs what is needed:
<table class="sortable">
<thead>
<tr>
<th>Filename</th>
<th>Type</th>
<th>Size <small>(bytes)</small></th>
<th>Date Modified</th>
</tr>
</thead>
<tbody>
<?php
// Opens directory
$myDirectory=opendir(".");
// Gets each entry
while($entryName=readdir($myDirectory)) {
$dirArray[]=$entryName;
}
// Finds extensions of files
function findexts($filename) {
$filename=strtolower($filename);
$exts=split("[/\\.]", $filename);
$n=count($exts)-1;
$exts=$exts[$n];
return $exts;
}
// Closes directory
closedir($myDirectory);
// Counts elements in array
$indexCount=count($dirArray);
// Sorts files
sort($dirArray);
// Loops through the array of files
for($index=0; $index < $indexCount; $index++) {
// Gets File Names
$name=$dirArray[$index];
$namehref=$dirArray[$index];
// Gets Extensions
$extn=findexts($dirArray[$index]);
// Gets file size
$size=number_format(filesize($dirArray[$index]));
// Gets Date Modified Data
$modtime=date("M j Y g:i A", filemtime($dirArray[$index]));
$timekey=date("YmdHis", filemtime($dirArray[$index]));
// Print 'em
print("
<tr class='$class'>
<td><a href='./$namehref'>$name</a></td>
<td><a href='./$namehref'>$extn</a></td>
<td><a href='./$namehref'>$size</a></td>
<td sorttable_customkey='$timekey'><a href='./$namehref'>$modtime</a></td>
</tr>");
}
?>
</tbody>
</table>
This is a simplified version. There is a more robust one here that cleans up file extensions, directories, hidden files, and more.
CSS
To style our directory, we can do whatever we like in our (hidden) `.style.css`. We could apply custom fancy icons like:
/* images */
table tr td:first-of-type a[href$=".jpg"],
table tr td:first-of-type a[href$=".png"],
table tr td:first-of-type a[href$=".gif"],
table tr td:first-of-type a[href$=".svg"],
table tr td:first-of-type a[href$=".jpeg"] {
background-image: url(./.images/image.png);
}
You can do any styling you like! There is a collection of table designs over on CodePen.
The End
The beauty of this setup is it’s really easy to upload non-sensitive files and share them as fast as you can refresh the page and send a link. If for some reason you wish to revert to the default unstyled directory, you can simply go to the htaccess file and replace DirectoryIndex .index.php
with Options +Indexes
and your back to the default directory.
Demo
There is a demo right here on this site. I also used this exact technique to build a fun image directory of my own: asecrettoeverybody.com

I made a similar work, a styled/customizable PHP directory indexer in just one single file, maybe a little more minimal/elegant-orientated :) https://github.com/lorenzos/Minixed
Nice work, Lorenzo. I like the single file configuration. Am using it.
I use a project called Apaxy.
http://adamwhitcroft.com/apaxy/
It do basically the same thing, but it doesn’t use PHP.
Great job, Keith!
I’ll second that.
A good tutorial. For everyone interesteed: H5AI is another alternative (very feature complete) out-of-the-box solution.
In the
findexts()
function,split
is deprecated in PHP as of 5.3. You could actually just rewrite the whole function to use PHP’s nativepathinfo
like:I don’t get it, maybe I didn’t understand, if the idea is only to show the files list, why dont put a index.php that show a list directory in that folder so you dont need to mess with .htacces nor hidden files and if you want you can make the index.php to ignore itself in the files list. Or did I miss something here?
I think one of the advantages this way is recursive. You don’t have to put an index.php file in each directory, it just keeps working all the way down.
That’s cute but this is just incredible: https://larsjung.de/h5ai/
demo: http://cdn.brod.io/rpi8188eu/
“They all look the same: an unstyled, sortable list.”
Until, since we’re already assuming Apache httpd, we’re using
IndexOptions FancyIndexing
to make the listing sortable, andHeaderName
to insert any html we want in the output.This one suits my simple needs.
https://gist.github.com/permanentinc/460d6c590660d4eb4374
Too bad you need PHP for this.
An interesting tutorial would be how to style and add JS to the existing apache-generated listing (lots of interesting points to deal with on those pages :)).
Mine : http://www.etiennepouvreau.fr/public/
Just a simple php page with inline css and base64 webfont.
Thank you for the tutorial !
Pretty cool, Zelda rules! I did something of the sorts, but I’ve aimed for something more clean designed.
You guys can check on GitHub: https://github.com/edmundojr/localhost
Why use PHP for this? If you’re using Apache, just style the built-in version. You can use the HeaderName directive to add HTML above the listing, ReadmeName to add HTML below the listing, and IndexStyleSheet to change the CSS file used.
Your PHP code has several bad practices in it, such as using the old readdir function (newer code should be using DirectoryIteratoror RecursiveDirectoryIterator)