"I regularly read Internet user groups filled with messages from people trying to solve software incompatibility problems that, in terms of complexity, make the U.S. Tax Code look like Dr. Seuss." — Dave Barry

Fancy Directory Listing (Using htaccess)

Fancy Directory Listing (Using htaccess)

Fancy Directory Listing (Using htaccess)

In this tutorial I cover the basics of htaccess, how to create a custom Apache directory listing using .htaccess. If you look at the default Apache directory listing you’ll see a plain, boring, dull, hard to read design. Our objective for the course of this tutorial is to spice up that design, and learn some htaccess in the process!

For those that would just like to see the finished results, you can see the before and afters here.

http://www.thewebsqueeze.com/samples/directory-listing/

The Rules

Before we get started I want to cover the SUPER basics of htaccess. This will help those who aren’t familiar with how Apache and htaccess work understand what we are doing as we go along. (These are generic rules, and may differ from server to server, depending on the configuration. Ask your server administrator if you receive any errors.)

  1. All htaccess code should be placed in a text document named ‘.htaccess’.
  2. htaccess works on a recursive basis. So any command you type will work for the current directory, and all sub-directories under that, unless otherwise specified.
  3. You can have any number of htaccess files on your domain. The root of your domain can have a master htaccess file, and then you can override the master htaccess file within sub-directories off the root of the domain.
  4. In htaccess, any line prefixed with a “#” symbol is considered to be a comment. You should comment your code so you can refer to that comment 3-4 months down the road when you are trying to figure out why you coded it in that way.
  5. If ever in doubt you can read the Apache documentation. (http://httpd.apache.org/docs/2.2/) Or, you could ask the kind hearted folks at The Web Squeeze in our forum! (http://www.thewebsqueeze.com/forum/)

Let’s get started!

Here’s the default directory listing for Apache! Now, you might not see this by default, in fact you may see a Forbidden page, however, we’ll fix that with this next bit of code!

Default Directory Listing

I always start my htaccess documents with what I call “General Rewrites”, those are the rewrites that I tend to duplicate throughout all my htaccess documents.

                                        # START :: General Rules
                                        RewriteEngine On
                                        RewriteBase /
                                        

In htaccess any line prefixed with a “#” symbol is considered to be a comment. So, for organizational purposes I have commented the start and end of sections. We are then turning on the RewriteEngine and setting the base for the engine, if it’s not already set.

                                        Options +Indexes
                                        

First, as you may already know htaccess has countless options to allow you to control how your domain works and loads without editing server configuration files. The “Options” directive controls which server features are available in a particular directory. You can view all the available options on Apache’s website.

http://httpd.apache.org/docs/2.0/mod/core.html#options

So, we’re saying find the “Indexes” option within the “Options” directive, and turn that on. By adding that “+” sign in-front of “Indexes” you are effectively turning on Apache’s directory index for not only that directory, but all sub-directories below that location.

This means that if a URL which points to a directory is requested, and there isn’t a DirectoryIndex (e.g. index.html) then mod_autoindex will return a formatted listing of the directory.

You could also turn off Apache directory listing by replacing the “+” with a “-”, effectively telling Apache, not to list the contents of that directory and all directories below that.

                                        Options +FollowSymLinks
                                        # END :: General Rules
                                        

FollowSymLinks tells Apache to follow symbolic links. Wikipedia defines a symbolic link as…

A symbolic link (also symlink or soft link) is a special type of file that contains a reference to another file or directory in the form of an absolute or relative path and that affects pathname resolution.

                                        # START :: Error Documents
                                        ErrorDocument 400 default
                                        ErrorDocument 401 default
                                        ErrorDocument 403 default
                                        ErrorDocument 404 default
                                        ErrorDocument 500 default
                                        # END :: Error Documents
                                        

Here, I’m setting all ErrorDocuments to the server default. You could replace ‘default’ with an absolute or relative path to the location of your error documents. You can read more about that here.

http://httpd.apache.org/docs/1.3/mod/core.html#errordocument

                                        # START :: URL Rewrites
                                        RewriteCond %{HTTP_HOST} !^clients.samples\.thewebsqueeze\.com$ [NC]
                                        RewriteRule ^(.*)$ http://clients.samples.thewebsqueeze.com/$1 [R=301,L]
                                        # END :: URL Rewrites
                                        

Here, I’m setting a rewrite condition. You can think of it like an “if” statement in PHP. If the URL doesn’t equal ‘clients.samples.thewebsqueeze.com’, with anything on the end, then do whatever the rewrite rule is. In this case, then, redirect them to ‘http://clients.samples.thewebsqueeze.com/’. You’ll want to either delete these lines, or change them to match the location of your fancy directory! You could also alter this to remove or add the ‘www’ for your domain. See below example.

                                        # START :: URL Rewrites
                                        RewriteCond %{HTTP_HOST} !^www\.thewebsqueeze\.com$ [NC]
                                        RewriteRule ^(.*)$ http://www.thewebsqueeze.com/$1 [R=301,L]
                                        # END :: URL Rewrites
                                        

Now, this last bit of code is a method of securing our directory’s htaccess file against attacks. Protecting your site’s htaccess file is critical to maintaining a secure environment.

                                        # START :: Strong .htaccess Protection
                                        <files ~ "^.*\.([Hh][Tt][Aa])">
                                        order allow,deny
                                        deny from all
                                        </files>
                                        # END :: Strong .htaccess Protection
                                        

You can read more about the above method at Perishable Press.

Now, let’s recap all the code thus far!

                                        # START :: General Rules
                                        RewriteEngine On
                                        RewriteBase /
                                        Options +Indexes
                                        Options +FollowSymLinks
                                        # END :: General Rules

# START :: Error Documents
                                        ErrorDocument 400 default
                                        ErrorDocument 401 default
                                        ErrorDocument 403 default
                                        ErrorDocument 404 default
                                        ErrorDocument 500 default
                                        # END :: Error Documents

# START :: URL Rewrites
                                        RewriteCond %{HTTP_HOST} !^clients.samples\.thewebsqueeze\.com$ [NC]
                                        RewriteRule ^(.*)$ http://clients.samples.thewebsqueeze.com/$1 [R=301,L]
                                        # END :: URL Rewrites

# START :: Strong .htaccess Protection
                                        <files ~ "^.*\.([Hh][Tt][Aa])">
                                        order allow,deny
                                        deny from all
                                        </files>
                                        # END :: Strong .htaccess Protection
                                        

So, now we’ve defined some basic rules, and your directory listing should look like mine!

Default Directory Listing

Next, we’re going to get started customizing the htaccess listing! So, what are you waiting for? Let’s go!

Pretty Directory Listing (htaccess)

                                        # START :: Directory Customization
                                        <ifmodule mod_autoindex.c>
                                        

Here we are creating an if module which says, if the Apache Module ‘mod_autoindex.c’ is available and installed, then do whatever is inside. You would end that IfModule like so…

                                        </ifmodule>
                                        # END :: Directory Customization
                                        

But, let’s not end it just yet. This is going to be the core of our directory listing. So, in-between the starting and ending ‘IfModule’, add the following.

                                        # Set Index Options
                                        IndexOptions IgnoreCase FancyIndexing FoldersFirst NameWidth=* DescriptionWidth=* XHTML HTMLtable SuppressHTMLPreamble SuppressRules SuppressDescription SuppressLastModified SuppressSize IconHeight=16 IconWidth=16 IconsAreLinks
                                        

Here we’re setting our directory index options. That’s a lot to undertake, so I’ll go over it piece by piece.

                                        IndexOptions
                                        

The IndexOptions directive specifies how Apache handles the directory indexing. You can see all the ‘IndexOptions’ available to you by seeing the Apache documentation.

http://httpd.apache.org/docs/2.0/mod/mod_autoindex.html#indexoptions

                                        IndexOptions IgnoreCase FancyIndexing FoldersFirst
                                        

After ‘IndexOptions’ we are setting all the different options for that directory. We are choosing to ignore case for the directory listing. Next, we are applying ‘FancyIndexing’, and setting folders to display before files using the ‘FoldersFirst’ declaration.

                                        NameWidth=* DescriptionWidth=* XHTML HTMLtable
                                        

We continue by setting the width of the name and description to ‘*’ which essentially means that it will grow the column to the necessary width in bytes. This means that no line wrapping will happen for longer file/directory names. We then turn on ‘XHTML’, you can leave this out if you are coding an HTML document. After that, we apply an HTML table around the directory listing using ‘HTMLtable’. This allows us to style the table without messing up the columns.

                                        SuppressHTMLPreamble SuppressRules SuppressDescription SuppressLastModified SuppressSize IconHeight=16 IconWidth=16 IconsAreLinks
                                        

‘SuppressHTMLPreamble’ removes the starting , and tags allowing you to code that in your header and footer documents below. ‘SuppressRules’ removes the horizontal rule lines (


). We then remove the description (SuppressDescription), last modified date (SupressLastModified), and size columns (SuppressSize). After which, we set the ‘IconHeight’ and ‘IconWidth’ to 16px, and make the icons links. (IconsAreLinks) Continuing on….

                                        # Set Display Order
                                        IndexOrderDefault Ascending Name
                                        

Here we set the index order to ascending by the file/folder name. So this means it’s in alphabetical order!

                                        # Specify Header File
                                        HeaderName /i/header.shtml

# Specify Footer File
                                        ReadmeName /i/footer.shtml
                                        

This is one of the keys! Here we are setting the location of the header and footer documents. These documents contain the structure of the directory listing. We’re using .shtml so that we can do some server side scripting later on. (Make sure you change the location/name of those documents to where they will be stored on your server.)

                                        # Ignore These Files/Folders
                                        IndexIgnore header.shtml footer.shtml i images cgi-bin favicon.ico .htaccess .ftpquota .DS_Store icons *.log *,v *,t .??* *~ *#
                                        

Here we are telling Apache not to display any of the files or folders that follow ‘IndexIgnore’, this is great as it allows you to hide your images directory…etc.


# END :: Directory Customization
                                        

Finally, we end the ‘IfModule’. Quickly recapping the above code….

                                        # START :: Directory Customization
                                        <ifmodule mod_autoindex.c>
                                        # Set Index Options
                                        IndexOptions IgnoreCase FancyIndexing FoldersFirst NameWidth=* DescriptionWidth=* XHTML HTMLtable SuppressHTMLPreamble SuppressRules SuppressDescription SuppressLastModified SuppressSize IconHeight=16 IconWidth=16 IconsAreLinks

# Set Display Order
                                        IndexOrderDefault Ascending Name

# Specify Header File
                                        HeaderName /i/header.shtml

# Specify Footer File
                                        ReadmeName /i/footer.shtml

# Ignore These Files/Folders
                                        IndexIgnore header.shtml footer.shtml i _htaccess-code clients.zip images cgi-bin favicon.ico .htaccess .ftpquota .DS_Store icons *.log *,v *,t .??* *~ *#

</ifmodule>
                                        # END :: Directory Customization
                                        

Now, we need to add the SHTML documents to the mix. You’ll notice I use some server side scripting, however, I won’t go into detail on that as it’s not the objective of this tutorial.

HEADER.SHTML

                                        < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
                                        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
                                        <head>
                                        <!--#if expr="$Request_URI == '/'"-->
                                        <title>TWS Clients :: Choose A Client</title>

	<!--#elif expr="$Request_URI == /AOL\/?/"-->
                                        <title>America Online, LLC.</title>

	<!--#elif expr="$Request_URI == /Apple\/?/"-->
                                        <title>Apple Inc.</title>

	<!--#elif expr="$Request_URI == /Cisco\/?/"-->
                                        <title>Cisco Systems, Inc.</title>

	<!--#elif expr="$Request_URI == /Dell\/?/"-->
                                        <title>Dell, Inc.</title>

	<!--#elif expr="$Request_URI == /EA\/?/"-->
                                        <title>Electronic Arts, Inc.</title>

	<!--#elif expr="$Request_URI == /Google\/?/"-->
                                        <title>Google, Inc.</title>

	<!--#elif expr="$Request_URI == /IBM\/?/"-->
                                        <title>IBM, Inc.</title>

	<!--#elif expr="$Request_URI == /Logitech\/?/"-->
                                        <title>Logitech, Inc.</title>

	<!--#elif expr="$Request_URI == /Microsoft\/?/"-->
                                        <title>Microsoft, Inc.</title>

	<!--#else -->
                                        <title><!--#echo var="Request_URI" --></title>
                                        <!--#endif -->
                                        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
                                        <link rel="stylesheet" type="text/css" href="/i/style.css" />
                                        <link rel="shortcut icon" href="/i/images/favicon.ico" />

</head>

<body>
                                        <div id="wrap">
                                        <div id="main">
                                        <!--#if expr="$Request_URI == '/'"-->
                                        <h1>TWS Clients</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /AOL\/?/"-->
                                        <h1>America Online, LLC.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /Apple\/?/"-->
                                        <h1>Apple Inc.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /Cisco\/?/"-->
                                        <h1>Cisco Systems, Inc.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /Dell\/?/"-->
                                        <h1>Dell, Inc.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /EA\/?/"-->
                                        <h1>Electronic Arts, Inc.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /Google\/?/"-->
                                        <h1>Google, Inc.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /IBM\/?/"-->
                                        <h1>IBM, Inc.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /Logitech\/?/"-->
                                        <h1>Logitech, Inc.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#elif expr="$Request_URI == /Microsoft\/?/"-->
                                        <h1>Microsoft, Inc.</h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>

	<!--#else -->
                                        <h1><!--#echo var="Request_URI" --></h1>
                                        <h3 class="location">Location: <!--#echo var="Request_URI" --></h3>
                                        <!--#endif -->
                                        

FOOTER.SHTML

                                        <p>Icons By: <a href="http://www.famfamfam.com/lab/icons/silk/">FAMFAMFAM</a></p>
                                        <p>&copy; Copyright 2009 <a href="http://www.thewebsqueeze.com/">The Web Squeeze, LLC.</a><br />All Rights Reserved.</p>
                                        </div>
                                        </div>
                                        </body>
                                        </html>
                                        

STYLE.CSS

                                        html, body, div, span, applet, object, iframe,
                                        header, footer, nav, section, article, aside,
                                        h1, h2, h3, h4, h5, h6, p, blockquote, pre,
                                        a, abbr, acronym, address, big, cite, code,
                                        del, dfn, font, img, ins, kbd, q, s, samp,
                                        small, strike, sub, sup, tt, var,
                                        dl, dt, dd, ol, ul, li,
                                        fieldset, form, label, legend,
                                        table, caption, tbody, tfoot, thead, tr, th, td {
                                        margin:0;
                                        padding:0;
                                        border:0;
                                        outline:0;
                                        font-weight:inherit;
                                        font-style:inherit;
                                        font-size:100%;
                                        font-family:inherit;
                                        vertical-align:baseline;
                                        }
                                        body {
                                        background:#469bfc;
                                        color:#333;
                                        font-family:Tahoma, Geneva, sans-serif;
                                        width:100%;
                                        float:left;
                                        padding:0 0 30px;
                                        }
                                        #wrap {
                                        width:360px;
                                        margin:30px auto 0;
                                        }
                                        #main {
                                        width:300px;
                                        float:left;
                                        padding:30px;
                                        background:#fafafa;
                                        border:6px solid #007ede;
                                        }
                                        h1 {
                                        font: 2.0em Georgia, serif;
                                        text-align:center;
                                        color:#78D316;
                                        }
                                        h3.location {
                                        font-size:13px;
                                        font-weight: bold;
                                        margin:12px 0 30px;
                                        text-align:center;
                                        color:#4D7EC7;
                                        }
                                        a:link, a:visited {
                                        text-decoration: none;
                                        color: #024591;
                                        }
                                        a:hover, a:active {
                                        text-decoration: underline;
                                        color: #006be6;
                                        }
                                        table {
                                        width:100%;
                                        padding:0;
                                        margin:0;
                                        border:0;
                                        }
                                        tr {
                                        width:100%;
                                        padding:0;
                                        margin:0;
                                        border:0;
                                        }
                                        tr:nth-child(even) {
                                        background:#def2ff;
                                        }
                                        th {
                                        display:none;
                                        }
                                        td {
                                        height:20px;
                                        padding:10px;
                                        margin:0;
                                        }
                                        td:nth-child(1){
                                        width:16px;
                                        }
                                        hr {
                                        display:none;
                                        }
                                        p {
                                        margin:20px 0 0;
                                        font-size:14px;
                                        text-align:center;
                                        }
                                        

