prepare( 'SELECT logo_blob, logo_mime_type, updated_at FROM customer_references WHERE id = ? AND is_active = 1 AND logo_blob IS NOT NULL LIMIT 1' ); $statement->execute([$id]); $logo = $statement->fetch(); $allowed = ['image/png', 'image/jpeg', 'image/webp', 'image/gif']; if (!$logo || !is_string($logo['logo_blob'])) { http_response_code(404); exit; } $mime = (string)($logo['logo_mime_type'] ?? ''); if (!in_array($mime, $allowed, true)) { http_response_code(415); exit; } $etag = '"' . sha1((string)$logo['updated_at'] . ':' . strlen($logo['logo_blob'])) . '"'; if (trim((string)($_SERVER['HTTP_IF_NONE_MATCH'] ?? '')) === $etag) { http_response_code(304); exit; } header('Content-Type: ' . $mime); header('Content-Length: ' . strlen($logo['logo_blob'])); header('Cache-Control: public, max-age=3600'); header('ETag: ' . $etag); header('X-Content-Type-Options: nosniff'); echo $logo['logo_blob']; exit; } function outputCachedCustomerLogo(int $id): void { $types = ['png' => 'image/png', 'jpg' => 'image/jpeg', 'webp' => 'image/webp', 'gif' => 'image/gif']; foreach ($types as $extension => $mime) { $path = __DIR__ . '/content-cache-logos/' . $id . '.' . $extension; if (!is_file($path)) { continue; } header('Content-Type: ' . $mime); header('Content-Length: ' . filesize($path)); header('Cache-Control: public, max-age=3600'); header('X-Content-Type-Options: nosniff'); readfile($path); exit; } http_response_code(404); exit; } function cachedContent(): ?array { $path = __DIR__ . '/content-cache.json'; if (!is_file($path)) { return null; } $decoded = json_decode((string)file_get_contents($path), true); return is_array($decoded) ? $decoded : null; } if (isset($_GET['logo'])) { $logoId = filter_input(INPUT_GET, 'logo', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]); if (!$logoId) { http_response_code(400); exit; } try { outputCustomerLogo(bmc_db(), $logoId); } catch (Throwable $e) { outputCachedCustomerLogo($logoId); } } function fetchCustomers(PDO $pdo): array { $sql = "SELECT customer_name, logo_url, website_url FROM customer_references WHERE is_active = 1 ORDER BY sort_order ASC, customer_name ASC LIMIT 50"; return $pdo->query($sql)->fetchAll(); } function fetchCurrentOperation(PDO $pdo): ?array { $sql = "SELECT title, severity, message, starts_at, ends_at, updated_at FROM operations_status WHERE is_active = 1 AND (starts_at IS NULL OR starts_at <= NOW()) AND (ends_at IS NULL OR ends_at >= NOW()) ORDER BY updated_at DESC LIMIT 1"; $row = $pdo->query($sql)->fetch(); return $row ?: null; } function fetchOperationHistory(PDO $pdo): array { $sql = "SELECT title, severity, message, starts_at, ends_at, updated_at FROM operations_incidents WHERE is_public = 1 ORDER BY updated_at DESC LIMIT 20"; return $pdo->query($sql)->fetchAll(); } try { $pdo = bmc_db(); $customers = []; $current = null; $history = []; try { $customers = fetchCustomers($pdo); } catch (Throwable $e) { $customers = []; } try { $current = fetchCurrentOperation($pdo); } catch (Throwable $e) { $current = null; } try { $history = fetchOperationHistory($pdo); } catch (Throwable $e) { $history = []; } bmc_json_response([ 'meta' => [ 'generated_at' => gmdate('c'), ], 'customers' => $customers, 'operations' => [ 'current' => $current, 'history' => $history, ], ]); } catch (Throwable $e) { $cached = cachedContent(); if ($cached !== null) { bmc_json_response($cached); } bmc_json_response([ 'error' => 'content_unavailable', 'message' => 'Kunne ikke hente dynamisk indhold.', ], 503); }