Laravel 下载 Zip 打开未编码的文本

问题描述 投票:0回答:1

我在 Laravel 中有以下路线:

Route::get('/downloadAndDeleteZip/{zipPath}', [PdfController::class, 'downloadAndDeleteZip'])
->name('downloadAndDeleteZip')
->where('zipPath', '.*');

这会触发下载和删除 zip 文件的方法:

public function downloadAndDeleteZip($zipPath) {
        if (ob_get_length()) {
            ob_end_clean();
        }
        if (Storage::disk('private')->exists($zipPath)) {
            $filePath = Storage::disk('private')->path($zipPath);

            return response()->download($filePath, basename($filePath), [
                'Content-Type' => 'application/zip',
                'Content-Disposition' => 'attachment; filename="' . basename($filePath) . '"',
            ])->deleteFileAfterSend(true);
        } else {
            abort(404, 'File not found.');
        }
    }

当我触发该方法时,zip 会被删除,但我的 zip 不会下载。它只是在浏览器窗口中显示未编码的文本:

unencoded text

值得注意的是,我使用的是 laravel Filament。我有一个操作可以通过 Spatie 的 browsershot/pdf 包触发 PDF 创建。当我的用户单击按钮时,作业负责创建 pdf 文件,将它们添加到 zip 文件并发送带有下载链接的数据库通知:

class GenerateCertificatesJob implements ShouldQueue {
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected Project $project;
    protected User $user;

    public function __construct($project, $user) {
        $this->project = $project;
        $this->user = $user;
    }

    /**
     * @throws \Exception
     */
    public function handle(): Notification  {
        $randomName = rand(1, 1000000) . '_' . time();
        $tempFolder = '/certificaten/' . $randomName .'/certificaat-';
        $pdfPaths = [];

        foreach($this->project->attendees as $attendee) {
            $pdfPath = $tempFolder . $attendee->last_name . '.pdf';
            PDF::view('pdf.certificate', ['project' => $this->project, 'attendee' => $attendee])
                ->disk('private')
                ->save($pdfPath);
            $pdfPaths[] = Storage::disk('private')->path($pdfPath);
        }

        // Create a zip archive and add PDF files
        $zipPath = 'certificaten/' . $randomName . '.zip';
        $zip = new ZipArchive;

        if ($zip->open(Storage::disk('private')->path($zipPath), ZipArchive::CREATE) === TRUE) {
            foreach ($pdfPaths as $file) {
                if (file_exists($file)) {
                    $zip->addFile($file, basename($file));
                }
            }
            $zip->close();
        } else {
            throw new \Exception('Zip file could not be created.');
        }

        // Cleaning up the temporary PDF files if needed
        foreach ($pdfPaths as $file) {
            if (file_exists($file)) {
                unlink($file);
            }
        }

        return Notification::make()
            ->title('Download ZIP here')
            ->success()
            ->actions([
                Action::make('downloadAndDeleteZip')
                    ->button()
                    ->label("Download")
                    ->color('primary')
                    ->url(route('downloadAndDeleteZip', ['zipPath' => $zipPath]))
            ])
            ->sendToDatabase($this->user);
    }
}

还值得注意的是:除了下载 zip 文件之外,一切正常。我尝试手动将 zip 文件放入文件夹中并下载它,但它给出了相同的输出。我还尝试了一个操作而不是 URL,但这不受支持,因为它是对通知的操作。

提出的问题并不相似。它是关于下载大约 11 年前的非常旧版本的框架的单个 pdf 文件。我生成 pdf 文件没有问题,但下载已压缩的文件时遇到问题。

laravel zip laravel-filament
1个回答
0
投票

如果您确信 zip 文件已正确生成(可以解压缩,可以打开其中的 PDF 文件等),那么我可能会查看

->download()
中定义的 Content-Disposition 标头(因为它不应该)甚至不能在浏览器窗口中打开,对吧)?

来自 mozilla 文档

参数

filename
filename*
的不同之处仅在于
filename*
使用 RFC 5987 中定义的编码。当
filename
filename*
都出现在单个标头字段值中时,当两者都被理解时,
filename*
优先于文件名。建议同时包含两者以获得最大兼容性,并且您可以通过用 ASCII 等效项替换非 ASCII 字符来将
filename*
转换为文件名(例如将
é
转换为
e
)。您可能希望避免文件名中使用百分比转义序列,因为它们在浏览器之间的处理方式不一致。 (Firefox 和 Chrome 对其进行解码,而 Safari 则不会。)
浏览器可以应用转换来符合文件系统要求,例如将路径分隔符(
/
\
)转换为下划线(
_
)。

© www.soinside.com 2019 - 2024. All rights reserved.