Try It
Example folder listing:
https://centerkey.com/files
<!doctype html> | |
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> | |
<!-- Folder Listing --> | |
<!-- v1.2.0 (June 12, 2023) --> | |
<!-- A good looking replacement for Directory Listings (Options +Indexes): --> | |
<!-- Rename this file to "index.php" and copy it into a web server --> | |
<!-- directory to enable browsing on that directory. --> | |
<!-- Requirement: --> | |
<!-- Apache HTTP Server Project with php_module enabled --> | |
<!-- (see: /usr/local/etc/httpd/httpd.conf) --> | |
<!-- Example page: --> | |
<!-- https://centerkey.com/files --> | |
<!-- WTFPL --> | |
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> | |
<html lang=en> | |
<head> | |
<meta charset=utf-8> | |
<meta name=viewport content="width=device-width, initial-scale=1"> | |
<meta name=robots content="index, follow"> | |
<meta name=description content="Folder listing for <?=basename(__DIR__)?>"> | |
<meta name=apple-mobile-web-app-title content="<?=basename(__DIR__)?>"> | |
<title>Folder: <?=basename(__DIR__)?></title> | |
<link rel=icon href=https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5/svgs/solid/folder.svg color=darkgoldenrod> | |
<link rel=mask-icon href=https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5/svgs/solid/folder.svg color=darkgoldenrod> | |
<link rel=apple-touch-icon href=https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5/svgs/solid/folder.svg color=darkgoldenrod> | |
<link rel=preconnect href=https://fonts.googleapis.com> | |
<link rel=preconnect href=https://fonts.gstatic.com crossorigin> | |
<link rel=stylesheet href=https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5/css/all.min.css> | |
<link rel=stylesheet href=https://cdn.jsdelivr.net/npm/dna-engine@3.0/dist/dna-engine.css> | |
<link rel=stylesheet href=https://cdn.jsdelivr.net/npm/web-ignition@2.1/dist/reset.min.css> | |
<style> | |
body { margin: 0px 20px; } | |
body >main { min-height: auto; } | |
body >main h1 { color: cadetblue; } | |
body >main a { border-color: cadetblue; } | |
body >main a { outline-color: white; } /* workaround for ghost line on hover in safari */ | |
body >main a:hover { background-color: cadetblue; outline-color: cadetblue; } | |
body >main ul.simple-text { margin: 0px 0px 30px 15px; } | |
body >main ul.simple-text li { display: flex; align-items: center; margin-bottom: 10px; } | |
body >main ul.simple-text li i.font-icon { width: 1.8em; text-align: center; color: darkslateblue; } | |
body >main ul.simple-text li i.font-icon[data-icon=arrow-alt-circle-up] { color: dimgray; } | |
body >main ul.simple-text li i.font-icon[data-icon=folder] { color: darkgoldenrod; } | |
body >main ul.simple-text li i.font-icon[data-icon=external-link-square-alt] { color: brown; } | |
body >main p a { margin-right: 8px; } | |
@media (max-width: 667px) { /* selects iPhone 6/6s/7/8/SE2/SE3 landscape and anything narrower */ | |
body { margin: 0px; } | |
body >main h1 { font-size: 1.7em; } | |
body >main ul.simple-text { margin-left: 0px; } | |
} | |
</style> | |
<script defer src=https://cdn.jsdelivr.net/npm/dna-engine@3.0/dist/dna-engine.min.js></script> | |
<script defer src=https://cdn.jsdelivr.net/npm/web-ignition@2.1/dist/lib-x.min.js></script> | |
<script data-on-load=displayPath> | |
const displayPath = () => { | |
// Show the URL of the current folder. | |
const subheader = globalThis.document.querySelector('main >h2'); | |
const homeIcon = globalThis.document.querySelector('.home-link'); | |
subheader.textContent = globalThis.location.origin + globalThis.location.pathname; | |
homeIcon.href = globalThis.location.origin; | |
}; | |
</script> | |
<?php | |
if (!function_exists("str_ends_with")) { | |
function str_ends_with($haystack, $needle) { | |
return substr($haystack, -strlen($needle)) === $needle; | |
} | |
} | |
function showFile($file) { | |
// Don't display hidden files, php files, link files, or folders. | |
$extension = pathinfo($file, PATHINFO_EXTENSION); | |
$extOk = !in_array($extension, array("php")); | |
$isLink = str_ends_with($file, ".link.md"); | |
return !is_dir($file) && $file[0] !== "." && $file !== "error_log" && $extOk && !$isLink; | |
} | |
function fileIcon($fileExtension) { | |
$fileTypes = array( | |
"gif" => "file-image", | |
"html" => "file-code", | |
"jpeg" => "file-image", | |
"jpg" => "file-image", | |
"md" => "file-pen", | |
"mp3" => "file-audio", | |
"pdf" => "file-pdf", | |
"png" => "file-image", | |
"svg" => "file-image", | |
"txt" => "file-lines", | |
"xml" => "file-code", | |
"zip" => "file-zipper", | |
); | |
return array_key_exists($fileExtension, $fileTypes) ? $fileTypes[$fileExtension] : "file"; | |
}; | |
function toHtml($file) { | |
// Create the <li> string to render a line representing a file or folder. | |
$isFolder = is_dir($file); | |
$icon = $isFolder ? "folder" : fileIcon(pathinfo($file, PATHINFO_EXTENSION)); | |
$title = $file; | |
if (!$isFolder && str_ends_with($file, ".link.md")) { | |
// Looks for the ".link.md" extension and reads the markdown syntax for a | |
// hyperlink. For example, the file "example-website.link.md" could have | |
// one line of text like "[Click me](https://example.org)". | |
$icon = "external-link-square-alt"; | |
$md = preg_split("/[\[\]()]/", htmlspecialchars(file_get_contents($file))); | |
$file = $md[3]; | |
$url = parse_url($file); | |
$relLinkHost = $_SERVER["HTTP_HOST"] ?: $_SERVER["SERVER_NAME"]; | |
$host = isset($url["host"]) ? $url["host"] : $relLinkHost; | |
$title = $md[1] . " [" . $host . "]"; | |
} | |
return "<li><a href='$file'><i data-icon=$icon></i></a> <a href='$file'>$title</a></li>"; | |
} | |
?> | |
</head> | |
<body> | |
<main> | |
<h1>Folder Listing</h1> | |
<h2></h2> | |
<ul class=simple-text> | |
<li><a href=..><i data-icon=arrow-alt-circle-up></i></a> <a href=..>Parent folder</a></li> | |
<?=implode(PHP_EOL, array_map("toHtml", glob("*", GLOB_ONLYDIR)))?> | |
<?=implode(PHP_EOL, array_map("toHtml", glob("*.link.md")))?> | |
<?=implode(PHP_EOL, array_map("toHtml", array_filter(glob("*"), "showFile")))?> | |
</ul> | |
<p> | |
<a href=# class=home-link><i data-icon=home></i></a> | |
<a href=https://gist.github.com/dpilafian/930e1677d0c08eed3c39f04d32d7bf19><i data-brand=github-alt></i></a> | |
</p> | |
</main> | |
</body> | |
</html> |
Example folder listing:
https://centerkey.com/files
#!/bin/bash | |
################## | |
# Folder Listing # | |
# WTFPL # | |
################## | |
# To make this file runnable: | |
# $ chmod +x *.sh.command | |
banner="Folder Listing" | |
projectHome=$(cd $(dirname $0); pwd) | |
apacheCfg=/usr/local/etc/httpd | |
apacheLog=/usr/local/var/log/httpd/error_log | |
webDocRoot=$(grep ^DocumentRoot $apacheCfg/httpd.conf | awk -F'"' '{ print $2 }') | |
displayIntro() { | |
cd $projectHome | |
echo | |
echo $banner | |
echo $(echo $banner | sed s/./=/g) | |
pwd | |
version=$(grep "<\!\-\- v" *.php | awk '{ print $2 }') | |
echo $version | |
echo | |
} | |
lintPhp() { | |
cd $projectHome | |
echo "Linting:" | |
php --syntax-check *.php | |
echo | |
} | |
publishWebFiles() { | |
cd $projectHome | |
publishSite=$webDocRoot/centerkey.com | |
publishFolder=$publishSite/files | |
publish() { | |
echo "Publishing:" | |
mkdir -p $publishFolder | |
cp -v *.php $publishFolder/index.php | |
echo | |
} | |
test -w $publishSite && publish | |
} | |
launchBrowser() { | |
cd $projectHome | |
url=https://centerkey.com/files | |
test -w $publishSite && url=http://localhost/centerkey.com/files | |
echo "Opening:" | |
echo $url | |
sleep 2 | |
open $url | |
echo | |
} | |
displayIntro | |
lintPhp | |
publishWebFiles | |
launchBrowser |