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 = '
| Campo | Antes | Depois |
|---|---|---|
| ' . htmlspecialchars((string) $k) . ' | ' . $fmt($v['from'] ?? null) . ' | ' . $fmt($v['to'] ?? null) . ' |
Quem fez o quê, a quê e quando. Os segredos nunca entram no registo.
| Quando | Quem | Ação | Alvo | Resumo | IP |
|---|---|---|---|---|---|
| Nada no registo com este filtro. | |||||
| = htmlspecialchars(date('d/m/Y H:i:s', strtotime((string) $r['created_at']))) ?> | = $r['actor_name'] !== null && $r['actor_name'] !== '' ? htmlspecialchars((string) $r['actor_name']) : 'sistema' ?>
= htmlspecialchars((string) $r['actor_role']) ?> |
= htmlspecialchars((string) $r['action']) ?> |
= htmlspecialchars((string) $r['target_type']) ?>= $r['target_id'] !== null && $r['target_id'] !== '' ? ' #' . htmlspecialchars((string) $r['target_id']) : '' ?>
= htmlspecialchars((string) $r['target_label']) ?>
|
= htmlspecialchars((string) ($r['summary'] ?? '')) ?>
alterações= $ch ?> |
= htmlspecialchars((string) ($r['ip'] ?? '')) ?> |