Symfony 1.4: the best way to ensure file upload without using a template / view

Of course, some other people discussed this issue on stackoverflow, but not all ansers work for me, and often they do not provide a symfony installation version.

Topics I read:

What I need to ask is how to handle file downloads in symfony 1.4 (without using a view)? In all my use cases, I need a template file to display the response. If I send a response due to the controller, there is the option to send it without php error (already sent header) using

controller:

/** @var $response sfWebResponse */ $response = $this->getResponse(); $response->clearHttpHeaders(); $response->setContentType($mimeType); $response->setHttpHeader('Content-Disposition', 'attachment; filename="' . basename($filePath) . '"'); $response->setHttpHeader('Content-Description', 'File Transfer'); $response->setHttpHeader('Content-Transfer-Encoding', 'binary'); $response->setHttpHeader('Content-Length', filesize($filePath)); $response->setHttpHeader('Cache-Control', 'public, must-revalidate'); $response->setHttpHeader('Pragma', 'public'); $response->sendHttpHeaders(); readfile($filePath); die(); 

This works without a template file. But imho is not a very beautiful encoding.

Alternative way with a template:

controller:

  /** @var $response sfWebResponse */ $response = $this->getResponse(); $response->clearHttpHeaders(); $response->setContentType($mimeType); $response->setHttpHeader('Content-Disposition', 'attachment; filename="' . basename($filePath) . '"'); $response->setHttpHeader('Content-Description', 'File Transfer'); $response->setHttpHeader('Content-Transfer-Encoding', 'binary'); $response->setHttpHeader('Content-Length', filesize($filePath)); $response->setHttpHeader('Cache-Control', 'public, must-revalidate'); $response->setHttpHeader('Pragma', 'public'); $response->setContent(file_get_contents($filePath)); $response->sendHttpHeaders(); return sfView::NONE; 

View:

 <?php echo $sf_response->getRawValue()->getContent(); ?> 
+4
source share
3 answers

My preferred solution

 $filePath = $document->getAbsoluteFilePath(); $mimeType = mime_content_type($filePath); /** @var $response sfWebResponse */ $response = $this->getResponse(); $response->clearHttpHeaders(); $response->setContentType($mimeType); $response->setHttpHeader('Content-Disposition', 'attachment; filename="' . basename($filePath) . '"'); $response->setHttpHeader('Content-Description', 'File Transfer'); $response->setHttpHeader('Content-Transfer-Encoding', 'binary'); $response->setHttpHeader('Content-Length', filesize($filePath)); $response->setHttpHeader('Cache-Control', 'public, must-revalidate'); // if https then always give a Pragma header like this to overwrite the "pragma: no-cache" header which // will hint IE8 from caching the file during download and leads to a download error!!! $response->setHttpHeader('Pragma', 'public'); //$response->setContent(file_get_contents($filePath)); # will produce a memory limit exhausted error $response->sendHttpHeaders(); ob_end_flush(); return $this->renderText(readfile($filePath)); 

No need to use a template file. Using standard symfony behavior. Important: the template file must be submitted!

+6
source

I used two methods depending on the contents of the file. For documents such as Excel documents, I usually use this approach:

 $this->getResponse()->clearHttpHeaders(); $this->getResponse()->setHttpHeaders('Content-Description','File Transer'); $this->getResponse()->setHttpHeaders('Content-Type','application/vnd.ms-excel'); //this would be based on your file $this->getResponse()->setHttpHeaders('Content-Disposition','attachment;filename='.$filename); //$filename is name of file on server $this->getResponse()->setHttpHeaders('Pragma',''); $this->getResponse()->setHttpHeaders('Cache-Control',''); $this->getResponse()->sendHttpHeaders(); $error_reporting = error_reporting(0); $this->renderText($some_data->save('php://output')); //in this case the $some_data was a PHPExcel writer object but anything that can be saved to a [php://output][1] should work eg fwrite() error_reporting($error_reporting); return sfView::NONE 

Disabling and enabling error_reporting involves using PHPExcel to write to the stream.

The other method I used uses the sendContent() sfResponse method. An example of this use:

 $this->getResponse()->clearHttpheaders(); $this->getResponse()->setHttpHeader('Content-Description','File Transfer'); $this->getResponse()->setHttpHeader('Cache-Control', 'public, must-revalidate, max-age=0'); $this->getResponse()->setHttpHeader('Pragma: public',true); $this->getResponse()->setHttpHeader('Content-Transfer-Encoding', 'binary'); $this->getResponse()->setHttpHeader('Content-length',filesize($filename)) //send the size of the file $this->getResponse()->setHttpHeader('Content-Type','some_mime_type') // eg application/pdf, image/png etc. $this->getResponse()->setHttpHeader('Content-Disposition','attachment; filename='.$filename) //some filename $this->getResponse()->sendHttpHeaders(); //edited to add the missed sendHttpHeaders $this->getResponse()->setContent(readfile($filename)); $this->getResponse()->sendContent(); return sfView::NONE; 

Both approaches work, and you don't need a template to render the content / file.

Note. Edited to add to $this->getResponse()->sendHttpHeaders() before setting up and sending content

+1
source

You can do this with simple php functions:

 public function executeIndex(sfWebRequest $request) { while(ob_get_level()) { ob_end_clean(); } // use plain php functions to // setup headers // ... // and read and echo the file throw new sfStopException(); } 
0
source

All Articles