Posted on 2 Comments

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>