123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- <?php
- /*
- * __
- * __ __/ _| ___
- * \ \ /\ / / |_ / _ \
- * \ V V /| _| __/
- * \_/\_/ |_| \___|
- *
- * Web File Explorer
- * This is free software!
- *
- * TODO
- * - Sorting
- * - Upload
- * - Download of gzipped folders
- * - REST API (?)
- * - Mobile version
- */
- # Debug
- ini_set('display_errors', 1);
- ini_set('display_startup_errors', 1);
- error_reporting(E_ALL);
- # Configuration
- // Code version
- $version = "1.1.0";
- // Set to 'false' to disable security
- $jail = false;
- # Constants
- // Folder in which the script runs
- define("FOLDER", getcwd());
- # Main variables (warning! Editing below this line is potentially dangerous!)
- // The script itself
- $url = $_SERVER["PHP_SELF"];
- $script = basename($url);
- // Working directory
- $path = getcwd();
- // Download file
- $download = null;
- // Open directory
- $directory = null;
- // Place for 'home' and 'parent directory' items
- $default = array();
- // Place for directories
- $directories = array();
- // Place for files
- $files = array();
- # Security stuff
- // Sanitize and deobfuscate qs parameters
- if (isset($_GET["f"])) {
- $download = filter_var($_GET["f"], FILTER_SANITIZE_STRING);
- $download = deobfuscate($download);
- }
- if (isset($_GET["d"])) {
- $directory = filter_var($_GET["d"], FILTER_SANITIZE_STRING);
- $directory = deobfuscate($directory);
- }
- // Canonicalized absolute pathname
- // Does not follow symbolic links
- $path = realpath($path) . "/";
- if ($directory !== null) {
- $path = realpath($directory) . "/";
- }
- // Document root directory
- $root = substr($path, 0, strlen(FOLDER));
- if ($download !== null) {
- $root = substr($download, 0, strlen(FOLDER));
- }
- // Do not access the entire file system!
- if ($jail === true && $root !== FOLDER) {
- header("Location: $url");
- exit;
- }
- # Main part
- // Download file
- if ($download !== null) {
- // See https://code-boxx.com/php-read-file/
- // Start output buffer
- ob_start();
- // HTTP headers to force download
- header("Content-Type: application/octet-stream");
- header("Content-Disposition: attachment; filename=\"" . basename($download) . "\"");
- header("Expires: 0");
- header("Cache-Control: must-revalidate");
- header("Pragma: public");
- header("Content-Length: " . filesize($download));
- // Output all the headers and stop buffering
- ob_end_flush();
- // Read and output file directly
- readfile($download);
- exit();
- }
- // Open directory
- // See https://www.php.net/manual/en/function.readdir.php
- if ($handle = opendir($path)) {
- // Get each entry
- while (false !== ($item = readdir($handle))) {
- $items[] = $item;
- }
- // Close directory
- closedir($handle);
- } else {
- // Unreadable data, or something worse
- header("Location: $url");
- exit;
- }
- // Loops through the array of items
- for ($i = 0; $i < count($items); $i++) {
- // Get item name
- $name = $items[$i];
- if ($name !== "." && $name !== "..") {
- // Directory
- if (is_dir($path . $name)) {
- if (is_readable($path . $name)) {
- $link = "?d=" . obfuscate($path . $name);
- } else {
- $link = null;
- }
- $directories[$i]["link"] = $link;
- $directories[$i]["name"] = "<b>↘</b> " . $name;
- $directories[$i]["type"] = "Directory";
- $directories[$i]["size"] = 0;
- $directories[$i]["date"] = prettydate($path . $items[$i]);
- }
- // File
- if (is_file($path . $name) && $name !== $script) {
- if (is_readable($path . $name)) {
- $link = "?f=" . obfuscate($path . $name);
- } else {
- $link = null;
- }
- $files[$i]["link"] = $link;
- $files[$i]["name"] = "<b>★</b> " . $name;
- $files[$i]["type"] = prettytype($path . $items[$i]);
- $files[$i]["size"] = prettysize(filesize($path . $items[$i]));
- $files[$i]["date"] = prettydate($path . $items[$i]);
- }
- }
- }
- // Home directory
- $default[0]["link"] = $url;
- $default[0]["name"] = "<b>⚑</b> Home";
- $default[0]["type"] = "Directory";
- $default[0]["size"] = 0;
- $default[0]["date"] = prettydate(__DIR__);
- // Parent directory
- $default[1]["link"] = $url . "?d=" . obfuscate($path . "../");
- $default[1]["name"] = "<b>↖</b> Parent directory";
- $default[1]["type"] = "Directory";
- $default[1]["size"] = 0;
- $default[1]["date"] = prettydate($path . "..");
- // Sort arrays
- $n = array_column($directories, "name");
- $d = array_column($directories, "date");
- array_multisort($n, SORT_ASC, $d, SORT_ASC, $directories);
- $n = array_column($files, "name");
- $d = array_column($files, "date");
- array_multisort($n, SORT_ASC, $d, SORT_ASC, $files);
- # Output
- // CSS3 code
- $css3 = <<<CSS3
- body{background-color:DarkSlateGrey;color:FloralWhite;font:12pt "Lucida Console","Courier New",Monospace;margin:15pt}
- a{text-decoration:none}
- a:link{color:Chartreuse}
- a:visited{color:Chartreuse}
- b{color:BlanchedAlmond;font:lighter 14pt Sans-serif}
- h1{background-color:LightSlateGray;border-radius:15pt 15pt 0 0;color:DarkSlateGrey;font:35pt Sans-serif;margin-bottom:-12pt;padding:4pt 0 16pt;text-align:center}
- footer{font:11pt Sans-serif;margin-top:10pt;text-align:center}
- footer>p{margin:0;padding-top:1pt}
- .container{background-color:DarkSlateGrey;border:3pt solid LightSlateGray;border-radius:15pt;padding:20pt 0 24pt 28pt}
- .flex-container{display:flex}
- .flex-container>div{height:16pt;line-height:16pt;overflow:hidden}
- CSS3;
- // HTML5 code
- // Useful link for SVG encoding: https://yoksel.github.io/url-encoder/
- $html5 = <<<HTML5
- <html>
- <head>
- <meta charset="UTF-8">
- <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cpath d='m 244.04381,212.92307 c -3.60647,5.42304 -11.7731,7.4057 -16.66459,12.15712 -5.85789,5.69014 -15.07376,14.52505 -27.53351,14.56409 -11.90529,0.039 -23.17775,-6.80379 -29.62542,-14.81268 -3.5757,-4.4415 -13.97271,-7.23609 -16.88903,-11.90853 -4.02131,-6.44284 -7.43438,-17.16455 -6.69618,-23.10071 0.3092,-2.48641 8.56734,-4.9239 9.8384,-2.16705 9.95411,21.58982 24.54537,25.35385 43.17247,25.35385 18.07331,0 30.55033,0.36987 41.15361,-25.02313 1.83852,-4.40292 9.05882,-0.9737 9.90873,1.80993 3.03466,9.93904 0.0296,0.007 0.0592,0.0132 0.0296,0.007 -2.51434,16.78435 -6.72367,23.11391 z m -43.81767,73.05112 c 23.78344,-9.9385 60.87929,-24.98051 85.68809,-29.20578 7.16001,-15.01208 44.20627,-46.00162 37.17641,0.62229 21.01689,14.49958 12.23597,39.78412 -26.97271,17.55322 -19.72442,1.44079 -55.38285,15.82106 -72.01094,24.1409 15.66034,7.19574 47.25562,25.91831 60.92706,33.77736 81.63685,7.3009 45.27116,32.11955 25.03291,34.52364 0.4083,10.6284 -33.73609,31.50279 -42.96578,-15.46842 -9.12497,-9.18539 -57.18179,-38.25033 -69.02042,-40.58877 -16.25551,6.11637 -53.97909,29.77844 -69.23713,42.92918 -5.11212,33.40551 -22.4687,30.42472 -39.040204,11.62746 -32.625926,-0.41169 -43.92465,-34.42716 25.842904,-35.66 13.44857,-6.89885 44.79673,-24.88779 59.07368,-31.14045 -24.9652,-10.1759 -54.35502,-19.69505 -74.10937,-24.01334 -29.075956,20.96464 -49.208492,2.25973 -26.765508,-17.36886 -2.332332,-9.71105 2.286775,-40.31952 44.170698,-3.5783 16.25235,5.43691 62.57246,23.11498 82.21031,31.84987 z m -0.67179,-140.77131 c -3.60112,6.37202 -16.27424,16.61667 -16.30496,20.33965 -0.0815,9.87553 9.74958,10.02745 16.48059,5.67642 6.89338,3.69555 16.41887,5.27089 15.9851,-5.92036 -0.16512,-4.25985 -11.39051,-12.31985 -16.16073,-20.09571 z m 33.3075,39.26688 c -3.49053,2.19568 -1.68005,10.35041 -5.48263,11.8104 -16.98182,6.52006 -38.34712,5.08379 -55.04437,0.68035 -5.27027,-1.3899 -4.64177,-11.44672 -6.60809,-12.49075 -11.77695,-6.25305 -29.10242,-7.82873 -38.35672,-15.60274 -4.22536,-3.54949 -1.70953,-27.39908 -9.24305,-31.90879 -6.89071,-4.12493 -9.65016,-19.05556 -12.07601,-31.80112 -2.41322,-12.679195 -4.25851,-38.148675 10.32399,-55.221424 14.5825,-17.07275 41.90039,-31.233748 83.70406,-31.233748 41.77609,0 69.79438,13.357592 83.60205,31.233748 13.85491,17.937329 10.06316,43.348359 7.91079,55.221424 -2.35911,13.01347 -8.68154,26.53614 -14.22102,31.44531 -5.76236,5.10669 -3.96697,29.57305 -6.41233,32.2646 -4.79997,5.2832 -27.06077,8.6607 -38.09667,15.60274 z m -97.47263,-59.74818 c -0.35747,17.81781 17.49732,26.00449 32.18065,21.01428 16.84431,-5.72462 19.00749,-35.9277 0.85722,-41.21401 -14.88584,-4.33553 -32.66291,1.51015 -33.03787,20.19973 z M 244.023,146.74927 c 19.35737,-2.42285 25.18053,-33.03141 8.40887,-41.18179 -13.50259,-6.561735 -34.33633,-1.33569 -36.23743,17.00112 -2.28851,22.07337 13.66571,25.95336 27.82856,24.18067 z' /%3E%3C/svg%3E" type="image/svg+xml" />
- <title>$script</title>
- <style>$css3</style>
- </head>
- <body>
- <h1>$script</h1>
- <div class="container">
- <div class="flex-container" style="margin-bottom: 8pt">
- <div style="flex-basis: 50%; font-weight: bolder; margin-left: 15pt">Name</a></div>
- <div style="flex-basis: 20%; font-weight: bolder">Type</div>
- <div style="flex-basis: 10%; font-weight: bolder">Size</div>
- <div style="flex-basis: 20%; font-weight: bolder">Date</div>
- </div>
- HTML5;
- echo $html5;
- foreach ($default as $value) {
- echo '<div class="flex-container">';
- echo '<div style="flex-basis: 50%"><a href=' . $value["link"] . '>' . $value["name"] . '</a></div>';
- echo '<div style="flex-basis: 20%; margin-left: 15pt">' . $value["type"] . '</div>';
- echo '<div style="flex-basis: 10%">' . $value["size"] . '</div>';
- echo '<div style="flex-basis: 20%">' . $value["date"] . '</div>';
- echo '</div>';
- }
- foreach ($directories as $value) {
- echo '<div class="flex-container">';
- if ($value["link"] === null) {
- echo '<div style="flex-basis: 50%; color: Pink">' . $value["name"] . '</div>';
- } else {
- echo '<div style="flex-basis: 50%"><a href=' . $value["link"] . '>' . $value["name"] . '</a></div>';
- }
- echo '<div style="flex-basis: 20%; margin-left: 15pt">' . $value["type"] . '</div>';
- echo '<div style="flex-basis: 10%">' . $value["size"] . '</div>';
- echo '<div style="flex-basis: 20%">' . $value["date"] . '</div>';
- echo '</div>';
- }
- foreach ($files as $value) {
- echo '<div class="flex-container">';
- if ($value["link"] === null) {
- echo '<div style="flex-basis: 50%; color: Pink">' . $value["name"] . '</div>';
- } else {
- echo '<div style="flex-basis: 50%"><a href=' . $value["link"] . '>' . $value["name"] . '</a></div>';
- }
- echo '<div style="flex-basis: 20%; margin-left: 13pt">' . $value["type"] . '</div>';
- echo '<div style="flex-basis: 10%">' . $value["size"] . '</div>';
- echo '<div style="flex-basis: 20%">' . $value["date"] . '</div>';
- echo '</div>';
- }
- $html5 = <<<HTML5
- </div>
- <footer>
- <p>Current path: <b>$path</b></p>
- <p>$script • Web File Explorer • v$version</p>
- </footer>
- </body>
- </html>
- HTML5;
- echo $html5;
- # Functions
- // String obfuscation
- // ROT-13 + Zlib compression + base64 encoding
- // See: https://stackoverflow.com/questions/2996049/how-to-compress-decompress-a-long-query-string-in-php
- function obfuscate($str)
- {
- return rtrim(strtr(base64_encode(gzdeflate(str_rot13($str), 9)), '+/', '-_'), '=');
- }
- function deobfuscate($str)
- {
- return str_rot13(gzinflate(base64_decode(strtr($str, '-_', '+/'))));
- }
- // Prettifies file size
- function prettysize($size)
- {
- if ($size < 1024) {
- $size = $size;
- } elseif (($size < 1048576) && ($size > 1023)) {
- $size = round($size / 1024, 1) . "K";
- } elseif (($size < 1073741824) && ($size > 1048575)) {
- $size = round($size / 1048576, 1) . "M";
- } else {
- $size = round($size / 1073741824, 1) . "G";
- }
- return $size;
- }
- // Prettifies file type
- function prettytype($file)
- {
- // Gets file extension
- $extn = pathinfo($file, PATHINFO_EXTENSION);
- switch ($extn) {
- case "png":
- $type = "PNG image";
- break;
- case "jpg":
- $type = "JPEG image";
- break;
- case "jpeg":
- $type = "JPEG image";
- break;
- case "svg":
- $type = "SVG image";
- break;
- case "gif":
- $type = "GIF image";
- break;
- case "ico":
- $type = "Windows icon";
- break;
- case "txt":
- $type = "Text file";
- break;
- case "log":
- $type = "Log file";
- break;
- case "htm":
- $type = "HTML file";
- break;
- case "html":
- $type = "HTML file";
- break;
- case "xhtml":
- $type = "HTML file";
- break;
- case "shtml":
- $type = "HTML file";
- break;
- case "php":
- $type = "PHP script";
- break;
- case "js":
- $type = "Javascript file";
- break;
- case "css":
- $type = "Stylesheet";
- break;
- case "pdf":
- $type = "PDF document";
- break;
- case "xls":
- $type = "Spreadsheet";
- break;
- case "xlsx":
- $type = "Spreadsheet";
- break;
- case "doc":
- $type = "Microsoft Word document";
- break;
- case "docx":
- $type = "Microsoft Word document";
- break;
- case "zip":
- $type = "ZIP archive";
- break;
- case "htaccess":
- $type = "Apache config file";
- break;
- case "exe":
- $type = "Windows executable";
- break;
- case "torrent":
- $type = "BitTorrent file";
- break;
- default:
- if ($extn !== "") {
- $type = strtoupper($extn) . " file";
- } else {
- $type = "Unknown";
- }
- break;
- }
- return $type;
- }
- // Prettifies modification date
- function prettydate($file)
- {
- return date("Y-m-d H:i:s", filemtime($file));
- }
|