Your directory listing should look like mine now!

Fancy Directory Listing - No Icons

But, what about the icons? Well, continue on to the next part!

Adding Custom Icons

Almost all of the icons used for directory symbols were downloaded from FAMFAMFAM. You can download the Silk Icon set below.

http://www.famfamfam.com/lab/icons/silk/

Once you’ve downloaded the icons, your ready to start! Find the following section of code.


# END :: Directory Customization
                                        

Above the end ‘’ add the following lines of code.

                                        # START :: DEFINE FILE & FOLDER ICONS
                                        # Default Icon
                                        DefaultIcon /i/images/icons/resultset_next.png

 # Folder/Directory Icon
                                        AddIcon /i/images/icons/folder.png ^^DIRECTORY^^

 # Up a directory
                                        AddIcon /i/images/icons/arrow_undo.png ..
                                        

Again, I heavily commented each line, thereby making it easier to update later. Basically, I’m defining a default icon for files, and a default icon for directories. After which we define the icon used to “Go Back”, or up a directory.

                                        # Directory Icons
                                        AddIcon /i/images/client-icons/aol.png AOL
                                        AddIcon /i/images/client-icons/apple.png Apple
                                        AddIcon /i/images/client-icons/cisco.png Cisco
                                        AddIcon /i/images/client-icons/dell.png Dell
                                        AddIcon /i/images/client-icons/ea.png EA
                                        AddIcon /i/images/client-icons/google.png Google
                                        AddIcon /i/images/client-icons/ibm.png IBM
                                        AddIcon /i/images/client-icons/logitech.png Logitech
                                        AddIcon /i/images/client-icons/microsoft.png Microsoft
                                        

