Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 create and download zip file

Tags:

php

zip

symfony

I have one application that upload some files and then I can compress as zip file and download.

The export action:

public function exportAction() {
        $files = array();
        $em = $this->getDoctrine()->getManager();
        $doc = $em->getRepository('AdminDocumentBundle:Document')->findAll();
        foreach ($_POST as $p) {
            foreach ($doc as $d) {
                if ($d->getId() == $p) {
                    array_push($files, "../web/".$d->getWebPath());
                }
            }
        }
        $zip = new \ZipArchive();
        $zipName = 'Documents-'.time().".zip";
        $zip->open($zipName,  \ZipArchive::CREATE);
        foreach ($files as $f) {
            $zip->addFromString(basename($f),  file_get_contents($f)); 
        }

        $response = new Response();
    $response->setContent(readfile("../web/".$zipName));
    $response->headers->set('Content-Type', 'application/zip');
    $response->header('Content-disposition: attachment; filename=../web/"'.$zipName.'"');
    $response->header('Content-Length: ' . filesize("../web/" . $zipName));
    $response->readfile("../web/" . $zipName);
    return $response;
    }

everything is ok until the line header. and everytime I'm going here I got the error: "Warning: readfile(../web/Documents-1385648213.zip): failed to open stream: No such file or directory"

What is wrong?

and why when I upload the files, this files have root permissions, and the same happens for the zip file that I create.

like image 525
BrunoRamalho Avatar asked Nov 28 '13 13:11

BrunoRamalho


4 Answers

SYMFONY 3 - 4 example :

use Symfony\Component\HttpFoundation\Response;

/**
* Create and download some zip documents.
*
* @param array $documents
* @return Symfony\Component\HttpFoundation\Response
*/
public function zipDownloadDocumentsAction(array $documents)
{
    $files = [];
    $em = $this->getDoctrine()->getManager();

    foreach ($documents as $document) {
        array_push($files, '../web/' . $document->getWebPath());
    }

    // Create new Zip Archive.
    $zip = new \ZipArchive();

    // The name of the Zip documents.
    $zipName = 'Documents.zip';

    $zip->open($zipName,  \ZipArchive::CREATE);
    foreach ($files as $file) {
        $zip->addFromString(basename($file),  file_get_contents($file));
    }
    $zip->close();

    $response = new Response(file_get_contents($zipName));
    $response->headers->set('Content-Type', 'application/zip');
    $response->headers->set('Content-Disposition', 'attachment;filename="' . $zipName . '"');
    $response->headers->set('Content-length', filesize($zipName));

    @unlink($zipName);

    return $response;
}
like image 57
Vincent Moulene Avatar answered Oct 01 '22 00:10

Vincent Moulene


solved:

$zip->close();
header('Content-Type', 'application/zip');
header('Content-disposition: attachment; filename="' . $zipName . '"');
header('Content-Length: ' . filesize($zipName));
readfile($zipName);

apparently closing the file is important ;)

like image 42
BrunoRamalho Avatar answered Sep 30 '22 23:09

BrunoRamalho


Since Symfony 3.2+ can use file helper to let file download in browser:

public function someAction()
{
    // create zip file
    $zip = ...;

    $this->file($zip);    
}
like image 2
Tomas Votruba Avatar answered Sep 30 '22 23:09

Tomas Votruba


ZipArchive creates the zip file into the root directory of your website if only a name is indicated into open function like $zip->open("document.zip", ZipArchive::CREATE). Specify the path into this function like $zip->open("my/path/document.zip", ZipArchive::CREATE). Do not forget delete this file with unlink() (see doc).

Here you have an example in Symfony 4 (may work on earlier version):

use Symfony\Component\HttpFoundation\Response;
use \ZipArchive;

public function exportAction()
{
    // Do your stuff with $files
    
    $zip = new ZipArchive();
    $zip_name = "../web/zipFileName.zip"; // Users should not have access to the web folder (it is for temporary files)
    // Create a zip file in tmp/zipFileName.zip (overwrite if exists)
    if ($zip->open($zip_name, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) {
           
         // Add your files into zip
         foreach ($files as $f) {
            $zip->addFromString(basename($f),  file_get_contents($f)); 
         }          
         $zip->close();
    
         $response = new Response(
            file_get_contents($zip_name),
            Response::HTTP_OK,
            ['Content-Type' => 'application/zip', 
             'Content-Disposition' => 'attachment; filename="' . basename($zip_name) . '"',
             'Content-Length' => filesize($zip_name)]);

         unlink($zip_name); // Delete file

         return $response;
     } else {
            // Throw an exception or manage the error
     }
}

You may need to add "ext-zip": "*" into your Composer file to use ZipArchive and extension=zip.so in your php.ini.

Answser inspired by Create a Response object with zip file in Symfony.

like image 1
Liscare Avatar answered Oct 01 '22 01:10

Liscare