PHP_AdminTool_Projekt/public/views/logs.php
2025-12-17 15:50:05 +01:00

166 lines
7.7 KiB
PHP

<?php
declare(strict_types=1);
/**
* Log Viewer (Ansicht).
*
* Erwartete Variablen:
* @var array<int, array{name:string, size:int, mtime:int}> $files
* @var string $selectedFile
* @var array{name:string, size:int, mtime:int}|null $fileMeta
* @var array<int, array{ts:string|null, level:string|null, message:string, context:array<string,mixed>|null, raw:string}> $entries
* @var string $filterLevel
* @var string $searchQuery
* @var int $lines
* @var string|null $error
*/
?>
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">Log Viewer</h1>
</div>
<?php if (!empty($error)) : ?>
<div class="alert alert-danger" role="alert">
<?php echo htmlspecialchars((string)$error, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</div>
<?php endif; ?>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Filter</h6>
</div>
<div class="card-body">
<form method="get" action="../index.php">
<input type="hidden" name="route" value="logs">
<div class="form-row">
<div class="form-group col-md-4">
<label for="file">Log-Datei</label>
<select class="form-control" id="file" name="file">
<?php foreach (($files ?? []) as $f) : ?>
<?php $name = (string)($f['name'] ?? ''); ?>
<option value="<?php echo htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>"
<?php echo ($name === (string)$selectedFile) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group col-md-2">
<label for="level">Level</label>
<select class="form-control" id="level" name="level">
<?php
$levels = ['', 'ERROR', 'WARNING', 'INFO', 'DEBUG'];
foreach ($levels as $lvl) :
$label = ($lvl === '') ? 'Alle' : $lvl;
?>
<option value="<?php echo htmlspecialchars($lvl, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>"
<?php echo ((string)$filterLevel === (string)$lvl) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($label, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group col-md-3">
<label for="q">Suche</label>
<input type="text" class="form-control" id="q" name="q"
value="<?php echo htmlspecialchars((string)$searchQuery, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>"
placeholder="Text in message/context">
</div>
<div class="form-group col-md-2">
<label for="lines">Zeilen</label>
<input type="number" class="form-control" id="lines" name="lines"
value="<?php echo (int)$lines; ?>" min="1" max="2000">
</div>
<div class="form-group col-md-1 d-flex align-items-end">
<button type="submit" class="btn btn-primary btn-block">
Anzeigen
</button>
</div>
</div>
<?php if (is_array($fileMeta)) : ?>
<div class="small text-gray-600">
Datei: <strong><?php echo htmlspecialchars((string)$fileMeta['name'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></strong>
· Größe: <?php echo number_format((int)$fileMeta['size'], 0, ',', '.'); ?> Bytes
· Stand: <?php echo ($fileMeta['mtime'] ?? 0) > 0 ? date('d.m.Y H:i:s', (int)$fileMeta['mtime']) : 'n/a'; ?>
</div>
<?php endif; ?>
</form>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Einträge (neueste unten)</h6>
<a class="btn btn-sm btn-outline-secondary"
href="../index.php?route=logs&amp;file=<?php echo urlencode((string)$selectedFile); ?>&amp;level=<?php echo urlencode((string)$filterLevel); ?>&amp;q=<?php echo urlencode((string)$searchQuery); ?>&amp;lines=<?php echo (int)$lines; ?>">
Refresh
</a>
</div>
<div class="card-body">
<?php if (empty($entries)) : ?>
<div class="text-gray-600">Keine Einträge gefunden.</div>
<?php else : ?>
<div class="table-responsive">
<table class="table table-bordered table-sm">
<thead>
<tr>
<th style="width: 170px;">Zeit</th>
<th style="width: 110px;">Level</th>
<th>Message</th>
<th style="width: 35%;">Context</th>
</tr>
</thead>
<tbody>
<?php foreach ($entries as $e) : ?>
<?php
$lvl = strtoupper((string)($e['level'] ?? ''));
$badge = 'badge-secondary';
if ($lvl === 'ERROR') { $badge = 'badge-danger'; }
if ($lvl === 'WARNING') { $badge = 'badge-warning'; }
if ($lvl === 'INFO') { $badge = 'badge-info'; }
if ($lvl === 'DEBUG') { $badge = 'badge-light'; }
$ctx = $e['context'] ?? null;
$ctxPretty = '';
if (is_array($ctx)) {
$ctxPretty = (string)json_encode($ctx, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
?>
<tr>
<td><?php echo htmlspecialchars((string)($e['ts'] ?? ''), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td>
<td>
<span class="badge <?php echo $badge; ?>">
<?php echo htmlspecialchars($lvl, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</span>
</td>
<td><?php echo htmlspecialchars((string)($e['message'] ?? ''), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td>
<td>
<?php if ($ctxPretty !== '') : ?>
<pre class="mb-0 text-white" style="white-space: pre-wrap;">
<?php echo htmlspecialchars($ctxPretty, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</pre>
<?php else : ?>
<span class="text-gray-600">-</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="small text-gray-600">
Hinweis: Dieser Viewer lädt bewusst nur die letzten Zeilen (Tail), damit große Logfiles die Oberfläche nicht killen.
</div>
<?php endif; ?>
</div>
</div>