El Klo's avatar
Level 11

Download a zip file from a route

I have the following route:

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

The route gets triggered in a Filament Action url like this (hardcoded filename for now, but it exists):

->url(route('downloadAndDeleteZip', ['zipPath' => 'certificaten/57631_1727426398.zip']))

The method on my PdfController looks like this:

public function downloadAndDeleteZip($zipPath) {
		dd($zipPath);
		//return response()->download(Storage::disk('private')->url($zipPath))->deleteFileAfterSend(true);
	}

This returns a 404. What am i doing wrong here?

0 likes
8 replies
tykus's avatar
tykus
Best Answer
Level 104

You don't have a Route URL with the needed number of segments; you can capture the entire zipPath by pattern-matching:

Route::get('/downloadAndDeleteZip/{zipPath}', [PdfController::class, 'downloadAndDeleteZip'])
    ->name('downloadAndDeleteZip')
    ->where('zipPath', '.*');
1 like
El Klo's avatar
Level 11

@tykus Awesome, you're the best.

If you don't mind, i have a follow-up question:

public function downloadAndDeleteZip($zipPath) {
	    if (Storage::disk('private')->exists($zipPath)) {
	        $filePath = Storage::disk('private')->path($zipPath);
	        return response()->download($filePath)->deleteFileAfterSend(true);
	    } else {
	        abort(404, 'File not found.');
	    }
	}

This deletes the file and opens the zip in a new window but it doesn't actually download it. Any idea what i'm missing here?

tykus's avatar

@El Klo it should be working; what does your anchor element look like?

El Klo's avatar
Level 11

@tykus It's a filament action with a url:

Action::make('downloadAndDeleteZip')
					->button()
					->label("Download je PDF bestanden")
					->color('primary')
					->openUrlInNewTab()
					->url(route('downloadAndDeleteZip', ['zipPath' => $zipPath]))
tykus's avatar

@El Klo is ->openUrlInNewTab() really necessary here?

Also, did this need a separate Route; I believe you should be able to handle downloading directly in the Action:

Action::make('downloadAndDeleteZip')
    ->button()
    ->label("Download je PDF bestanden")
    ->color('primary')
    ->action(function () use ($zipPath) {
        if (Storage::disk('private')->exists($zipPath)) {
	        $filePath = Storage::disk('private')->get($zipPath);
	        return response()->download($filePath)->deleteFileAfterSend(true);
        }
    })
El Klo's avatar
Level 11

Yeah, i just tried a couple of things and ->openUrlInNewTab() was one of them.

The action works fine, if it's a standalone action. However, i have a process of generating multiple pdf's from a certain Models relation. When the PDF's are generated they are zipped and stored. What i am trying to accomplish is a database notification with an option for the user to download the zip. Unfortunately, notification actions don't accept the ->action() parameter so it needs to be ->url().

everything works fine, the PDF's get generated, they are zipped, the zipped file is stored and my user receives a Database notification with a download link. However, when they click that link, it opens the zip file in the browser window with gibberish: �b��fNx�,�6���uP��74�Ӥ�w

I'm guessing it has something to do with encoding, but don't know where. @tykus

tykus's avatar

@El Klo maybe try setting headers explicitly:

return response()->download(file: $filePath, headers: [
    'Content-Type' => 'application/octet-stream',
    'Content-Disposition' => 'attachment; filename=' . str($zipPath)->afterLast('/'),
])->deleteFileAfterSend(true);

I can't test anything similar now; but, the Content-Disposition header especially might help

El Klo's avatar
Level 11

@tykus Understandable, its not it, but i'll let you know when i figure it out Thanks for all the help.

Please or to participate in this conversation.