2. |
Custom directory listing using PHP. |
|
2.1. |
What and how to list? |
|
|
With all these Lazarus/Free Pascal applications, that I developed and actually am developing, I want to give the users the possibility
to download them by directly by accessing the directories containing the (Windows 64bit) executables, the sources and the programs'
previous versions, as well as the data files, not included within the application's download archive. So, the aim of the scripts is to
display a personalized listing of the content of these directories (without being specific for them, of course). The listing should
include a file-type related icon, the filename (with a link to download it), a description what's the file about, the filesize and
the date, when it last has been modified.
|
|
|
2.2. |
What and how to do? |
|
|
As I said above, the aim of the scripts is to list the content of my download directories, but should also be usable for any other
webserver directory. Thus, the first thing to do is to write some generic functions to retrieve the directory content
and to display it (as a HTML table). A simple possibility to create listings, with subdirectories displayed first, is to make the
retrieve function return 2 arrays, one with the subdirectories, the other with the files. The simplest way to include the file-type specific icons in the listing, is to create another PHP file, just containing the declaration of an array
with the MIME-types (or, alternately, the file-types) as keys and the URL of the file-type-images as values.
|
The Lazarus/Free Pascal download directories specific part should be done in another script, that first calls
the file retrieval function, then the function to display the listing, passing as arguments not only the directory content, but also the
descriptions of the file content; as for the file-icons, these may be declared in an array (with the filename
as keys and the description text as values) contained in a separate PHP file.
|
Finally, we need index.php files, placed in the directories to be listed using my personalized application
(index.php will be executed when the browser accesses the directory without specifying any filename). In my case, these files are nothing
else than the common HTML header, as it appears on all pages of my site and the inclusion of the Lazarus/Free Pascal specific PHP script,
described above. This script has of course to know which directory it should list. The simplest way to let it know this information, is to
set a directory specific variable in each of the index.php files.
|
|
|
2.3. |
My directory listing PHP scripts. |
|
|
You can view the code by opening the tabs below. Or click the following link to download
all that you need to install this appliation. Please note, that I place all my PHP scripts in a directory called php, located directly beneath
the server document root (The index.php files have to be placed into the directory to be listed, of course).
|
a. The directory content retrieval and display functions (filelist.php). |
<?php
function getFileList($dir, $skipscripts) {
function sort_it($a, $b) {
return ($a["name"] <= $b["name"]) ? -1 : 1;
}
$subdirlist = []; $filelist = [];
if(substr($dir, -1) != "/") {
$dir .= "/";
}
$d = @dir($dir) or die("getFileList: Failed opening directory {$dir} for reading");
while(FALSE !== ($entry = $d->read())) {
if($entry{0} == ".") {
continue;
}
if(is_dir("{$dir}{$entry}")) {
$subdirlist[] = [
'path' => "{$dir}{$entry}/",
'name' => "{$entry}",
'type' => filetype("{$dir}{$entry}"),
'size' => 0,
'date' => filemtime("{$dir}{$entry}")
];
}
elseif(is_readable("{$dir}{$entry}")) {
if (!(stripos($entry, 'error') === FALSE && stripos($entry, 'log') === FALSE)) {
continue;
}
if ($skipscripts) {
$fileext = substr($entry, strrpos($entry, '.'));
if ($fileext == '.php' || $fileext == '.pl' || $fileext == '.pm' || $fileext == '.cgi') {
continue;
}
}
$filelist[] = [
'path' => "{$dir}{$entry}",
'name' => "{$entry}",
'type' => mime_content_type("{$dir}{$entry}"),
'size' => filesize("{$dir}{$entry}"),
'date' => filemtime("{$dir}{$entry}")
];
}
}
$d->close();
usort($subdirlist, "sort_it");
usort($filelist, "sort_it");
return array($subdirlist, $filelist);
}
function displayFileList($subdirlist, $filelist, $filedescription, $suffixignore) {
$phpdir = $_SERVER['DOCUMENT_ROOT'] . '/php/';
include("{$phpdir}icons.php");
if (count($subdirlist) == 0 && count($filelist) == 0) {
$ret = 0;
}
else {
$ret = 1;
echo "<table border=\"0\" class=\"small\">\n";
echo "<tr>\n";
echo "<td><img src=\"{$icon['PARENT']}\"/></td>";
echo "<td width=\"10px\"> </td>";
echo "<td colspan=\"7\"><a href=\"../\">Parent directory</a></td>\n";
echo "</tr>\n";
echo "<tr><td colspan=\"9\"> </td></tr>";
if (count($subdirlist) != 0) {
foreach($subdirlist as $subdir) {
$name = $subdir['name'];
$url = str_replace($_SERVER['DOCUMENT_ROOT'], '', $name) . '/';
$type = 'DIRECTORY';
$description = ' ';
$date = substr(date('r', $subdir['date']), 5, strlen($subdir['date']) - 25);
$size = ' ';
echo "<tr>\n";
echo "<td><img src=\"{$icon[$type]}\"/></td>";
echo "<td width=\"10px\"> </td>";
echo "<td><a href=\"{$url}\">{$name}</a></td>\n";
echo "<td width=\"20px\"> </td>";
echo "<td>{$description}</td>\n";
echo "<td width=\"20px\"> </td>";
echo "<td align=\"right\">{$size}</td>\n";
echo "<td width=\"20px\"> </td>";
echo "<td>{$date}</td>\n";  
echo "</tr>\n";
}
echo "<tr><td> </td></tr>";
}
if (count($filelist) != 0) {
foreach($filelist as $file) {
$name = $file['name'];
$url = str_replace($_SERVER['DOCUMENT_ROOT'], '', $name);
$name = substr($name, 0, strrpos($name, '.'));
$lookupname = $name;
if ($suffixignore) {
if (strpos($lookupname, '_') != 0) {
$lookupname = substr($lookupname, 0, strrpos($name, '_'));
}
}
$type = $file['type'];
$date = substr(date('r', $file['date']), 5, strlen($file['date']) - 25);
$size = $file['size'];
if ($size <= 1000) {
$size .= ' bytes ';
}
else {
$size = round($file['size'] / 1000) . ' kbytes';
}
echo "<tr>\n";
if (!array_key_exists($type, $icon)) {
$type = 'FILE';
}
echo "<td><img src=\"{$icon[$type]}\"/></td>";
echo "<td width=\"10px\"> </td>";
echo "<td><a href=\"{$url}\">{$name}</a></td>\n";
echo "<td width=\"20px\"> </td>";
if (array_key_exists($lookupname, $filedescription)) {
$description = $filedescription[$lookupname];
}
else {
$description = ' ';
}
echo "<td>{$description}</td>\n";
echo "<td width=\"20px\"> </td>";
echo "<td align=\"right\">{$size}</td>\n";
echo "<td width=\"20px\"> </td>";
echo "<td>{$date}</td>\n";
echo "</tr>\n";
}
}
echo "</tbody>\n";
echo "</table>\n\n";
}
return $ret;
}
?>
|
|
b. The file-type icons URL array code (icons.php). |
<?php
$resurl = '/res/';
$icon = array (
'PARENT' => "{$resurl}up.png",
'DIRECTORY' => "{$resurl}folder.png",
'FILE' => "{$resurl}file.png",
'application/zip' => "{$resurl}zip.png",
'text/plain' => "{$resurl}text.png"
);
?>
|
|
c. The Lazarus/Free Pascal directories specific script (lazarus_filelist.php). |
<?php
$phpdir = $_SERVER['DOCUMENT_ROOT'] . '/php/';
include("{$phpdir}filelist.php");
include("{$phpdir}lazarus_filedescription.php");
if (!isset($dir)) {
echo "<p>Script error: No directory set!</p>";
}
else {
$dir = $_SERVER['DOCUMENT_ROOT'] . '/computing/lazarus/' . $dir;
list($subdirlist, $filelist) = getFileList($dir, 1);
$ret = displayFileList($subdirlist, $filelist, $filedescription, 1);
if ($ret == 0) {
echo "<p>This directory is empty!</p>";
}
}
?>
|
|
d. The Lazarus/Free Pascal file description array code (lazarus_filedescription.php). |
<?php
$filedescription = array (
'AAStats' => 'Protein analysis: Amino acids statistics',
'AcidBase' => 'Mineral acid-base reactions exercise generator',
'ACircuits1' => 'Electronics trainer - RLC circuits',
'Adjectifs' => 'French grammar: The adjective suffixes',
- truncated -
'WorldQuiz' => 'World countries quiz',
'Zuelespill' => 'Number game',
'ZueleRaetsel' => 'Guess which number hides behind the different shapes',
'Zodiac' => 'Astrology: Zodiac signs'
);
?>
|
|
e. The index.php files (e.g. PHP code inserted into index.php listing
the Lazarus/Free Pascal sources). |
<?php
$script = $_SERVER['DOCUMENT_ROOT'] . '/php/lazarus_filelist.php';
$dir = 'files/sources';
include($script);
?>
|
|
|
|
|
2.4. |
Error handling. |
|
|
The file retrieval function checks if the directory exists and dies if it doesn't; thus, no need to do so in the calling script. For an empty
directory, the file listing function displays nothing and returns 0 (instead of 1, indicating that all is ok); it's up to the calling script
to display or not a message in this case.
|
|
|
2.5. |
Modifying and extending the scripts. |
|
|
Please, note that the scripts described here are intended to list the content of 1 single directory and not to display a recursive directory
listing of a given path! To do this, another function would have to be written. You are entirely free to adapt the scripts to your needs just as
you like. A useful extension could, for example, be to display the number of subdirectories and the number and total size of the files.
|
|
|
2.6. |
Script output. |
|
|
Here, as example of how the page generated by my personalized directory listing script looks like, a screenshot of the listing of the Lazarus/Free
Pascal source files on my local webserver.
|
|
|
|