Add request logging, bot blocking, and admin log viewer
This commit is contained in:
@@ -131,6 +131,10 @@ switch ($route) {
|
||||
handleGuide($auth, $appConfig);
|
||||
break;
|
||||
|
||||
case 'logs':
|
||||
handleLogs($auth, $appConfig);
|
||||
break;
|
||||
|
||||
case 'users':
|
||||
handleUsers($auth, $appConfig);
|
||||
break;
|
||||
@@ -1451,6 +1455,66 @@ function handleGuide(AdminAuth $auth, array $config): void
|
||||
require __DIR__ . '/../admin/templates/layout.php';
|
||||
}
|
||||
|
||||
function handleLogs(AdminAuth $auth, array $config): void
|
||||
{
|
||||
$user = $auth->getCurrentUser();
|
||||
$csrf = $auth->getCsrfToken();
|
||||
|
||||
$activeTab = $_GET['tab'] ?? 'admin';
|
||||
if (!in_array($activeTab, ['admin', 'requests'])) $activeTab = 'admin';
|
||||
|
||||
$adminLogFile = $config['log_file'];
|
||||
$requestLogFile = $config['request_log'];
|
||||
|
||||
// Clear
|
||||
if (isset($_GET['clear'])) {
|
||||
$target = $activeTab === 'admin' ? $adminLogFile : $requestLogFile;
|
||||
@file_put_contents($target, '');
|
||||
$message = $activeTab === 'admin' ? 'Activiteitenlog gewist.' : 'Requestlog gewist.';
|
||||
header('Location: /admin/logs?tab=' . $activeTab);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Download
|
||||
if (isset($_GET['download'])) {
|
||||
$target = $activeTab === 'admin' ? $adminLogFile : $requestLogFile;
|
||||
$filename = $activeTab === 'admin' ? 'admin.log' : 'requests.log';
|
||||
if (file_exists($target)) {
|
||||
header('Content-Type: text/plain');
|
||||
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||
header('Content-Length: ' . filesize($target));
|
||||
readfile($target);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Read admin log
|
||||
$adminLogs = [];
|
||||
if (file_exists($adminLogFile)) {
|
||||
$lines = file($adminLogFile);
|
||||
$lines = array_slice($lines, -200);
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/^\[([^\]]+)\] \[([^\]]+)\] \[([^\]]+)\] (.+)$/', trim($line), $m)) {
|
||||
$adminLogs[] = [
|
||||
'time' => $m[1],
|
||||
'level' => strtolower($m[2]),
|
||||
'ip' => $m[3],
|
||||
'message' => $m[4],
|
||||
];
|
||||
}
|
||||
}
|
||||
$adminLogs = array_reverse($adminLogs);
|
||||
}
|
||||
|
||||
// Read request log
|
||||
require_once __DIR__ . '/../cms/core/class/RequestLogger.php';
|
||||
$requestLogger = new RequestLogger($requestLogFile);
|
||||
$requestLogs = $requestLogger->getLogs(200);
|
||||
|
||||
$route = 'logs';
|
||||
require __DIR__ . '/../admin/templates/layout.php';
|
||||
}
|
||||
|
||||
// --- Frontmatter helpers ---
|
||||
|
||||
function parseFrontmatterField(string $content, string $key, string $default = ''): string
|
||||
|
||||
@@ -89,5 +89,27 @@ if (strpos($path, '/content/') === 0) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Bot detection — block known bots/AI scrapers early
|
||||
if (RequestLogger::detectBot() !== null) {
|
||||
http_response_code(403);
|
||||
echo '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>403 Forbidden</title><meta name="robots" content="noindex,nofollow"></head><body><h1>403 Forbidden</h1><p>Access denied.</p></body></html>';
|
||||
exit;
|
||||
}
|
||||
|
||||
$cms = new CodePressCMS($config);
|
||||
|
||||
// Log page view (not for media/assets)
|
||||
if (!str_starts_with($path, '/-media/') && !str_starts_with($path, '/-assets/')) {
|
||||
$requestLogFile = dirname(__DIR__) . '/admin/storage/logs/requests.log';
|
||||
$logger = new RequestLogger($requestLogFile);
|
||||
$logger->log(
|
||||
$_GET['page'] ?? $config['default_page'] ?? 'index',
|
||||
$_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'] ?? 'cli',
|
||||
$_SERVER['HTTP_USER_AGENT'] ?? '',
|
||||
$_SERVER['HTTP_REFERER'] ?? '',
|
||||
$_SERVER['HTTP_HOST'] ?? '',
|
||||
$_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
$cms->render();
|
||||
Reference in New Issue
Block a user