93

We use a web server that does not allow directory listing.

There is a specific directory I would like to allow listing of.

How can make a simple HTML file that will contain the contents of this directory?

anatoly techtonik
  • 19,847
  • 9
  • 124
  • 140
David B
  • 29,258
  • 50
  • 133
  • 186

9 Answers9

145

There are enough valid reasons to explicitly disable automatic directory indexes in apache or other web servers. Or, for example, you might only want to include certain file types in the index. In these cases you might still want to have a statically generated index.html file in specific folders.

tree

tree is a minimalistic utility that is available on most unix-like systems (ubuntu/debian: sudo apt install tree, mac: brew install tree, windows: zip). tree can generate plain text, XML (-X), JSON (-J) and HTML (-H) output.

Generate an HTML directory index one level deep (skip, ie -Ignore the generated index.html file itself), include sizes (-s) and timestamps (-D):

tree -H '.' -L 1 --noreport --dirsfirst -T 'Downloads' -s -D --charset utf-8 -I "index.html" -o index.html

Include only specific file types that match a glob pattern, e.g. *.zip and *.gz files, dirs first, include size and timestamps with a custom date format:

tree -H '.' \
    -L 1 \
    --noreport \
    --dirsfirst \
    --charset utf-8 \
    --ignore-case \
    --timefmt '%d-%b-%Y %H:%M' \
    -I "index.html" \
    -T 'Downloads' \
    -s -D \
    -P "*.zip|*.gz" \
    -o index.html

-H '.' enable HTML mode and set base href, can be relative e.g. . or absolute e.g. /files.
-L 1 limit to current directory only
--noreport do not include the summary at the end
--dirsfirst put directories first
--charset utf-8 ensure UTF-8 charset
--ignore-case make the -I and -P options case insensitive
--timefmt '%d-%b-%Y %H:%M' set date format (see man strftime in your terminal for details).
-I "index.html" Ignore the generated index.html file
-P "*.zip|*.gz" filter by glob Pattern, e.g. only include zip/gz files
-T set custom Title
-s include file Sizes
-D include modified dates
-o index.html write to file (stdout by default)

tree does not have a flag to disable the credits in the HTML footer, but you can remove them by piping through sed:

# delete 7 lines starting with the line matching <hr>
tree -H '.' -L 1 --noreport --charset utf-8 | sed -e '/<hr>/,+7d' > index.html

For all supported options see tree --help or man tree in a shell.

Recursively create index.html files in subdirectories

Combined with gnu find you can recursively create index files in a subtree e.g. with:

find . -type d -print -exec sh -c 'tree "$0" \
    -H "." \
    -L 1 \
    --noreport \
    --dirsfirst \
    --charset utf-8 \
    -I "index.html" \
    -T "Custom Title" \
    --ignore-case \
    --timefmt "%d-%b-%Y %H:%M" \
    -s \
    -D \
    -o "$0/index.html"' {} \;

Generator script with recursive traversal

I needed an index generator which I could style the way I want, so ended up writing this script (python 3) which in addition to having customisable styling can also recursively generate an index.html file in all the nested subdirectories (with the --recursive or -r flag). The styling borrows heavily from caddyserver's file-server module *. It includes last modified time and is responsive in mobile viewports.

ccpizza
  • 28,968
  • 18
  • 162
  • 169
  • 5
    excellent solution!!! if you want to omit directories in your `index.html` file, add `--prune` to the `tree` command – MarcoS Dec 06 '17 at 14:46
  • 2
    Inspired by your script, I wrote [https://github.com/yencarnacion/html4tree](https://github.com/yencarnacion/html4tree). html4tree is written in Kotlin. – Yamir Encarnacion Jan 27 '19 at 17:44
  • @ccpizza, the link to the script is broken. – Muon Mar 24 '19 at 04:08
  • 2
    This is a great solution for deploying a site to place like GitLab Pages which only allows static web content (i.e. no php) and also does not allow the use of .htaccess. – haff Jul 23 '19 at 11:22
  • Thank you for the script! Worked perfectly when I needed a quick hack. All hail SO. – CraigDavid Sep 15 '20 at 21:59
  • sadly on Windows it doesn't seem to support the options including limiting to file types that make it effective :/ – Mike M Mar 04 '21 at 13:20
  • Tree works for me in an AWS Amazon website if I don't produce index.html but dircontent.html and link to that. – Rob Rutten Mar 31 '21 at 11:16
  • 1
    If you're running this a second time, you might want to add `-I "index.html"` to not include the index.html file itself. – BallpointBen Feb 12 '23 at 04:26
41

For me PHP is the easiest way to do it:

<?php
echo "Here are our files";
$path = ".";
$dh = opendir($path);
$i=1;
while (($file = readdir($dh)) !== false) {
    if($file != "." && $file != ".." && $file != "index.php" && $file != ".htaccess" && $file != "error_log" && $file != "cgi-bin") {
        echo "<a href='$path/$file'>$file</a><br /><br />";
        $i++;
    }
}
closedir($dh);
?> 

Place this in your directory and set where you want it to search on the $path. The first if statement will hide your php file and .htaccess and the error log. It will then display the output with a link. This is very simple code and easy to edit.

AnthonyVO
  • 3,821
  • 1
  • 36
  • 41
ryryan
  • 3,890
  • 13
  • 43
  • 72
  • 8
    This has multiple stored XSS vulnerabilities: filenames can contain quotes and < >, etc. – Ivan Kozik Jan 03 '17 at 08:28
  • When I try this on AWS, the $file
    ;$i++;}}closedir($dh);?> are the result with the spacing as specified by the
    – Mike D Apr 14 '19 at 19:41
