Custom Apache Directory Listing using PHP

Apache Logo

This snippet overrides Apache’s default presentation of folder contents.

/**
 * CustomDirectoryListing
 *
 * A simple script for custom directory listing. Adds support for
 * - maximum amount of items per row
 * - image listing with automatic resizing
 * - displaying images before other file types for a prettier layout
 *
 * The above options can be controlled via the corresponding $_GET variables,
 * @see below.
 *
 * USAGE
 * Simply put this file into the directory you want to be listed. You might want
 * to set the defaultWidth and defaultHeight, as well as maxItemsPerRow to your
 * needs.
 *
 * @author Matthias Kerstner info@kerstner.at
 * @copyright Matthias Kerstner info@kerstner.at
 * @version 1.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

mb_internal_encoding('UTF-8');
mb_regex_encoding('UTF-8');

$maxItemsPerRow = (isset($_GET['maxItemsPerRow']) && (int)$_GET['maxItemsPerRow'] > 0)
        ? (int)$_GET['maxItemsPerRow']-1 : 4;
$defaultWidth = (isset($_GET['defaultWidth']) && (int)$_GET['defaultWidth'] > 0)
        ? (int)$_GET['defaultWidth'] : 150;
$defaultHeight = (isset($_GET['defaultHeight']) && (int)$_GET['defaultHeight'] > 0)
        ? (int)$_GET['defaultHeight'] : 100;
$imagesFirst = isset($_GET['imagesFirst']);

/**
 * Calculates resized size based on $dstHeight and $dstWidth by maintaining the
 * original width-height-ratio. Checks which dimension is greater and sets it to
 * a fixed value specified. The remaining dimension is resized using the
 * original ratio to the other dimension's new fixed value.
 * @param <string> $srcFile
 * @param <int> $dstHeight
 * @param <int> $dstWidth
 * @return <array> [0]=width, [1]=height
 */
function getResizeSize($srcFile, $dstHeight, $dstWidth) {

    $srcFileInfo = getimagesize($srcFile); //[0]=width,[1]=height

    if(empty($srcFileInfo))
        throw new Exception('Failed to read image fileinfo.');

    if($srcFileInfo[0] <= (int)$dstWidth &&
            $srcFileInfo[1] <= (int)$dstHeight) {
        return array($srcFileInfo[0], $srcFileInfo[1]); //nothing to do
    }

    $newSize = array();

    if($srcFileInfo[0] >= $srcFileInfo[1]) { //calculate new dimensions while keeping current ratio
        $newSize[0] = $dstWidth;
        $newSize[1] = ($srcFileInfo[1]/$srcFileInfo[0]) * $dstWidth;
    } else {
        $newSize[0] = ($srcFileInfo[0]/$srcFileInfo[1]) * $dstHeight;
        $newSize[1] = $dstHeight;
    }

    return $newSize;
}

?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Custom Directory Listing</title>
        <style type="text/css">
            html {
                font-family: Courier, Verdana, sans-serif;
                font-size: 9pt;
                border: 0;
            }
        </style>
    </head>
    <body>

        <?php

        try {

            $handle = opendir('.');
            $file = null;

            if(!$handle)
                throw new Exception('Failed to read directory.');

            $nonImageItems = array();
            $itemPerRowCount = 0;

            while(false !== ($file = readdir($handle))) {

                if($itemPerRowCount >= $maxItemsPerRow) {
                    echo '<br/>';
                    $itemPerRowCount = 0;
                }

                if($file !== "." && $file !== "..") {

                    if(mb_eregi('.jpg$', $file) === 1) { //image

                        $filesize = getResizeSize($file, $defaultWidth, $defaultHeight);

                        echo '<a href="'.$file.'">'.
                                '<img src="'.$file.'" width="'.$filesize[0].'" '.
                                'height="'.$filesize[1].'" alt="'.$file.'" '.
                                'border="0"/>'.
                                '</a>&nbsp;&nbsp;';

                        $itemPerRowCount++;
                    } else {
                        if($imagesFirst)
                            $nonImageItems[] = $file;
                        else {
                            echo '<a href="'.$file.'">'.$file.'</a>&nbsp;&nbsp;';
                            $itemPerRowCount++;
                        }
                    }
                }
            }

            closedir($handle);

            $itemPerRowCount = 0;

            foreach($nonImageItems as $v) { //display non-image files afterwards
                if($itemPerRowCount >= $maxItemsPerRow) {
                    echo '<br/>';
                    $itemPerRowCount = 0;
                }

                echo '<a href="'.$v.'">'.$v.'</a>&nbsp;&nbsp;';

                $itemPerRowCount++;
            }

        } catch(Exception $e) {
            echo 'Sorry an error occurred: '.$e->getMessage();
        }

        ?>

    </body>
</html>

Comments

2 responses to “Custom Apache Directory Listing using PHP”

  1. Jayapal Chandran Avatar

    custom directory listing script in apache/php in shared hosting
    As we know that if we have enabled directory listing then all files and folders will be listed if we do not have index.* or default.*

    I have used htaccess to auto prepend a php script thinking that it will run instead of the default directory script. but it works only for scripts like php and not for html or other extensions.

    So here what i want is i want to do my custom directory listing but i don’t want to put an index.php in all folders with my custom code… whereas i want to autoprepend my custom directory listing script in htaccess but this is not working…

    so i want to run my custom script for directory listing

    Besides, i am in a shared hosting so i cannot modify config files. htaccess is working.

    so what is the way to do a custom directory listing?

    1. matthias.kerstner Avatar

      Hello Jayapal,

      originally the custom directory listing script was only designed to be used for specific folders. Thus, basically the idea was to set the custom directoy listing script as index file in these folders.

      Now, concerning your request to achieve custom directory listings using a script that resides in only one location I must say that this is a bit tricky. Let’s assume you have the following folder structure:

      • /root
      • /root/folder1
      • /root/folder2
      • /root/folder2/folder2_1

      Now what I understand from your comment is that you want to put your custom directory listing script in /root only and expect it to be executed when visitors try to get a directory listing for root/folder2_1 too. Correct?

      If this is the case then you will have to work with mod_redirect and an additional include file. Thus, you have to redirect all requests to a base folder (e.g. /root, /root/folder1, …) to the additional include script that in return will execute the custom directory listing script residing in /root. For this to work, your .htaccess in root will have to

      • – determine wheter a file or folder request has been made
      • – if a file request has been made simply serve the file as usual
      • – otherwise the custom directory listing script has to be executed

      If a folder request has been made check if for the requested folder there exists the additional include file (referencing the custom directory listing file in /root). If this is the case simply serve it.

      Based on this approach you should achieve custom directory listings for sub folder without being forced to include your original custom directory listing script in every sub folder.

      Hope that helps.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.