Разумеется, некоторые другие люди обсуждали эту проблему в stackoverflow, но не все ansers работают для меня, и часто они не предоставляют версию установки Symfony.
Темы, которые я прочитал:
Я хочу спросить, как вы обрабатываете загрузки файлов в 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(); }