13

You can either: Write a server-side script page like PHP, JSP, ASP.net etc to generate this HTML dynamically

or

Setup the web-server that you are using (e.g. Apache) to do exactly that automatically for directories that doesn't contain welcome-page (e.g. index.html)

Specifically in apache read more here: Edit the httpd.conf: http://justlinux.com/forum/showthread.php?s=&postid=502789#post502789 (updated link: https://forums.justlinux.com/showthread.php?94230-Make-apache-list-directory-contents&highlight=502789)

or add the autoindex mod: http://httpd.apache.org/docs/current/mod/mod_autoindex.html

DuduAlul
  • 6,313
  • 7
  • 39
  • 63
  • The apache server is out of my control. `.htaccess` is disabled. I'm a real newbie to this, so a simple working example would be appreciated. – David B Sep 24 '10 at 07:53
  • 1
    does your apache support PHP? you must use apache that supports server-side scriptwriting otherwise it's impossible.. – DuduAlul Sep 24 '10 at 07:55
  • 1
    add some php file like hello.php, edit this file: " " , try to access it from the client http://server/hello.php and see what you get.. – DuduAlul Sep 24 '10 at 08:00
  • @MrOhad This works. So what should I pout in the HTML to allow listing? – David B Sep 24 '10 at 08:03
  • You can have apache on your local machine, to generate the index files, then use `wget` or `curl` to download the page generated. Apache Fancy Directory Listings allow file descriptions, changing the icons for file types, and add a header and/or footer HTML. This is an example a very fancy Apache directory listing, captured and served on gitlab... https://antofthy.gitlab.io/info/perl/ – anthony Oct 06 '22 at 04:19
9

There's a free php script made by Celeron Dude that can do this called Celeron Dude Indexer 2. It doesn't require .htaccess The source code is easy to understand and provides a good starting point.

Here's a download link: https://gitlab.com/desbest/celeron-dude-indexer/

celeron dude indexer

sehe
  • 374,641
  • 47
  • 450
  • 633
desbest
  • 4,746
  • 11
  • 51
  • 84
6

Did you try to allow it for this directory via .htaccess?

Options +Indexes

I use this for some of my directories where directory listing is disabled by my provider

Michael
  • 79
  • 1
  • 2
    That was my first choice, but the apache server is out of my control and it seems `.htaccess` is disabled. I get `Internal Server Error` when adding such `.htaccess`. – David B Sep 24 '10 at 07:55
2

If you have a staging server that has directory listing enabled, then you can copy the index.html to the production server.

For example:

wget https://staging/dir/index.html

# do any additional processing on index.html

scp index.html prod/dir

wisbucky
  • 33,218
  • 10
  • 150
  • 101
1

This can't be done with pure HTML.

However if you have access to PHP on the Apache server (you tagged the post "apache") it can be done easilly - se the PHP glob function. If not - you might try Server Side Include - it's an Apache thing, and I don't know much about it.

Michael Banzon
  • 4,879
  • 1
  • 26
  • 28
  • I've never wrote PHP. If you could give a working example for an HTML I can put in my dir - it would be great! – David B Sep 24 '10 at 07:44
0

If you have node then you can use fs like in this answer to get all the files:

const { resolve } = require('path'),
  { readdir } = require('fs').promises;

async function getFiles(dir) {
  const dirents = await readdir(dir, { withFileTypes: true });
  const files = await Promise.all(dirents.map((dirent) => {
    const res = resolve(dir, dirent.name);
    return dirent.isDirectory() ? getFiles(res) : res;
  }));
  return Array.prototype.concat(...files);
}

And you might use that like this:

const directory = "./Documents/";
  
getFiles(directory).then(results => {
  const html = `<ul>` +
  results.map(fileOrDirectory => `<li>${fileOrDirectory}</li>`).join('\n') +
  `</ul>`;

  process.stdout.write(html);
  // or you could use something like fs.writeFile to write the file directly
});

You could call it at the command-line with something like this:

$ node thatScript.js > index.html
Jeremy Jones
  • 4,561
  • 3
  • 16
  • 26
-1

My solution was to use a local apache web server to generate HTML index files.

  • Have a local apache web server with 'fancy indexes' enabled as you want them. This includes having headers and footers (readme file) on a per directory basis.
  • Download the missing apache index files from localhost and save them
  • Upload the changes to the remote static web server
  • Remove the generated index files.

This works very well, and means I can test and check any changes on the local apcahe webserver, before I generate listings and uploading the files. In fact my indexes were designed to use apache fancy indexing LONG before I was force to switch to a static web server, so I did not have to re-designed them for a different index generator.

The script to do it was actually VERY simple and written in plain shell.

If you like to see the uploaded result... Visit my "Tower of Computational Sorcery"... https://antofthy.gitlab.io/info/

anthony
  • 7,696
  • 1
  • 17
  • 11