File size: 4.54Kb
<?php
/**
* CMS: LaiCMS (v1.0 Edition 2026)
* File: admin/logs.php
* Оптимизация: Ultra-Compact Event Stream
*/
require_once '../system/db.php';
require_once '../system/functions.php';
if (!isAdmin()) { die("403 Forbidden"); }
$log_file = '../system/logs.json';
// Очистка логов (Safe)
if (isset($_POST['clear_logs']) && check_csrf($_POST['csrf_token'])) {
file_put_contents($log_file, json_encode([]));
header("Location: logs.php?status=cleared"); exit;
}
// Чтение логов
$logs = file_exists($log_file) ? (json_decode(file_get_contents($log_file), true) ?: []) : [];
$logs = array_reverse($logs);
$page_title = "Logs — LaiCMS";
include '../system/header.php';
?>
<style>
.logs-wrap { padding: 10px; max-width: 100%; }
/* Компактная лента событий */
.log-item {
background: var(--pico-card-background-color);
border: 1px solid var(--pico-muted-border-color);
border-radius: 12px;
padding: 10px;
margin-bottom: 8px;
display: flex;
flex-direction: column;
gap: 5px;
transition: 0.2s;
}
.log-item:hover { border-color: var(--pico-primary); }
/* Мета-данные в одну строку */
.log-meta { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 5px; }
/* Типы событий */
.type-tag { font-size: 0.6rem; font-weight: 800; padding: 2px 6px; border-radius: 4px; text-transform: uppercase; color: #fff; }
.type-error { background: #e74c3c; box-shadow: 0 0 8px #e74c3c44; }
.type-security { background: #9b59b6; }
.type-success { background: #2ecc71; }
.type-info { background: #3498db; }
.log-msg { font-size: 0.8rem; line-height: 1.4; color: var(--pico-contrast); }
.log-footer { display: flex; gap: 10px; font-size: 0.7rem; opacity: 0.6; }
@media (min-width: 768px) {
.log-item { flex-direction: row; align-items: center; gap: 15px; }
.log-meta { border-bottom: none; padding-bottom: 0; min-width: 180px; }
.log-msg { flex: 1; }
}
</style>
<div class="logs-wrap">
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 1.5rem;">
<hgroup style="margin:0;">
<h3 style="margin:0;"><i class="fa-solid fa-receipt"></i> Журнал</h3>
<p style="font-size:0.7rem; opacity:0.7;">Всего записей: <?= count($logs) ?></p>
</hgroup>
<form method="POST" onsubmit="return confirm('Удалить всю историю?')">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<button type="submit" name="clear_logs" class="outline secondary btn-sm" style="margin:0;">
<i class="fa-solid fa-eraser"></i> <span class="hide-mobile">Очистить</span>
</button>
</form>
</div>
<input type="text" id="logSearch" placeholder="Фильтр по IP, юзеру или тексту..." onkeyup="filterLogs()" style="margin-bottom: 1rem; font-size: 0.85rem;">
<div id="logsContainer">
<?php if (empty($logs)): ?>
<article style="text-align:center;">Журнал пуст</article>
<?php else: ?>
<?php foreach ($logs as $entry):
$type = $entry['type'] ?? 'info';
?>
<div class="log-item" data-text="<?= strtolower(_e($entry['user'].$entry['message'].$entry['ip'])) ?>">
<div class="log-meta">
<span class="type-tag type-<?= $type ?>"><?= $type ?></span>
<small style="font-size: 0.65rem; opacity: 0.5;"><?= date('H:i:s d.m', strtotime($entry['date'])) ?></small>
</div>
<div class="log-msg">
<strong><?= _e($entry['user'] ?? 'Guest') ?>:</strong> <?= _e($entry['message']) ?>
</div>
<div class="log-footer">
<span><i class="fa-solid fa-network-wired"></i> <?= _e($entry['ip']) ?></span>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<script>
function filterLogs() {
const query = document.getElementById("logSearch").value.toLowerCase();
document.querySelectorAll(".log-item").forEach(item => {
item.style.display = item.getAttribute("data-text").includes(query) ? "flex" : "none";
});
}
</script>
<?php include '../system/footer.php'; ?>