1

I have a function to download a zip file with or without folders based on the file_type_id. However when file_type_id is 1 my server is returning a empty 200 response. When i look at the temp folder i created the zip file is there and all the files are in it when i unzip it in the command line. So my question would be why this behaviour exists and if someone got a solution? The there is also nothing in the laravel.log or nginx/apache logs.

    public function downloadZip($file_type, $resId)
    {
        $reservation = Reservation::with('contact.insurer')->where('id', $resId)->first();

        if (Auth::user()->hasRole('verzekeraar')) {
            $contact = Auth::user()->userable;

            if ($contact->insurer_id != $reservation->contact->insurer_id) {
                return AppJsonResponse::UnAuthorized('U heeft geen rechten voor dit dossier.');
            }
        }
        $files = [];
        $dirs = [];
        if ($file_type == 2) {
            $files = $reservation->files;
        } else {
            $dirs = Folder::whereNull('parent_id')->where('reservation_id', $reservation->id)->get();
            $files = File::whereNull('parent_id')->where('reservation_id', $reservation->id)->where('file_type_id', 1)->get();
        }

        $zip_file = storage_path('app/tmp/wrapper.zip');

        // Ensure tmp directory exists
        if (!file_exists(storage_path('app/tmp'))) {
            mkdir(storage_path('app/tmp'), 0755, true);
        }

        // Initializing PHP class
        $zip = new \ZipArchive();
        if ($zip->open($zip_file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== TRUE) {
            \Log::error("Cannot open <$zipPath>\n");
            return AppJsonResponse::Error('ZIP creation failed.');
        }

        if ($file_type == 2) {
            foreach ($files as $file) {
                if ($file->file_type_id == $file_type) {
                    $zip->addFile(Storage::disk('private')->getDriver()->getAdapter()->applyPathPrefix($file->path), 'storage/' . $file->name . '.' . strtolower($file->ext));
                }
            }
        } else {
            $ultPath = 'storage/';
            $this->zipDocuments($dirs, $files, $ultPath, $reservation->id, $zip);
        }
       if (!$zip->close()) {
            \Log::error("Failed to close the zip file.");
        } else {
            \Log::debug("Successfully closed zip file: $zip_file");
        }

        if (file_exists($zip_file)) {
            Log::info("File size of ZIP: " . filesize($zip_file));
        return response()->download($zip_file, 'wrapper.zip', [
    'Content-Type' => 'application/zip',
        ]);

        } else{
            \Log::error('ZIP file is missing or too small: ' . $zip_file);
            return AppJsonResponse::Error('ZIP creation failed.');
        }
    }

And this is the zipdocuments function

public function zipDocuments($dirs, $files, $ultPath, $resId, $zip)
{
    foreach ($dirs as $dir) {
        $currentPath = $ultPath . $dir->name . '/';

        // Log current directory
        \Log::debug("Entering directory: $currentPath");

        // Add all files in current directory
        $filesInDir = File::where('parent_id', $dir->id)
            ->where('reservation_id', $resId)
            ->where('file_type_id', 1)
            ->get();

        foreach ($filesInDir as $file) {
            $fullPath = Storage::disk('private')->getDriver()->getAdapter()->applyPathPrefix($file->path);
            if (!file_exists($fullPath)) {
                \Log::warning("File not found: $fullPath");
                continue;
            }

            if($zip->addFile($fullPath, $currentPath . $file->name . '.' . strtolower($file->ext)) === true){

            }

        }

        // Recursively process subfolders
        $subDirs = Folder::where('parent_id', $dir->id)->where('reservation_id', $resId)->get();
        $this->zipDocuments($subDirs, [], $currentPath, $resId, $zip);
    }

    // Add top-level files (only for first call)
    foreach ($files as $file) {
        $fullPath = Storage::disk('private')->getDriver()->getAdapter()->applyPathPrefix($file->path);
        if (!file_exists($fullPath)) {
            \Log::warning("Top-level file not found: $fullPath");
            continue;
        }

        $zip->addFile($fullPath, $ultPath . $file->name . '.' . strtolower($file->ext));
    }

    return $zip;
}

I just call the endpoint using my angular application like this:

downloadZip(id, file_type): any {
    return this.http.get('/audits/downloadzip/'+file_type+'/'+id, {observe: 'response', responseType: 'blob', headers: new HttpHeaders({'Cache-Control': 'no-cache'})});
  }

and this gives the following message in the console and the response is empty

auditor-reservation-…ge.component.ts:174 
 GET http://127.0.0.1:8000/api/audits/downloadzip/1/2 net::ERR_FAILED 200 (OK)
3
  • 2
    You say there was nothing in the logs - not even whether it failed to close the zip file, or did that successfully? We have not seen the code for $this->zipDocuments, please include that as well. Commented Jun 19 at 6:22
  • Sorry i wasn't clear. this is the output in my log: [2025-06-19 11:52:10] test.DEBUG: Entering directory: storage/test/ [2025-06-19 11:52:10] test.DEBUG: Entering directory: storage/test 2/ [2025-06-19 11:52:12] test.DEBUG: Successfully closed zip file: storage\app/tmp/wrapper.zip [2025-06-19 11:52:12] test.INFO: File size of ZIP: 23443567 and i just checked again and it seems it doesn't work locally as well now Commented Jun 19 at 9:55
  • @C3roe and i am also able to just open the zip file with rar when i copy it to my desktop Commented Jun 19 at 10:46

1 Answer 1

0

This usually happens due to issues with how Laravel streams the file — especially if the ZIP contains nested folders or if output buffering interferes. Here’s what worked for me:

1. Replace response()->download() with manual streaming using readfile():

if (ob_get_length()) {
    ob_end_clean(); // Clear any previous output
}

return response()->streamDownload(function () use ($zip_file) {
    readfile($zip_file);
}, 'wrapper.zip', [
    'Content-Type' => 'application/zip',
    'Content-Length' => filesize($zip_file),
]);

This bypasses Laravel’s default file streaming and sends the file directly.

2. Double-check the file exists and has size:


if (!file_exists($zip_file)) {
    \Log::error("ZIP file not found: $zip_file");
    abort(404, 'ZIP file not found.');
}

$size = filesize($zip_file);
\Log::info("ZIP size: $size bytes");

3. Frontend (Angular) should handle the blob properly:

this.http.get('/api/your-download-endpoint', {
  responseType: 'blob',
  observe: 'response'
}).subscribe(response => {
  const blob = new Blob([response.body], { type: 'application/zip' });
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'wrapper.zip';
  a.click();
  window.URL.revokeObjectURL(url);
});

Summary:
• The ZIP file is created correctly.
• response()->download() may silently fail with complex ZIP structures.
• Use streamDownload() with readfile() instead.
• Clean output buffer before returning.
• Make sure Angular correctly handles binary blob responses.

Sign up to request clarification or add additional context in comments.

1 Comment

For me this still gives me a Err:failed 200 response from the api where the response data is just empty.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.