prepare("SELECT token FROM admin_tokens WHERE token=? AND expires_at > NOW()"); $stmt->execute([$token]); return (bool)$stmt->fetch(); } $token = preg_replace('/[^a-f0-9]/', '', $_GET['_t'] ?? ''); if (!_verifyToken($token)) { http_response_code(403); header('Content-Type: text/plain'); exit('Unauthorized — please log in to the admin panel first.'); } $ref = strtoupper(preg_replace('/[^A-Z0-9\-]/', '', $_GET['ref'] ?? '')); $type = in_array($_GET['type'] ?? '', ['license','insurance']) ? $_GET['type'] : ''; if (!$ref || !$type) { http_response_code(400); header('Content-Type: text/plain'); exit('Missing parameters.'); } $col = $type === 'license' ? 'license_file' : 'insurance_file'; $stmt = db()->prepare("SELECT {$col} AS file_path FROM bookings WHERE booking_ref=?"); $stmt->execute([$ref]); $row = $stmt->fetch(); if (!$row || !$row['file_path']) { http_response_code(404); header('Content-Type: text/plain'); exit('Document not found.'); } $base = realpath(__DIR__ . '/uploads'); $path = realpath(__DIR__ . '/' . $row['file_path']); if (!$path || !$base || strpos($path, $base . DIRECTORY_SEPARATOR) !== 0) { http_response_code(404); header('Content-Type: text/plain'); exit('File not found.'); } $finfo = new finfo(FILEINFO_MIME_TYPE); $mime = $finfo->file($path); $allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'application/pdf' => 'pdf']; if (!isset($allowed[$mime])) { http_response_code(403); header('Content-Type: text/plain'); exit('Invalid file type.'); } $fname = $type . '-' . $ref . '.' . $allowed[$mime]; header('Content-Type: ' . $mime); header('Content-Disposition: inline; filename="' . $fname . '"'); header('Content-Length: ' . filesize($path)); header('Cache-Control: private, max-age=3600'); readfile($path); exit;