single( "SELECT id, identity_id FROM access_tokens WHERE uuid = ? AND (expires_at IS NULL OR expires_at > NOW())", "s", [$uuid] ); if (!$token) { http_response_code(403); exit('Kein Zugriff'); } /** * Datei laden & Berechtigung prüfen */ $file = $sql->single( "SELECT * FROM files WHERE id = ? AND identity_id = ? AND (token_id IS NULL OR token_id = ?)", "iii", [$fileId, $token['identity_id'], $token['id']] ); if (!$file) { http_response_code(404); exit('Datei nicht gefunden'); } /** * Dateipfad */ $basePath = '/var/www/files/'; $path = realpath($basePath . $file['stored_name']); if (!$path || !str_starts_with($path, $basePath) || !is_file($path)) { http_response_code(404); exit('Datei fehlt'); } /** * Saubere Ausgabe */ $filename = $file['filename']; $mime = $file['mime_type'] ?: 'application/octet-stream'; $size = filesize($path); header('Content-Description: File Transfer'); header('Content-Type: ' . $mime); header('Content-Disposition: attachment; filename="' . basename($filename) . '"'); header('Content-Length: ' . $size); header('X-Content-Type-Options: nosniff'); header('Cache-Control: private, no-store, no-cache, must-revalidate'); header('Pragma: no-cache'); header('Expires: 0'); while (ob_get_level()) { ob_end_clean(); } readfile($path); exit;