Code Bytes
List approved files from a directory with PHP
Build a small public download list with a fixed directory, an extension allowlist, escaped labels and no hidden files or symlink traversal.
A directory-backed download list is useful for a small collection of public PDFs or images. The important word is public: hiding a filename from the list does not stop someone requesting the file directly.
Give the list its own directory
Put only publication-approved files in downloads/, alongside this PHP page, and serve that directory at /downloads/. The code is deliberately non-recursive: it lists files from that one directory, not the surrounding project.
<?php
declare(strict_types=1);
$directory = __DIR__ . '/downloads';
$extensions = ['pdf', 'jpg', 'jpeg', 'png', 'mp3', 'docx'];
$names = [];
if (!is_dir($directory) || is_link($directory)) {
throw new RuntimeException('The public download directory is unavailable.');
}
foreach (new FilesystemIterator($directory, FilesystemIterator::SKIP_DOTS) as $entry) {
$name = $entry->getFilename();
if ($entry->isLink() || !$entry->isFile() || str_starts_with($name, '.')
|| !in_array(strtolower($entry->getExtension()), $extensions, true)) {
continue;
}
$names[] = $name;
if (count($names) > 100) {
throw new RuntimeException('Use a paginated catalogue for a larger library.');
}
}
natcasesort($names);
echo '<ul>';
foreach ($names as $name) {
$label = htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
echo '<li><a href="/downloads/' . rawurlencode($name) . '">'
. $label . '</a></li>';
}
echo '</ul>';
Filename encoding keeps spaces and characters such as & from breaking the URL. HTML escaping protects the visible label independently. Neither is a substitute for deciding which files belong online.
Do not turn this into a file browser
Keep the filesystem path in code or trusted configuration, never in a query parameter. Backups, invoices, source files and customer documents belong elsewhere. For private downloads, use an authenticated handler with a per-file permission check rather than direct public links. Uploaded files also need their own content validation and safe serving policy; an extension allowlist alone does not establish a file's actual type.
References: FilesystemIterator and escaping HTML.
Original version26 January 2014
Kept here for reference and earlier links. The updated guide above is the recommended starting point; older code may depend on retired services or different software versions.
I've created this simple bit of PHP to specify a directory, and then list the files grouped by folder on screen.
You can set certain files to be created as links, for easy browsing, they are: jpg,png,gif,docx,pdf,mp3. You can add any other file you want in the $files line.
I personally find this snippet very useful for document libraries and file management. As it saves you adding a file, and then having to manually list it in any index.php file. It will just automatically appear!
This example shows how it will turn a list of folders/documents etc into a clickable directory online:

Just change the $path variable to point to your desired directory.
<? ob_start();
$path="example/Docs";
$directories = glob($path.'/*', GLOB_BRACE);
foreach($directories as $directory) {
echo '
<div class="container_16">
<div class="grid_16"><table border="1" bordercolor="#FFFFFF" class="tables">
<tr>
<td colspan="2" bordercolor="#999999" bgcolor="#f4f4f4"><span class="table-title"><em><strong>';?><?=$directory; echo'</strong></em></span>
</td>
</tr>
<tr>
<td colspan="2" bordercolor="#CCCCCC"><table border="1" bordercolor="#FFFFFF">
<tr bordercolor="#FFFFFF" class="forms">';
$files = glob($directory. '/*.{jpg,png,gif,docx,pdf,mp3}', GLOB_BRACE);
foreach($files as $file1) {
$info1 = pathinfo($file1);
$name = $info1['filename']; //index
echo "<a href=\"$file1\">$name</a><br>";
}
echo '
</table></td>
</tr>
</table>
</div><!—End Grid16—>
</div><!—End Container16—>';
}
ob_flush(); ?>
Keep exploring