Symfony 1.4: лучший способ обеспечить загрузку файла без использования шаблона / представления

Разумеется, некоторые другие люди обсуждали эту проблему в stackoverflow, но не все ansers работают для меня, и часто они не предоставляют версию установки Symfony.

Темы, которые я прочитал:

  • Отправить вложение / Загрузить файл из Symfony action
  • Как загрузить файл при нажатии на путь к файлу с помощью PHP-Symfony?
  • symfony: setHttpHeader () не работает, заголовок () делает

Я хочу спросить, как вы обрабатываете загрузки файлов в symfony 1.4 (без использования представления)? Во всех моих случаях использования мне нужен файл шаблона для отображения ответа. Если я отправлю ответ из-за контроллера, есть возможность отправить его без ошибки php (уже отправленный заголовок) с

контроллер:

/** @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(); 

Это работает без файла шаблона. Но имхо это не очень красивое кодирование.

Альтернативный способ с шаблоном:

контроллер:

  /** @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; 

Посмотреть:

 <?php echo $sf_response->getRawValue()->getContent(); ?> 

Мое предпочтительное решение

 $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)); 

Нет необходимости использовать файл шаблона. Использование стандартного поведения symfony. Важно: файл шаблона должен быть представлен!

Я использовал два метода в зависимости от содержимого файла. Для документов, таких как документы Excel, я обычно использую такой подход:

 $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 

Выключение и выключение error_reporting связано с использованием PHPExcel для записи в поток.

Другой метод, который я использовал, использует метод sendContent() для sfResponse . Пример этого использования:

 $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; 

Оба подхода работают, и вам не нужен шаблон для отображения содержимого / файла.

Примечание. Отредактировано для добавления в $this->getResponse()->sendHttpHeaders() перед настройкой и отправкой содержимого

Вы можете сделать это с помощью простых php-функций:

 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(); } в 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(); }