164 lines
4.3 KiB
PHP
164 lines
4.3 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
require_once __DIR__ . '/bootstrap.php';
|
||
|
|
|
||
|
|
function outputCustomerLogo(PDO $pdo, int $id): void
|
||
|
|
{
|
||
|
|
$statement = $pdo->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);
|
||
|
|
}
|