Tutorial Display Styled Directory Contents
Servers can be configured to show the contents of a directory that doesn't have an index file to render. The result is usually less than visually spectacular:
Lackluster default in Chrome More better, View DemoWe can take control of this ourselves by replicating this functionality with PHP.
Make an index file (.index.php, starting with the dot, really) which reads the files in the directory and outputs them into a table
Make an .htaccess file that serves that file as the index
Have the index file load in CSS and other resources that are also prefixed with a dot (hidden)
The following PHP reads the directory of files and displays a styled table of their name, file type, and file size. It also applies a class name in which to apply icons for the different major file types (see CSS).
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Directory Contents</title>
<link rel="stylesheet" href=".style.css">
<script src=".sorttable.js"></script>
</head>
<body>
<div id="container">
<h1>Directory Contents</h1>
<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++) {
// Allows ./?hidden to show hidden files
if($_SERVER['QUERY_STRING']=="hidden")
{$hide="";
$ahref="./";
$atext="Hide";}
else
{$hide=".";
$ahref="./?hidden";
$atext="Show";}
if(substr("$dirArray[$index]", 0, 1) != $hide) {
// 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]));
// Prettifies File Types, add more to suit your needs.
switch ($extn){
case "png": $extn="PNG Image"; break;
case "jpg": $extn="JPEG Image"; break;
case "svg": $extn="SVG Image"; break;
case "gif": $extn="GIF Image"; break;
case "ico": $extn="Windows Icon"; break;
case "txt": $extn="Text File"; break;
case "log": $extn="Log File"; break;
case "htm": $extn="HTML File"; break;
case "php": $extn="PHP Script"; break;
case "js": $extn="Javascript"; break;
case "css": $extn="Stylesheet"; break;
case "pdf": $extn="PDF Document"; break;
case "zip": $extn="ZIP Archive"; break;
case "bak": $extn="Backup File"; break;
default: $extn=strtoupper($extn)." File"; break;
}
// Separates directories
if(is_dir($dirArray[$index])) {
$extn="<Directory>";
$size="<Directory>";
$class="dir";
} else {
$class="file";
}
// Cleans up . and .. directories
if($name=="."){$name=". (Current Directory)"; $extn="<System Dir>";}
if($name==".."){$name=".. (Parent Directory)"; $extn="<System Dir>";}
// 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>
<h2><?php print("<a href='$ahref'>$atext hidden files</a>"); ?></h2>
</div>
</body>
</html>
The resources loaded in that index file are the top-in table sorter script sortable.js and a .style.css file. (Remember, prefacing the files with a dot makes the invisible in most operating systems, and also won't show up in your directory of files (good)). Here's that CSS:
* {
padding:0;
margin:0;
}
body {
color: #333;
font: 14px Sans-Serif;
padding: 50px;
background: #eee;
}
h1 {
text-align: center;
padding: 20px 0 12px 0;
margin: 0;
}
h2 {
font-size: 16px;
text-align: center;
padding: 0 0 12px 0;
}
#container {
box-shadow: 0 5px 10px -5px rgba(0,0,0,0.5);
position: relative;
background: white;
}
table {
background-color: #F3F3F3;
border-collapse: collapse;
width: 100%;
margin: 15px 0;
}
th {
background-color: #FE4902;
color: #FFF;
cursor: pointer;
padding: 5px 10px;
}
th small {
font-size: 9px;
}
td, th {
text-align: left;
}
a {
text-decoration: none;
}
td a {
color: #663300;
display: block;
padding: 5px 10px;
}
th a {
padding-left: 0
}
td:first-of-type a {
background: url(./.images/file.png) no-repeat 10px 50%;
padding-left: 35px;
}
th:first-of-type {
padding-left: 35px;
}
td:not(:first-of-type) a {
background-image: none !important;
}
tr:nth-of-type(odd) {
background-color: #E6E6E6;
}
tr:hover td {
background-color:#CACACA;
}
tr:hover td a {
color: #000;
}
/* icons for file types (icons by famfamfam) */
/* 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);}
/* zips */
table tr td:first-of-type a[href$=".zip"]
{background-image: url(./.images/zip.png);}
/* css */
table tr td:first-of-type a[href$=".css"]
{background-image: url(./.images/css.png);}
/* docs */
table tr td:first-of-type a[href$=".doc"],
table tr td:first-of-type a[href$=".docx"],
table tr td:first-of-type a[href$=".ppt"],
table tr td:first-of-type a[href$=".pptx"],
table tr td:first-of-type a[href$=".pps"],
table tr td:first-of-type a[href$=".ppsx"],
table tr td:first-of-type a[href$=".xls"],
table tr td:first-of-type a[href$=".xlsx"]
{background-image: url(./.images/office.png)}
/* videos */
table tr td:first-of-type a[href$=".avi"],
table tr td:first-of-type a[href$=".wmv"],
table tr td:first-of-type a[href$=".mp4"],
table tr td:first-of-type a[href$=".mov"],
table tr td:first-of-type a[href$=".m4a"]
{background-image: url(./.images/video.png);}
/* audio */
table tr td:first-of-type a[href$=".mp3"],
table tr td:first-of-type a[href$=".ogg"],
table tr td:first-of-type a[href$=".aac"],
table tr td:first-of-type a[href$=".wma"]
{background-image: url(./.images/audio.png);}
/* web pages */
table tr td:first-of-type a[href$=".html"],
table tr td:first-of-type a[href$=".htm"],
table tr td:first-of-type a[href$=".xml"]
{background-image: url(./.images/xml.png);}
table tr td:first-of-type a[href$=".php"]
{background-image: url(./.images/php.png);}
table tr td:first-of-type a[href$=".js"]
{background-image: url(./.images/script.png);}
/* directories */
table tr.dir td:first-of-type a
{background-image: url(./.images/folder.png);}
REMEMBER: The .zip file might appear to be empty, but it's not. The files are all prefaced with a dot. View them in a file editor which shows you "hidden" files.
Special thanks to Cliff White.