我在 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 不会下载。它只是在浏览器窗口中显示未编码的文本:
值得注意的是,我使用的是 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 文件没有问题,但下载已压缩的文件时遇到问题。
如果您确信 zip 文件已正确生成(可以解压缩,可以打开其中的 PDF 文件等),那么我可能会查看
->download()
中定义的 Content-Disposition 标头(因为它不应该)甚至不能在浏览器窗口中打开,对吧)?
来自 mozilla 文档:
参数
和filename
的不同之处仅在于filename*
使用 RFC 5987 中定义的编码。当filename*
和filename
都出现在单个标头字段值中时,当两者都被理解时,filename*
优先于文件名。建议同时包含两者以获得最大兼容性,并且您可以通过用 ASCII 等效项替换非 ASCII 字符来将filename*
转换为文件名(例如将filename*
转换为é
)。您可能希望避免文件名中使用百分比转义序列,因为它们在浏览器之间的处理方式不一致。 (Firefox 和 Chrome 对其进行解码,而 Safari 则不会。)e
浏览器可以应用转换来符合文件系统要求,例如将路径分隔符(和/
)转换为下划线(\
)。_