auditoria.php 4.75 KB
<?php

declare(strict_types=1);

require __DIR__ . '/../src/bootstrap.php';
Auth::requireAdmin();

$perPageOptions = [10, 25, 50, 100];
$perPage = (int) ($_GET['per'] ?? 50);
if (!in_array($perPage, $perPageOptions, true)) {
    $perPage = 50;
}
$total = (int) Database::pdo()->query('SELECT COUNT(*) FROM audit_log')->fetchColumn();
$totalPages = max(1, (int) ceil($total / $perPage));

$page = max(1, (int) ($_GET['p'] ?? 1));
$page = min($page, $totalPages);
$offset = ($page - 1) * $perPage;

$stmt = Database::pdo()->prepare(
    'SELECT * FROM audit_log ORDER BY criado_em DESC, id DESC LIMIT :limit OFFSET :offset'
);
$stmt->bindValue('limit', $perPage, PDO::PARAM_INT);
$stmt->bindValue('offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$logs = $stmt->fetchAll();

$acaoLabels = [
    'login'                 => 'Login',
    'login_negado'          => 'Login negado (sem permissão)',
    'login_falhou'          => 'Login falhou (usuário/senha)',
    'logout'                => 'Logoff',
    'habilitou_aluno'       => 'Habilitou aluno',
    'desabilitou_aluno'     => 'Desabilitou aluno',
    'alterou_senha_aluno'   => 'Alterou senha de aluno',
    'adicionou_admin'       => 'Adicionou administrador',
    'desativou_admin'       => 'Desativou administrador',
    'reativou_admin'        => 'Reativou administrador',
    'alterou_papel_admin'   => 'Alterou papel de administrador',
    'atualizou_settings'    => 'Atualizou configurações',
];

View::header('Auditoria');
?>
<div class="card">
    <h1>Auditoria</h1>
    <p class="hint">
        Histórico de logins (inclusive tentativas com senha incorreta), alterações em
        alunos, administradores e configurações.
    </p>

    <div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;margin-bottom:4px">
        <span class="hint">
            Mostrando <?= count($logs) ?> de <?= $total ?> registros — página <?= $page ?> de <?= $totalPages ?>
        </span>
        <form method="get" action="auditoria" style="display:flex;align-items:center;gap:8px;margin:0">
            <label for="per" style="margin:0;white-space:nowrap">Por página</label>
            <select id="per" name="per" onchange="this.form.submit()" style="margin:0;width:auto">
                <?php foreach ($perPageOptions as $opt): ?>
                    <option value="<?= $opt ?>" <?= $opt === $perPage ? 'selected' : '' ?>><?= $opt ?></option>
                <?php endforeach; ?>
            </select>
        </form>
    </div>

    <table>
        <tr>
            <th>Data/hora</th>
            <th>Usuário</th>
            <th>Ação</th>
            <th>Alvo</th>
            <th>Detalhe</th>
            <th>IP</th>
        </tr>
        <?php foreach ($logs as $log): ?>
        <tr>
            <td data-label="Data/hora"><?= View::escape($log['criado_em']) ?></td>
            <td data-label="Usuário"><?= View::escape($log['usuario']) ?></td>
            <td data-label="Ação"><?= View::escape($acaoLabels[$log['acao']] ?? $log['acao']) ?></td>
            <td data-label="Alvo"><?= View::escape($log['alvo'] ?? '') ?></td>
            <td data-label="Detalhe"><?= View::escape($log['detalhe'] ?? '') ?></td>
            <td data-label="IP"><?= View::escape($log['ip'] ?? '') ?></td>
        </tr>
        <?php endforeach; ?>
        <?php if (!$logs): ?>
        <tr><td colspan="6">Nenhum registro ainda.</td></tr>
        <?php endif; ?>
    </table>

    <?php if ($totalPages > 1): ?>
    <div style="display:flex;align-items:center;gap:10px;margin-top:16px;flex-wrap:wrap">
        <?php if ($page > 1): ?>
            <a class="btn secondary" href="auditoria?per=<?= $perPage ?>&p=<?= $page - 1 ?>">&larr; Anterior</a>
        <?php else: ?>
            <span class="btn secondary" style="opacity:.4;pointer-events:none">&larr; Anterior</span>
        <?php endif; ?>

        <form method="get" action="auditoria" style="display:flex;align-items:center;gap:8px;margin:0">
            <input type="hidden" name="per" value="<?= $perPage ?>">
            <label for="p" style="margin:0;white-space:nowrap">Página</label>
            <select id="p" name="p" onchange="this.form.submit()" style="margin:0;width:auto">
                <?php for ($p = 1; $p <= $totalPages; $p++): ?>
                    <option value="<?= $p ?>" <?= $p === $page ? 'selected' : '' ?>><?= $p ?> de <?= $totalPages ?></option>
                <?php endfor; ?>
            </select>
        </form>

        <?php if ($page < $totalPages): ?>
            <a class="btn secondary" href="auditoria?per=<?= $perPage ?>&p=<?= $page + 1 ?>">Próxima &rarr;</a>
        <?php else: ?>
            <span class="btn secondary" style="opacity:.4;pointer-events:none">Próxima &rarr;</span>
        <?php endif; ?>
    </div>
    <?php endif; ?>
</div>
<?php
View::footer();