trim((string) ($_GET['actor'] ?? '')), 'action' => trim((string) ($_GET['action'] ?? '')), 'target_type' => trim((string) ($_GET['target_type'] ?? '')), 'target_id' => trim((string) ($_GET['target_id'] ?? '')), 'q' => trim((string) ($_GET['q'] ?? '')), 'from' => preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_GET['from'] ?? '')) ? (string) $_GET['from'] : '', 'to' => preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_GET['to'] ?? '')) ? (string) $_GET['to'] : '', ]; $perPage = 50; $page = max(1, (int) ($_GET['p'] ?? 1)); // Exportação: o filtro inteiro (até 5000 linhas), em CSV que o Excel abre em pt. if (($_GET['export'] ?? '') === 'csv') { $rows = platform_audit_query($pdo, $filters, 5000); header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename="auditoria-' . date('Y-m-d') . '.csv"'); $out = fopen('php://output', 'w'); fwrite($out, "\xEF\xBB\xBF"); fputcsv($out, ['Quando', 'Quem', 'Papel', 'Ação', 'Tipo', 'Id', 'Alvo', 'Resumo', 'Alterações', 'IP'], ';'); foreach ($rows as $r) { fputcsv($out, [$r['created_at'], $r['actor_name'], $r['actor_role'], $r['action'], $r['target_type'], $r['target_id'], $r['target_label'], $r['summary'], $r['changes'], $r['ip']], ';'); } fclose($out); exit; } $rows = platform_audit_query($pdo, $filters, $perPage + 1, ($page - 1) * $perPage); $hasNext = count($rows) > $perPage; $rows = array_slice($rows, 0, $perPage); $actions = platform_audit_distinct($pdo, 'action'); $types = platform_audit_distinct($pdo, 'target_type'); $selfUrl = strtok((string) ($_SERVER['REQUEST_URI'] ?? ''), '?') ?: ''; $link = function (array $q) use ($selfUrl, $filters): string { $base = isset($_GET['tool']) ? ['tool' => (string) $_GET['tool']] : []; return $selfUrl . '?' . http_build_query($base + array_filter($q + $filters, fn($v) => $v !== '' && $v !== null)); }; /** Uma alteração em HTML: tabela campo / antes / depois, ou o texto tal como veio. */ $renderChanges = function (?string $json): string { if ($json === null || $json === '') return ''; $data = json_decode($json, true); if (!is_array($data)) return '
' . htmlspecialchars($json) . '
'; $fmt = fn($v) => $v === null ? '—' : htmlspecialchars(is_scalar($v) ? (string) $v : json_encode($v, JSON_UNESCAPED_UNICODE)); $isDiff = $data && array_reduce($data, fn($ok, $v) => $ok && is_array($v) && (array_key_exists('from', $v) || array_key_exists('to', $v)), true); if (!$isDiff) return '
' . htmlspecialchars(json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)) . '
'; $h = ''; foreach ($data as $k => $v) { $h .= ''; } return $h . '
CampoAntesDepois
' . htmlspecialchars((string) $k) . '' . $fmt($v['from'] ?? null) . '' . $fmt($v['to'] ?? null) . '
'; }; $layout_header = $platform_layout_header ?? ($repo_root . '/includes/header.php'); $layout_navbar = $platform_layout_navbar ?? ($repo_root . '/includes/navbar.php'); $layout_footer = $platform_layout_footer ?? ($repo_root . '/includes/footer.php'); $dashboard_url = $platform_dashboard_url ?? (function_exists('platform_admin_url') ? platform_admin_url('index.php') : 'index.php'); $pageTitle = 'Registo de auditoria'; if (is_file($layout_header)) include $layout_header; if (is_file($layout_navbar)) include $layout_navbar; ?>

Registo de auditoria

Quem fez o quê, a quê e quando. Os segredos nunca entram no registo.

Limpar
QuandoQuemAçãoAlvoResumoIP
Nada no registo com este filtro.
sistema' ?>
alterações
1 || $hasNext): ?>