1
0
forked from Thunix/www

added terminal interface as default. old website as no-js fallback

This commit is contained in:
root
2026-01-21 09:58:53 -07:00
parent 81d9ddfd03
commit 6f709886ed
14 changed files with 1569 additions and 19 deletions

234
terminal/view.php Normal file
View File

@@ -0,0 +1,234 @@
<?php
declare(strict_types=1);
// Render wiki content using the *same* parser stack as wiki.php,
require __DIR__ . '/../config.php';
require __DIR__ . '/../parsedown-1.7.3/Parsedown.php';
require __DIR__ . '/../parsedown-extra-0.7.1/ParsedownExtra.php';
$page = isset($_GET['page']) ? (string) $_GET['page'] : 'main';
if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/', $page)) {
http_response_code(400);
header('Content-Type: text/plain; charset=UTF-8');
echo "Bad page name.";
exit;
}
$contentPath = $doc_root . '/articles/' . $page . '.md';
if (!is_file($contentPath)) {
http_response_code(404);
header('Content-Type: text/plain; charset=UTF-8');
echo "Not found.";
exit;
}
$ParsedownExtra = new ParsedownExtra();
$md = file_get_contents($contentPath);
if ($md === false) {
http_response_code(500);
header('Content-Type: text/plain; charset=UTF-8');
echo "Failed to read page.";
exit;
}
$html = $ParsedownExtra->text($md);
if ($page === 'users' || $page === 'server') {
$inc = $doc_root . '/includes/' . $page . '.php';
if (is_file($inc)) {
ob_start();
require $inc;
$html .= (string) ob_get_clean();
}
}
$knownPages = [];
foreach (glob($doc_root . '/articles/*.md') ?: [] as $file) {
$slug = basename($file, '.md');
$knownPages[$slug] = true;
}
$rewriteFormActions = function (string $action): string {
$path = parse_url($action, PHP_URL_PATH);
if (!is_string($path) || $path === '') {
$path = $action;
}
$pathLower = strtolower($path);
if (!preg_match('~(^|/)(includes/(contact|signup)\.php)$~', $pathLower)) {
return $action;
}
$parts = parse_url($action);
if ($parts === false) {
if (strpos($action, 'terminal=1') !== false) {
return $action;
}
return (strpos($action, '?') !== false) ? ($action . '&terminal=1') : ($action . '?terminal=1');
}
$query = [];
if (isset($parts['query'])) {
parse_str((string) $parts['query'], $query);
}
$query['terminal'] = '1';
$queryString = http_build_query($query);
$rebuilt = '';
if (isset($parts['scheme'])) {
$rebuilt .= $parts['scheme'] . '://';
} elseif (str_starts_with($action, '//')) {
$rebuilt .= '//';
}
if (isset($parts['user'])) {
$rebuilt .= $parts['user'];
if (isset($parts['pass'])) {
$rebuilt .= ':' . $parts['pass'];
}
$rebuilt .= '@';
}
if (isset($parts['host'])) {
$rebuilt .= $parts['host'];
}
if (isset($parts['port'])) {
$rebuilt .= ':' . $parts['port'];
}
$rebuilt .= $parts['path'] ?? '';
if ($queryString !== '') {
$rebuilt .= '?' . $queryString;
}
if (isset($parts['fragment'])) {
$rebuilt .= '#' . $parts['fragment'];
}
return $rebuilt;
};
$isTerminalSuccessFormTarget = function (string $action): bool {
$path = parse_url($action, PHP_URL_PATH);
if (!is_string($path) || $path === '') {
$path = $action;
}
$pathLower = strtolower($path);
return preg_match('~(^|/)(includes/(contact|signup)\.php)$~', $pathLower) === 1;
};
$html = preg_replace_callback(
'~(<form\b[^>]*\baction\s*=\s*)(["\'])([^"\']+)(\2)~i',
function (array $m) use ($rewriteFormActions): string {
$new = $rewriteFormActions((string) $m[3]);
return $m[1] . $m[2] . $new . $m[4];
},
$html
);
$html = preg_replace_callback(
'~(<form\b[^>]*>)~i',
function (array $m) use ($rewriteFormActions, $isTerminalSuccessFormTarget): string {
$tag = $m[1];
if (preg_match('~\baction\s*=\s*(["\'])([^"\']+)\1~i', $tag, $am) !== 1) {
return $tag;
}
$action = (string) $am[2];
if ($isTerminalSuccessFormTarget($action) === false) {
return $tag;
}
$newAction = $rewriteFormActions($action);
$tag = preg_replace(
'~\baction\s*=\s*(["\'])([^"\']+)\1~i',
'action=' . $am[1] . $newAction . $am[1],
$tag,
1
);
return $tag . "\n" . '<input type="hidden" name="terminal" value="1">';
},
$html
);
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML(
'<!doctype html><html><head><meta charset="utf-8"></head><body><div id="content">' . $html . '</div></body></html>',
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
);
foreach ($dom->getElementsByTagName('a') as $a) {
$href = $a->getAttribute('href');
if ($href === '' || str_starts_with($href, '#')) {
continue;
}
if (preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*:/', $href) === 1) {
$a->setAttribute('target', '_blank');
$a->setAttribute('rel', 'noopener');
continue;
}
if (str_starts_with($href, '/')) {
$path = parse_url($href, PHP_URL_PATH) ?? '';
$slug = ltrim($path, '/');
if ($slug !== '' && isset($knownPages[$slug])) {
$a->setAttribute('href', './view.php?page=' . rawurlencode($slug));
continue;
}
$a->setAttribute('target', '_blank');
$a->setAttribute('rel', 'noopener');
continue;
}
$a->setAttribute('target', '_blank');
$a->setAttribute('rel', 'noopener');
}
foreach ($dom->getElementsByTagName('form') as $form) {
$action = $form->getAttribute('action');
if ($action !== '') {
$form->setAttribute('action', $rewriteFormActions($action));
}
}
$finalHtml = $dom->saveHTML();
libxml_clear_errors();
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: no-referrer');
header('Content-Type: text/html; charset=UTF-8');
?><!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo htmlspecialchars($site_name . ' - ' . $page, ENT_QUOTES, 'UTF-8'); ?></title>
<link rel="stylesheet" type="text/css" href="<?php echo htmlspecialchars($site_root . '/includes/terminal.css', ENT_QUOTES, 'UTF-8'); ?>">
</head>
<body>
<?php
$dom2 = new DOMDocument();
libxml_use_internal_errors(true);
$dom2->loadHTML($finalHtml);
libxml_clear_errors();
$content = $dom2->getElementById('content');
if ($content === null) {
echo $finalHtml;
} else {
echo $dom2->saveHTML($content);
}
?>
</body>
</html>