Now I’m setting custom icons for my main directory listing. You set a custom icon in the following format….

                                        AddIcon /location/to/graphic.png FILE-NAME
                                        

So, you see how I assigned icons to certain folders, but what about file formats? You don’t want to have to assign an icon to every mp3 file using the above method. Here’s a method to assign an icon to file formats.

                                        # START :: DEFINE FILE FORMAT ICONS
                                        # PDF Documents
                                        AddIcon /i/images/icons/book_open.png .pdf

 # Word Documents
                                        AddIcon /i/images/icons/page_white_word.png .txt .doc .rtf .log .asc

 # Pictures
                                        AddIcon /i/images/icons/picture.png .jpg .jpeg .jpe .png .gif .mpg .ico .psd

 # Music
                                        AddIcon /i/images/icons/music.png .mp3 .wav .vox .wma .ra .ram .ogg .vqf .aac

 # Video/Movies
                                        AddIcon /i/images/icons/film.png .mov .avi .wmv .mpeg

 # HTML
                                        AddIcon /i/images/icons/html.png .html .htm .shtm .shtml

 # XHTML
                                        AddIcon /i/images/icons/xhtml.png .xhtml

 # CSS
                                        AddIcon /i/images/icons/css.png .css

 # PHP
                                        AddIcon /i/images/icons/script.png .php

 # ASP / JavaScript
                                        AddIcon /i/images/icons/script.png .asp .js .xml

 # Flash
                                        AddIcon /i/images/icons/page_white_actionscript.png .swf .fla .as

 # Compressed Documents
                                        AddIcon /i/images/icons/page_white_zip.png .zip .rar .gz .bz2

 # Disk Image
                                        AddIcon /i/images/icons/drive_web.png .iso .rpm

 # Torrent Files
                                        AddIcon /i/images/icons/application_lightning.png .torrent
                                        # END :: DEFINE FILE FORMAT ICONS
                                        

