Search code examples
phpcsvsymfonydownload

How to force download a .csv file in Symfony 2, using Response object?


I'm making a "Download" controller using Symfony 2, that has the sole purpose of sending headers so that I can force a .csv file download, but it isn't working properly.

$response = new Response();
$response->headers->set('Content-Type', "text/csv");
$response->headers->set('Content-Disposition', 'attachment; filename="'.$fileName.'"');
$response->headers->set('Pragma', "no-cache");
$response->headers->set('Expires', "0");
$response->headers->set('Content-Transfer-Encoding', "binary");
$response->headers->set('Content-Length', filesize($fileName));
$response->prepare();
$response->sendHeaders();
$response->setContent(readfile($fileName));
$response->sendContent();

$fileName is a "info.csv" string. Such are my actions inside my controller, there's no return statement. When I tried returning the Response Object, the contents of the file were displayed in the browser, not my intended result.

The problem I've found is that in some pages I do get my info.csv file, but in anothers all I get is a message:

No webpage was found for the web address: http://mywebpage.com/download Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found.

I'm completely sure the file exists, so there must be another thing wrong. Also, routing.yml is working correctly, since I do get the file from other pages that also link to that path. The Apache error log doesn't show anything about it.

Has anyone forced the download of a .csv file on Symfony 2 before? If so, what am I doing wrong?


Solution

  • Here is a minimal example that works just fine in production:

    class MyController
    public function myAction()
    
        $response = $this->render('ZaysoAreaBundle:Admin:Team/list.csv.php',$tplData);
    
        $response->headers->set('Content-Type', 'text/csv');
        $response->headers->set('Content-Disposition', 'attachment; filename="teams.csv"');
    
        return $response;
    

    You can replace the render call with new response and response->setContent if you like.

    Your comment about no return statement inside a controller is puzzling. Controllers return a response. Let the framework take care of sending the stuff to the browser.