<?php
//If you want this script to list all of the files in the directory it is in
//and all of the files from the folders underneath the folder it is in
//set recurse to yes. Otherwise, if you just want a list of files in this
//folder set recurse to no. Make sure only one option is set. Comment out (add
//// in front of) the one you don't want to use. Default is no.
$recurse = 'NO';
//$recurse = 'YES';
//Create a variable that referees to this file itself. That way it can be
//excluded from the directory listing.
$me = basename($_SERVER['PHP_SELF']);
//Create an excluded files array. Any filenames in the below array will not be
//shown in the directory listing. Use the pattern below to hide
// as many files as you like. These are case sensitive.
//NOTE: You can exclude folders as well. Just list their names without a
//trailing slash. If you hide a directory all files and folders underneath it
//will be hidden as well.
//LIMITATIONS/EXCLUDING THINGS IN FOLDERS: Things are excluded on a "filename"
//basis, not a "path/filename" basis. Meaning to exclude documents/resume.doc
//you add a line like this: $exclude[2] = "resume.doc";. However this means
//that school/english111/papers/resume.doc and /resume.doc would also be
////hidden. This same thing applies to folders as well. Also filenames and
//folders will both be blocked if one is blocked (ie: excluding "todo" willl
//block todo/ and todo).Basically this means if you want to do anything
//complicated you need all uniquely named folders and files. For small sites
//this should not be a problem.
$exclude[0] = "this_is_a_hidden_file";
$exclude[1] = "this_is_a_hidden_folder";
//^Hopefully nobody has files and folders named the above things :)
//Time to work with the _description.txt file. This file will allow you to have
//a description for each file in the directory listing. Here is how to use it:
// 1) create a _description.txt file in the same directory that this file is
// in. 2) chmod it at least 744. 3) type filename|description lines. 4)
// seperate each filename description pair by a new line. Make sure the
// filenames match the *exact* case of the files on your webhost. Make sure
// you use unix line breaks. In case you are wondering the "_" in the filename
// is just to make sure I don't stop anybody from listing a description.txt
// file they might have in a directory for some reason.
// Example:
// cat.jpg|A picture of my cute kitty.
// me.jpg|You know you want me.
//NOTE: You can add descriptions to folders as well. Just add their names to
//the _description.txt file without a trailing slash.
//LIMITATIONS/DESCRIBING THINGS IN FOLDERS: Things are described on a
//"filename" basis, not a "path/filename" basis. Meaning to describe the file
//documents/resume.doc you would add a line like this: "resume.doc|my resume"
//to _description.txt . However this means that
//school/english111/papers/resume.doc and /resume.doc would also have the same
//description. The same thing applies to folders as well. Also filenames and
//folders will both be described as the same if one is described (ie:
//describing "todo" will describe todo/ and todo).Basically this means if you
//want to do anything complicated you need all uniquely named folders and
//files. For small sites this should not be a problem.
//No "if" checking to see if file exists or if array is built successfully.
// Because we want all the code below to execute even if the description
// fails. That way you will always get at least a list of files. If
// _description.txt is not working right for you, you will not get any
// errors, you will just have to figure out the problem yourself.
//Read entire file in as an array.
$des_org_array = file("_description.txt");
//Search each "record/line" in the array and replace anything after "|" with
//nothingness. Create a new array with the results. So from the array that
//holds "cat.jpg|my cat." comes a new array array for just the filenames, ie
//cat.jpg.
$des_file_array = preg_replace ("/\|.*/", "", $des_org_array);
//The regular expression above leaves an extra space after the file names, ie
//"cat.jpg " we need to remove this for matching later. The function below
//will accomplish this. Taken from php.net/trim.
function trim_value(&$value)
{
$value = trim($value);
}
array_walk($des_file_array, 'trim_value');
//Search each "record/line" in the original array and replace anything before
//"|" with nothingness. Create a new array with the results. So from the array
//that holds "cat.jpg|my cat." comes a new array array for just the
//descriptions, ie my cat.
$des_des_array = preg_replace ("/.*\|/", "", $des_org_array);
//Now that we have the descriptions and filenames in their own arrays we need
//to make one array with all the data. The format will be key ==> value.
//filename ==> description.
// PHP 4 does not have a native array_combine
//function. So I lifted the below code from php.net's forum. Props to Ivo van
//Sandick.
function array_combine_emulated( $keys, $vals ) {
$keys = array_values( (array) $keys );
$vals = array_values( (array) $vals );
$n = max( count( $keys ), count( $vals ) );
$r = array();
for( $i=0; $i<$n; $i++ ) {
$r[ $keys[ $i ] ] = $vals[ $i ];
}
return $r;
}
//Now do the work. Combine the arrays.
$combined_array = array_combine_emulated($des_file_array, $des_des_array);
//We need to create an array for the file list itself. This is necessary
//because readdir does not allow you to do any sorting and shows all files and
//directories in a seemingly random order. We will populate this array later.
$filelist = array();
//Array work done.
//See if the current directory is readable. It must be to continue.
//If it is not readable complain.
if (is_readable("./")) {
//Before we start printing the file list we need to construct the page!
echo"
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
<html>
<head>";
//Get the current directory. Will use this for "Index of.." in the page
//title as well as other places.
$dirname = dirname($_SERVER["REQUEST_URI"]);
//External CSS
//Use hard coded CSS by default. Change to YES if you want external CSS, be
//sure to update external_css_file.
$use_external_css = 'NO';
//The external CSS file. This is the file that contains the CSS
//definitions. Best to keep it outside of the directory this script is in.
$external_css_file = "../style.css";
if ($use_external_css == 'YES')
{
//If using external CSS setup the 'head' section to use that file and don't
//have any hard coded CSS definitions.
echo"
<link rel=\"stylesheet\" href=\"$external_css_file\" />
<title>Index of $dirname </title>
</head>";
}
//Else. If you are not using an external CSS file. Don't let 'head' look for
//one and include the hard coded definitions.
elseif ($use_external_css == 'NO')
{
//CSS Definitions
echo"
<style type=\"text/css\">
body.phpdi {background-color: white;
color: black;
text-align: center}
h2.phpdi {text-align: center;
font-weight: bold;
background-color: white}
table.phpdi {border-width: thin thin thin thin;
border-spacing: 2px;
border-color: black black black black;
border-style: solid solid solid solid;
border-collapse: collapse;
text-align: left;
empty-cells: show;
background-color: white;
margin-left: auto;
margin-right: auto}
table.phpdi thead {}
table.phpdi tbody {}
table.phpdi tr {}
table.phpdi th {border-width: thin thin thin thin;
padding: 1px 1px 1px 1px;
border-style: solid solid solid solid;
border-color: black black black black;
background-color: white;
color: black;
font-size:16px;
text-align: center;
-moz-border-radius: 0px 0px 0px 0px}
table.phpdi td.phpdi-file {font-family: sans-serif;
border-width: thin thin thin thin;
padding: 1px 1px 1px 1px;
border-style: solid solid solid solid;
border-color: black black black black;
background-color: white;
color: black;
font-size:14px;
width: 100px;
-moz-border-radius: 0px 0px 0px 0px}
table.phpdi td.phpdi-dir {font-style: italic;
font-family: sans-serif;
border-width: thin thin thin thin;
padding: 1px 1px 1px 1px;
border-style: solid solid solid solid;
border-color: black black black black;
background-color: white;
color: black;
font-size:13px;
width: 100px;
-moz-border-radius: 0px 0px 0px 0px}
table.phpdi td.phpdi-des {font-family: monospace;
border-width: thin thin thin thin;
padding: 1px 1px 1px 1px;
border-style: solid solid solid solid;
border-color: black black black black;
background-color: white;
font-weight: bold;
color: black;
font-size:10px;
width: 300px;
-moz-border-radius: 0px 0px 0px 0px}
a.phpdi:link { color:#0000EE;
text-decoration: none}
a.phpdi:visited { color: #551A8B;
text-decoration: none}
a.phpdi:active {}
a.phpdi:hover {color: #FF0033}
</style>
<title>Index of $dirname</title>
</head>";
}
//CSS IF / ELSE done. Time to move past the <head>.
//BEGIN HTML
echo"
<body class=\"phpdi\">
<h2 class=\"phpdi\">Index of $dirname</h2>
<table class=\"phpdi\">
<thead>
<tr>
<th>Filename</th>
<th>Description</th>
</tr>
</thead>
<tbody>";
///////////////////////////////////////////////////
/////////NO RECURSE///////////////////////////////
//////////////////////////////////////////////////
//If recurse is set to no. Just list files in this directory.
if ($recurse == 'NO')
{
//Open the current directory.
if ($handle = opendir('.')) {
//Read in the filenames as the file variable.
while ($file = readdir($handle)) {
//If filename is NOT EQUAL TO the following, add the filenames to the filelist
//array. The values in this array will later be extracted and printed to on
//the site. In other words Don't ever list the current directory (.) the up a
//directory link (..) this file itself ($me), or the description text file.
//Additionally if the filename is in the exclude array above do not ever list
//it. Finally if the file begins with a dot (unix hidden files) don't show
//them.
if ($file != "." && $file != ".." && $file != $me && $file != "_description.txt" && $file != in_array($file, $exclude) && substr($file,0,1) != '.') {
//Populate the filelist array with all files in this directory that DONT
//match the above terms.
$filelist[] = $file;
}
}
//Close the directory.
closedir($handle);
}
//Sort the array.
//This will make your file list appear in alphabetical order.
asort($filelist);
//Loop through the array. The value in each row should be called $file
//and the following code should be executed against it.
foreach ($filelist as $file)
{
//If filename is a key in the combined_array (meaning it has a description
//defined in _description.txt) list the file and its associated description.
if (array_key_exists($file, $combined_array)) {
//If $file is a directory add a trailing slash to the printed output.
if (is_dir($file)) {
echo" <tr>
<td class=\"phpdi-dir\"><a class=\"phpdi\" href=\"$file\">$file/</a></td>
<td class=\"phpdi-des\">$combined_array[$file]</td>
</tr>";
}
//If the file is not a directory just print the filename and its description.
else {
echo"
<tr >
<td class=\"phpdi-file\"><a class=\"phpdi\" href=\"$file\">$file</a></td>
<td class=\"phpdi-des\">$combined_array[$file]</td>
</tr>";
}
}
//Else. If the filename is not a key in the combined_array (meaning it does
//not appear in _description.txt) print a link to the file and a blank
//description.
else {
//If $file is a directory add a trailing slash to the printed output.
if (is_dir($file)) {
echo "
<tr>
<td class=\"phpdi-dir\"><a class=\"phpdi\" href=\"$file\">$file/</a></td>
<td class=\"phpdi-des\"></td>
</tr>";
}
//If the file is not a directory just print the filename.
else {
echo "
<tr>
<td class=\"phpdi-file\"><a class=\"phpdi\" href=\"$file\">$file</a></td>
<td class=\"phpdi-des\"></td>
</tr>";
}
}
}
//Time to close out the page.
echo"
</tbody>
</table>
</body>
</html>
";
}
////////////////////////////////////////////////////////////////////
////////////////////RECURSE YES/////////////////////////////////////
///////////////////////////////////////////////////////////////////
//If recurse is set to yes. List files in this directory and all
//sub-directories.
//NOTE:
//If you use recursive mode you may notice that everything is in exact (path
//based) alphbetical order. Meaning files may not be broken up in the exact
//same way an that an Operating system would break them up. This is because the
//recursive directory to array function I use below gets all the files in a
//path into an array in one big call. Then they are all sorted. If anybody
//has a code snippet that would call each subdirectory into its own array that
//could be sorted and then later merged into a master array let me know. I'm
// not smart enough to code such a monster. ;)
elseif ($recurse == 'YES')
{
//The below function will read directory contents into an array.
//Taken from http://www.bigbold.com/snippets/posts/show/155.
//Modified some. This will allow us to read all the contents of
//this directory and all sub-directories into an array.
//Once we have the array we will sort it alphabetically
//and print the filenames on the page.
//The comments below the code snippets in the function
//are how I follow the code. Since I did
//did not write the original code they may not be entirely
//accurate. Parts that start with MOD: are what I added
//to the code.
function directoryToArray($directory, $recursive) {
//Start function. Parse var1 as directory. Parse var2
//as true or false indicating whether to use recursive
//routine or not.
//MOD:
//First we need to define some global variables so this function can access
//what we assigned at the top of the file. GLOBALS must be enabled for this to
//work.
global $me;
global $exclude;
global $combined_array;
$array_items = array();
//Define array for later use.
if ($handle = opendir($directory)) {
while (false !== ($file = readdir($handle))) {
//Open the directory specified in the function.
//MOD:
//If filename is NOT EQUAL TO the following, add the filenames to the filelist
//array. The values in this array will later be extracted and printed to on
//the site. In other words Don't ever list the current directory (.) the up a
//directory link (..) this file itself ($me), or the description text file.
//Additionally if the filename is in the exclude array above do not ever list
//it. Finally if the file begins with a dot (unix hidden files) don't show
//them.
if ($file != "." && $file != ".." && $file != $me && $file != "_description.txt" && $file != in_array($file, $exclude) && substr($file,0,1) != '.') {
//For every file in that directory that doesn't match the above terms do....
if (is_dir($directory. "/" . $file)) {
//If the 'file' in the directory opened is a directory do...
if($recursive) {
//If recursive is set, rerun the function on that directory.
$array_items = array_merge($array_items, directoryToArray($directory. "/" . $file, $recursive));
}
//Add the contents of recursed directory to the array.
$file = $directory . "/" . $file;
$array_items[] = preg_replace("/\/\//si", "/", $file);
//If recurse is not set add the directory to the array, replacing // with /
} else {
$file = $directory . "/" . $file;
$array_items[] = preg_replace("/\/\//si", "/", $file);
//Else if the "file" in the opened directory is a file (not a dir),
//replace // with / and add it to the array.
}
}
}
closedir($handle);
//Close the directory.
//MOD:
//Sort the array alphabetically.
asort($array_items);
}
return $array_items;
//Return the array.
}
//End borrowed code.
//Create the array filelist by running the function
//on the current directory with recursing enabled. This
//will give us an array with valid path links to the
//files. ie: ./pic.jpg and ./pics/babes/theron.jpg.
//Thes entries will be used in our a href statements.
$filelist = directoryToArray("./", true);
// Lets count the number of slashes (/s) in the relative path
//to this document. Since the directory this file is in (in relation to
//itself) should always be "./" this should always equal 1. This will be used
//in the variable $spaces below in order to indent
//file in subdirectories.
$cwd_slash_count = 1;
//Loop through the array. The value in each row should be called $filepath and
//the following code should be executed against it.
foreach ($filelist as $filepath)
{
//Get the filename from the filepath entries in the array.
//These will be what is shown on the page as links. In other words: the array
//$filelist holds path entries to files (ie: ./pics/babes/theron.jpg). The
//basename call below turns the above into "theron.jpg". So what you will end
//up having is <a href="$filepath">$file</a> or <a
//href="pics/babes/theron.jpg">theron.jpg</a>.
$file = basename($filepath);
//Count the number of slashes in the relative path to each file.
//This will be used in the variable $spaces below in order to indent
//file in subdirectories.
$file_slash_count = substr_count($filepath, '/');
//Subtract the number of slashes in the path to this indexer file (./ 1) from
//the number of slashes in the relative path to the files. Save the result as
//$slash_diff. This will be used in the variable $spaces below in order to
//indent file in subdirectories.
$slash_diff = $file_slash_count - $cwd_slash_count;
//Make variable spaces.
//Here is what it does. Takes the number of slashes in the relative path
//to your files and then subtracts the amount of slashes in the relative path
//to this file ($slash_diff). The difference is then multiplied by 2. And the
//product of that determines how many spaces (html s) will come before
//the file link. This should work in most cases, because a file in a
// directory below the one this file is in will get two spaces in front
// of it, and so on. People that use symbolic links might run into
// troubles though!
// Meaning files in subdirectories look indented.
// Your output will end up looking like
//this: path (formatted filename). ./albumlist.txt (albumlist.txt) ./Pink
//Floyd - The //Wall/tracklist.txt ( tracklist.txt) ./Pink Floyd - The
//Wall/CD1/01.mp3 //( 01.mp3).
$spaces = str_repeat( ' ', ( $slash_diff * 2) );
//If filename is a key in the combined_array (meaning it has a description
//defined in _description.txt) list the file and its associated description.
if (array_key_exists($file, $combined_array)) {
//If $filepath is a directory add a trailing slash to the printed output.
if (is_dir($filepath)) {
echo" <tr>
<td class=\"phpdi-dir\">$spaces $file/</td>
<td class=\"phpdi-des\">$combined_array[$file]</td>
</tr>";
}
//If the file is not a directory just print the filename and its description.
else {
echo"
<tr >
<td class=\"phpdi-file\"><a class=\"phpdi\" href=\"$filepath\">$spaces $file</a></td>
<td class=\"phpdi-des\">$combined_array[$file]</td>
</tr>";
}
}
//Else. If the filename is not a key in the combined_array (meaning it does
//not appear in _description.txt) print a link to the file and a blank
//description.
else {
//If $filepath is a directory add a trailing slash to the printed output.
if (is_dir($filepath)) {
echo "
<tr>
<td class=\"phpdi-dir\">$spaces $file/</td>
<td class=\"phpdi-des\"></td>
</tr>";
}
//If the file is not a directory just print the filename.
else {
echo "
<tr>
<td class=\"phpdi-file\"><a class=\"phpdi\" href=\"$filepath\">$spaces $file</a></td>
<td class=\"phpdi-des\"></td>
</tr>";
}
}
//End foreach
}
//Time to close out the page.
echo"
</tbody>
</table>
</body>
</html>
";
}
}
else {
//If the current directory isn't readable complain.
echo"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"><html><head><title>Directory Listing: ERROR</title></head><body><p>Could not list the contents of the directory for some reason.</p></body></html>";
}
?>