This basically works the same way.

                                        AddIcon /location/to/graphic.png .FILE-TYPE
                                        

Again, all the icons are from the Silk Icon set by FAMFAMFAM. You can download them and view them here.

http://www.famfamfam.com/lab/icons/silk/
http://www.famfamfam.com/lab/icons/silk/previews/index_abc.png

You can also add file and folder descriptions using this format.

                                        # START :: File Type Descriptions
                                        AddDescription "<span class='description'>Music/Sound File</span>" .mp3
                                        AddDescription "<span class='description'>GZIP compressed TAR archive</span>" .tgz .tar.gz
                                        AddDescription "<span class='description'>GZIP compressed archive</span>" .Z .z .gz .zip
                                        ......etc.....
                                        # END :: File Type Descriptions
                                        

That adds a description for certain file types, with a span class around the description. You can also target certain directories or files.

                                        # START :: Folder Descriptions
                                        AddDescription "[<span class='description'>Go Back..</span>]" ..
                                        AddDescription "[<span class='description'>American Online, LLC.</span>]" AOL
                                        AddDescription "[<span class='description'>Apple Inc.</span>]" Apple
                                        AddDescription "[<span class='description'>Cisco Systems, Inc.</span>]" Cisco
                                        AddDescription "[<span class='description'>Dell Inc.</span>]" Dell
                                        AddDescription "[<span class='description'>Electronic Arts, Inc.</span>]" EA
                                        AddDescription "[<span class='description'>Google, Inc.</span>]" Google
                                        AddDescription "[<span class='description'>IBM, Inc.</span>]" IBM
                                        AddDescription "[<span class='description'>Logitech, Inc.</span>]" Logitech
                                        AddDescription "[<span class='description'>Microsoft, Inc.</span>]" Microsoft
                                        # END :: Folder Descriptions
                                        

You can also add a default description for other “unknown” file types/folders by using a wildcard.

                                        # Default Description
                                        AddDescription "<span class='description'></span>" *
                                        

Apache Directory Listing Gallery

I didn’t have time to cover all of the possible options you can use when styling your custom Apache directory listing, however, I hope the samples I designed will help you!

http://samples.thewebsqueeze.com/directory-listing/

Clients Listing

BEFORE
Client Before

AFTER
Client After

Media Listing

BEFORE
Media Before

AFTER
Media After

Linux Mirror

Linux After

You can view all the designs, and download the code here.

http://www.thewebsqueeze.com/samples/directory-listing/

If you have any questions, ask them below. Now, go out a design your own fancy directory listings and post them in the comments section below!

Comments are closed.