<?php
require_once('config.php');
/**
* @author Gernot WALZL
*/
class FileSystemObject {
function is_hidden($hidden_dirnames, $dir) {
$result = false;
if (is_array($hidden_dirnames)) {
if (in_array($dir, $hidden_dirnames)) {
$result = true;
}
}
return $result;
}
function read_dirs($path='.', $hidden_dirnames=null) {
$result = null;
if ($handle = opendir(dirname(__FILE__).'/'.$path)) {
$result = array();
while (false !== ($entry = readdir($handle))) {
if (substr($entry,0,1) != '.') {
if (is_dir($path.'/'.$entry)) {
if (!$this->is_hidden($hidden_dirnames, $entry)) {
array_push($result, $path.'/'.$entry);
}
}
}
}
closedir($handle);
sort($result);
}
return $result;
}
function read_files($path='.') {
$result = null;
if ($handle = opendir(dirname(__FILE__).'/'.$path)) {
$result = array();
while (false !== ($entry = readdir($handle))) {
if (substr($entry,0,1) != '.') {
if (is_file($path.'/'.$entry) &&
is_readable($path.'/'.$entry)) {
array_push($result, $path.'/'.$entry);
}
}
}
closedir($handle);
sort($result);
}
return $result;
}
function get_file_ext($filepath) {
$result = null;
$pathinfo = pathinfo($filepath);
if (isset($pathinfo['extension'])) {
$result = $pathinfo['extension'];
}
return $result;
}
function read_preview($filepath, $num_lines) {
$result = '';
$comment = null;
$handle = fopen($filepath, 'r');
$cnt = 0;
while ($cnt < $num_lines && !feof($handle)) {
$buffer = fgets($handle, 4096);
if ($cnt == 0 && substr($buffer,0,2) == '#!') {
$comment = '#';
} else {
if (empty($comment)) {
$buffer = trim($buffer);
if (strlen($buffer) > 0) {
$result .= $buffer."\n";
$cnt += 1;
}
} else {
if (substr($buffer,0,strlen($comment)) == $comment) {
$buffer = trim(str_replace($comment, '', $buffer));
if (strlen($buffer) > 0) {
$result .= $buffer."\n";
$cnt += 1;
}
}
}
}
}
fclose($handle);
return $result;
}
function exists_file($path, $filenames) {
$result = false;
foreach ($filenames as $filename) {
if (is_readable($path.'/'.$filename)) {
$result = true;
break;
}
}
return $result;
}
}
/**
* @author Gernot WALZL
*/
class HTML {
protected $config = null;
protected $fso = null;
protected $list_files = true;
function __construct($config, $fso) {
$this->config = $config;
$this->fso = $fso;
$list_files = $this->config->list_files;
}
function println($msg='') {
print($msg."\n");
}
function print_head($nav='.') {
$this->println('<!DOCTYPE html>');
$this->println('<html lang="en">');
$this->println('<head>');
$this->println('<meta charset="utf-8" />');
$title = $this->config->title;
if (!empty($nav)) {
$subtitle = str_replace('_', ' ', basename($nav));
if (substr($subtitle, 0, 1) != '.') {
$title = $subtitle.' - '.$title;
}
}
$this->println('<title>'.$title.'</title>');
if (!empty($this->config->meta_description)) {
$this->println('<meta name="description" content="'.
$this->config->meta_description.'" />');
}
if (!empty($this->config->meta_keywords)) {
$this->println('<meta name="keywords" content="'.
$this->config->meta_keywords.'" />');
}
$this->println('<meta name="viewport" '.
'content="width=device-width, initial-scale=1.0" />');
if (!empty($this->config->stylesheets)) {
foreach ($this->config->stylesheets as $stylesheet) {
$href = $stylesheet.'?mtime='.filemtime($stylesheet);
$this->println('<link rel="stylesheet" href="'.$href.'" />');
}
}
if (!empty($this->config->rss)) {
$this->println('<link rel="alternate" type="application/rss+xml" '.
'title="RSS Feed" href="'.$this->config->rss.'" />');
}
if (!empty($this->config->scripts)) {
foreach ($this->config->scripts as $script) {
$src = $script.'?mtime='.filemtime($script);
$integrity = 'sha256-'.base64_encode(
hash_file('sha256', $script, true));
$this->println('<script src="'.$src.'" '.
'integrity="'.$integrity.'"></script>');
}
}
$this->println('</head>');
$this->println('<body>');
if (isset($this->config->header)) {
if (is_readable($this->config->header)) {
$this->println('<header>');
readfile($this->config->header);
$this->println('</header>');
}
}
}
function print_foot() {
if (isset($this->config->footer)) {
if (is_readable($this->config->footer)) {
$this->println('<footer>');
readfile($this->config->footer);
$this->println('</footer>');
}
}
$this->println('</body>');
$this->println('</html>');
}
function print_rootnode() {
print('<a href=".">'.$this->config->rootnode.'</a>');
}
function print_dirs_rec($nav, $path='.') {
$dirs = $this->fso->read_dirs($path, $this->config->hidden_dirnames);
if (!empty($dirs)) {
$this->println();
$this->println('<ul>');
foreach ($dirs as $dir) {
print('<li>');
$name = str_replace('_', ' ', basename($dir));
if ($this->fso->exists_file($dir, $this->config->indices)) {
print('<a href="'.$dir.'/">'.$name.'</a>');
} else {
if ($nav === $dir || $nav === substr($dir, 2)) {
print('<a class="selected" href="'.$_SERVER['PHP_SELF'].
'?nav='.urlencode($dir).'">'.$name.'</a>');
} else {
print('<a href="'.$_SERVER['PHP_SELF'].
'?nav='.urlencode($dir).'">'.$name.'</a>');
}
$this->print_dirs_rec($nav, $dir);
}
$this->println('</li>');
}
$this->println('</ul>');
}
}
function print_navigation($nav='.') {
$this->println('<div id="navigation">');
$this->println('<a href="#navigation" id="show_nav">Navigation</a>');
$this->println('<nav>');
$this->print_rootnode();
$this->print_dirs_rec($nav);
$this->println('</nav>');
$this->println('</div>');
}
function print_advertisement($_filepath) {
$this->println('<div id="advertisement">');
$fileext = $this->fso->get_file_ext($_filepath);
if ($fileext == 'php') {
include($_filepath);
} else {
$filecontents = file_get_contents($_filepath);
print($filecontents);
}
$this->println('</div>');
}
function print_sidebar($nav='.') {
$this->println('<div id="sidebar">');
$this->print_navigation($nav);
if (isset($this->config->advertisement)) {
if (is_readable($this->config->advertisement)) {
$this->print_advertisement($this->config->advertisement);
}
}
$this->println('</div>');
}
function print_readme($_filepath) {
$_path = dirname($_filepath);
$fileext = $this->fso->get_file_ext($_filepath);
if ($fileext == 'php') {
$_list_files = $this->list_files;
// Shared variables with included php script:
// $_path, $_filepath, $_list_files
include($_filepath);
$this->list_files = $_list_files;
} else {
$filecontents = file_get_contents($_filepath);
$filecontents = str_replace('href="./', 'href="'.$_path.'/',
$filecontents);
$filecontents = str_replace('src="./', 'src="'.$_path.'/',
$filecontents);
print($filecontents);
}
}
function print_readmes($path='.') {
if ($this->fso->exists_file($path, $this->config->readmes)) {
$this->println('<div id="readme">');
foreach ($this->config->readmes as $readme) {
$filepath = $path.'/'.$readme;
if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'],0,2);
$pathinfo = pathinfo($filepath);
$filepath_lang = $path.'/'.$pathinfo['filename'].'.'.$lang;
if (isset($pathinfo['extension'])) {
$filepath_lang .= '.'.$pathinfo['extension'];
}
if (is_file($filepath_lang) and
is_readable($filepath_lang)) {
$this->print_readme($filepath_lang);
} else if (is_file($filepath) and
is_readable($filepath)) {
$this->print_readme($filepath);
}
} else if (is_file($filepath) and
is_readable($filepath)) {
$this->print_readme($filepath);
}
}
$this->println('</div>');
}
}
function print_tr_file($filepath) {
$this->println('<tr>');
$this->println('<td class="filename">'.
'<a href="'.$filepath.'" target="_blank">'.
basename($filepath).'</a></td>');
$fileapps = '';
$ext = pathinfo($filepath, PATHINFO_EXTENSION);
if (array_key_exists($ext, $this->config->file_apps)) {
$apps = $this->config->file_apps[$ext];
foreach ($apps as $app) {
if (!empty($fileapps)) {
$fileapps .= ' ';
}
$fileapps .= '<a href="'.$app['url'].
urlencode($filepath).'" target="_blank">'.
$app['label'].'</a>';
}
}
$this->println('<td class="fileapps">'.$fileapps.'</td>');
$filedate_hr = date('Y-m-d',filemtime($filepath));
$this->println('<td class="filedate">'.$filedate_hr.'</td>');
$size = filesize($filepath);
$mod = 1024;
$units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
for ($cnt = 0; $size > $mod; $cnt++) {
$size /= $mod;
}
$filesize_hr = round($size, 1).' '.$units[$cnt];
$this->println('<td class="filesize">'.$filesize_hr.'</td>');
$this->println('</tr>');
}
function print_tr_filepreview($preview) {
$preview_html = htmlentities($preview);
$this->println('<tr>');
$this->println('<td colspan="4" class="filepreview">');
print('<pre>');
print($preview_html);
$this->println('</pre>');
$this->println('</td>');
$this->println('</tr>');
}
function print_files($path='.') {
$files = $this->fso->read_files($path);
if (!empty($files)) {
$this->println('<div id="files">');
$this->println('<table class="files">');
foreach ($files as $filepath) {
$this->println('<tbody class="file">');
$this->print_tr_file($filepath);
if (in_array($this->fso->get_file_ext($filepath),
$this->config->preview_file_exts)) {
$preview = $this->fso->read_preview($filepath,
$this->config->preview_size);
if (!empty($preview)) {
$this->print_tr_filepreview($preview);
}
}
$this->println('</tbody>');
}
$this->println('</table>');
$this->println('</div>');
}
}
function print_content($nav='.') {
$this->println('<div id="content">');
if (file_exists(dirname(__FILE__).'/'.$nav)) {
$name = str_replace('_', ' ', basename($nav));
if ($name != '.') {
$this->println('<h2>'.$name.'</h2>');
}
$this->print_readmes($nav);
if ($this->list_files) {
$this->print_files($nav);
}
} else {
$this->println('<p>Error: Variable nav="'.$nav.'" is invalid.</p>');
}
$this->println('</div>');
}
function print_not_found($url) {
$this->println('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">');
$this->println('<html><head>');
$this->println('<title>404 Not Found</title>');
$this->println('</head><body>');
$this->println('<h1>Not Found</h1>');
$this->println('<p>The requested URL '.$url.' was not found on this server.</p>');
$this->println('</body></html>');
}
}
if (!empty($_SERVER['PATH_INFO'])) {
header("HTTP/1.0 404 Not Found");
}
$nav = '.';
if (!empty($_GET['nav'])) {
$nav = $_GET['nav'];
if (stristr($nav, '..')) {
$nav = '.';
}
if (!file_exists(dirname(__FILE__).'/'.$nav)) {
$nav = '.';
}
}
$config = new Config();
$fso = new FileSystemObject();
$html = new HTML($config, $fso);
if (!empty($_SERVER['PATH_INFO'])) {
$html->print_not_found($_SERVER['PHP_SELF']);
exit();
}
$html->print_head($nav);
$html->print_sidebar($nav);
$html->print_content($nav);
$html->print_foot();
?>