allow($rateKey, (int) $app['rate_limit']['requests'], (int) $app['rate_limit']['window_seconds'])) { http_response_code(429); header('Content-Type: text/plain; charset=utf-8'); echo 'Zu viele Anfragen. Bitte später erneut versuchen.'; exit; } $store = new JsonStore(); $draft = $store->getDraft($email); if (!is_array($draft)) { http_response_code(404); header('Content-Type: text/plain; charset=utf-8'); echo 'Entwurf nicht gefunden.'; exit; } $uploads = (array) ($draft['uploads'] ?? []); $files = $uploads[$field] ?? null; $entry = (is_array($files) && isset($files[$index]) && is_array($files[$index])) ? $files[$index] : null; if (!is_array($entry)) { http_response_code(404); header('Content-Type: text/plain; charset=utf-8'); echo 'Upload nicht gefunden.'; exit; } $path = resolveStoredPreviewPath($entry, $app); if ($path === null || !is_file($path)) { http_response_code(404); header('Content-Type: text/plain; charset=utf-8'); echo 'Datei nicht gefunden.'; exit; } $mime = (string) ($entry['mime'] ?? ''); if ($mime === '') { $detected = @mime_content_type($path); $mime = is_string($detected) ? $detected : 'application/octet-stream'; } $downloadName = (string) ($entry['original_filename'] ?? basename($path)); $fallbackName = preg_replace('/[^A-Za-z0-9._-]/', '_', $downloadName) ?: 'upload.bin'; $encodedName = rawurlencode($downloadName); header('Content-Type: ' . $mime); header('X-Content-Type-Options: nosniff'); header('Content-Length: ' . (string) filesize($path)); header('Content-Disposition: inline; filename="' . $fallbackName . '"; filename*=UTF-8\'\'' . $encodedName); readfile($path); exit;