false, 'error' => 'Error interno: ' . $err['message']]); } }); header('Content-Type: application/json; charset=utf-8'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; } function jsonOk(array $data = [], string $msg = ''): never { ob_clean(); $r = ['ok' => true]; if ($msg) $r['message'] = $msg; if ($data) $r = array_merge($r, $data); echo json_encode($r); exit; } function jsonError(string $msg, int $code = 400): never { ob_clean(); http_response_code($code); echo json_encode(['ok' => false, 'error' => $msg]); exit; } function requireAdmin(): void { if (!isUserLoggedIn()) jsonError('No autorizado', 401); $role = $_SESSION['admin_user']['role'] ?? ''; if (!in_array($role, ['superadmin', 'admin', 'supervisor'], true)) jsonError('Sin permiso', 403); } function requireLogin(): void { if (!isUserLoggedIn()) jsonError('No autorizado', 401); } function inputJson(): array { return json_decode(file_get_contents('php://input'), true) ?? []; } function db(): PDO { $pdo = Database::getInstance()->getConnection(); $pdo->exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"); return $pdo; }