Symfony2 : header won’t change in download controller

Sooner or late you have to add file download option to your symfony2 project. As many times before I have been created controller just for that. But something went wrong, file was interpreted as text by browser instead as file for download.

Controller was looking something like this:


/**
  * FileDownload controller
  */
public function returnFileAction($id)
{
    // security check
    if(!is_numeric($id))
    {
    	return new Response('', HTTP_BAD_REQUEST);
    }
       
    // parameters.yml
    $fileDir = $this->container->getParameter('path_to_files');
       
    // find file by name, don't care about extension
    $fileArray = glob($fileDir . "$id.*");
    
    // expecting only one result
    if(count($fileArray) != 1) {
    	return new Response('', HTTP_BAD_REQUEST);	
    }

    $filePath = $fileArray[0];
    
    $finfo = finfo_open(FILEINFO_MIME_TYPE);

    $response = new Response();
    
    // Set headers
    $response->headers->set('Cache-Control', 'private');
    $response->headers->set('Content-type', finfo_file($finfo, $filePath));
    $response->headers->set('Content-Disposition', 'inline; filename="' . basename($filePath) . '";');
    $response->headers->set('Content-length', filesize($filePath));
	
    // Send headers before outputting anything
    $response->sendHeaders();
    
    readfile($filePath);

    return $response;
}

Common mistake is to set readfile before sending header back to user.

Result of sending wrong http header leads to byte output directly to browser interpreted as plain text. In that case move readfile or wrap it with ob_start/ob_end.

Example :


ob_start();
readfile($filePath);
$file = ob_get_contents();
// ...
// at end of function
$response->setContent($file);

Take care to put file output at end and eliminate possible error output it will save you some debugging time, trust me I know 😉

Leave a Reply

Your email address will not be published. Required fields are marked *