. ================================================================ */ /* Okay, I admit it, this entire script is just an excuse to try PHP's heredoc syntax. */ // **** EXTERNAL BITS (you can touch 'em) $root = dirname(__FILE__); // we assume root to be the location of this script // A list of files to never index, relative to our ROOT $blacklist = [ '/'.basename(__FILE__) // hide ourself ]; // Glob-style search pattern for our files in the requested directory $glob = "*"; // Fields to render per file, anything supported by stat() can be defined here $fields = [ "name" => "Filename", "size" => "Size", "mtime" => "Last Modified" ]; // date format for time related fields $date = "Y-m-d H:i:s"; // Modify this for styling. I didn't want separate files, so ugliness abounds $css = << 1) { ele[sel].className = ""; ele[--sel].className = "selected"; } }}, {key: [40, 74], func: function() { // down var ele = document.getElementsByTagName("tr"); if (sel < ele.length-1) { ele[sel].className = ""; ele[++sel].className = "selected"; } }}, {key: [37, 72], func: function() { // left var ele = document.getElementsByTagName("tr"); if (ele.length > 1 && ele[1].getElementsByTagName("A")[0].innerHTML == "..") ele[1].getElementsByTagName("A")[0].onclick(); }}, {key: [39, 76], func: function() { // right if (sel > 0) document.getElementsByTagName("TR")[sel].getElementsByTagName("A")[0].onclick(); }} ]; document.onkeydown = function(event) { if (event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) return; for (var i = 0; i < bind.length; i++) { for (var k = 0; k < bind[i].key.length; k++) { if (event.which == bind[i].key[k]) bind[i].func(); } } }; var parseContent = function() { var l = document.getElementsByTagName('A'); var i; for (i = 0; i < l.length; i++) { l[i].onclick = function() { if (this.className == "dir" || this.className == "parent") { this.className = "load"; swapContent(window.location.href+this.getAttribute('href')); return false; } else { window.open(this.href); return false; }}; } }; var swapContent = function(target) { var req = new XMLHttpRequest(); req.open("POST", target, true); req.onreadystatechange = (function(req, target) { return function() { switch (req.readyState) { case 4: document.getElementsByTagName("body")[0].innerHTML = req.responseText; window.history.pushState({content: req.responseText, url: target, title: document.getElementsByTagName("H1")[0].innerHTML}, target, target); document.title = document.getElementsByTagName("H1")[0].innerHTML; parseContent(); if (sel != 0) { sel = 0; bind[1].func(); } break; } }})(req, target); req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); req.send("p=true"); }; var popState = function(event) { if (event.state == null) return; document.getElementsByTagName("body")[0].innerHTML = event.state.content; document.title = event.state.title; parseContent(); }; JS; // **** INTERNAL BITS $VERSION = "ARK 1.0"; // ---- INIT LOGIC $mode = 200; // Default mode of serve file $index = []; // array of files to index $dindex = []; // array of directories to index // inherit $dir from $_GET["d"] or assign to "/" $dir = (($_GET["d"]) ? '/'.$_GET["d"] : "/"); // Probably pointless file path sanitization. $path = realpath($root."/".$dir)."/"; // Due to realpath, the following should resolve only if the requested $dir does not go above the path of this script. if (($root_pos = strpos($path, $root)) === FALSE) { $mode = 403; } else if (!file_exists($path)) { $mode = 404; } else { // seems we're good, let's populate $index and $dindex, then combine them if (is_dir($path)) { // It seems wiser to generate two separate arrays and combine rather than to use unshift and introduce reindexing each pass. foreach (glob($path.$glob) as $file) { if (in_array($dir.basename($file), $blacklist)) continue; $type = filetype($file); if ($type == "dir") { $dindex[$file] = stat($file); $dindex[$file]["type"] = $type; $dindex[$file]["name"] = basename($file)."/"; } else { $index[$file] = stat($file); $index[$file]["type"] = $type; $index[$file]["name"] = basename($file); $index[$file]["ext"] = pathinfo($file, PATHINFO_EXTENSION); } } $index = $dindex + $index; } } // **** RENDERING // ---- BEGIN HEAD if (!isset($_POST['p'])) { echo << Index of $dir HEAD; } // ---- BEGIN BODY CONTENT switch($mode) { case 200: if (is_dir($path)) { // serve index echo "

Index of $dir

\n"; echo "\n"; echo ""; foreach ($fields as $fkey=>$fvalue) { echo ""; } echo "\n"; if ($dir != "/") { echo ""; foreach ($fields as $fkey=>$fvalue) { if ($fkey == "name") { echo ""; } else { echo ""; } } echo "\n"; } foreach ($index as $key=>$value) { echo ""; foreach ($fields as $fkey=>$fvalue) { echo ""; } echo "\n"; } echo "
".$fvalue."
"; echo ""; echo ".."; echo "
"; if ($fkey == "name") { echo ""; echo $value[$fkey].""; } else if (strstr($fkey, "time")) { echo date($date, $value[$fkey]); } else if ($fkey == "size") { if ($value[$fkey] >= 1 << 30) { echo round($value[$fkey] / (1<<30), 2).'GB'; } else if ($value[$fkey] >= 1 << 20) { echo round($value[$fkey] / (1<<20), 2).'MB'; } else if ($value[$fkey] >= 1 << 10) { echo round($value[$fkey] / (1<<10), 2).'KB'; } else { echo $value[$fkey].' bytes'; } } else { echo $value[$fkey]; } echo "
\n"; } else { // serve file } break; case 403: echo '

403: Access Denied

'; echo "Return to previous page\n"; break; case 404: echo '

404: No such file or directory

'; echo "Return to previous page\n"; break; } echo "Generated by $VERSION"; // ---- BEGIN FOOT if (!isset($_POST['p'])) { echo << FOOT; } ?>