Как принудительно загрузить CSV файл в Symfony 2, используя объект Response?
Я делаю контроллер "Загрузка" с помощью Symfony 2, который имеет единственную цель - отправлять заголовки, чтобы я мог принудительно загрузить файл .csv, но он работает неправильно.
$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
является строкой "info.csv"
. Таковы мои действия внутри моего контроллера, нет возврата. Когда я попытался вернуть объект Response
, содержимое файла было отображено в браузере, а не мой предполагаемый результат.
Проблема, которую я обнаружил, заключается в том, что на некоторых страницах я получаю свой info.csv file
, но в других случаях я получаю сообщение:
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.
Я полностью уверен, что файл существует, поэтому должно быть другое дело. Кроме того, routing.yml работает правильно, так как я получаю файл с других страниц, которые также ссылаются на этот путь.
Журнал ошибок Apache ничего не сообщает об этом.
Кто-нибудь принудительно загрузил файл .csv на Symfony 2 раньше? Если да, то что я делаю неправильно?
Ответы
Ответ 1
Вот минимальный пример, который отлично работает в производстве:
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;
Вы можете заменить вызов рендеринга новым ответом и ответом- > setContent, если хотите.
Ваш комментарий об отсутствии оператора возврата внутри контроллера вызывает недоумение. Контроллеры возвращают ответ. Пусть структура позаботится о отправке материала в браузер.
Ответ 2
Я понимаю, что этот пост довольно старый и что, как ни странно, практически нет хороших ресурсов для того, как делать CSV Export в symfony 2 помимо этого сообщения в stackoverflow.
В любом случае я использовал приведенный выше пример для сайта конкурса клиентов, и он работал достаточно хорошо. Но сегодня я получил электронное письмо и после его тестирования сам код сломался - мне удалось получить загрузку с небольшим количеством результатов, но теперь база данных, экспортирующая более 31 000 строк, либо просто показывала текст, либо хром, просто ничего не сделал.
Для тех, кто имеет проблемы с большим экспортом данных, это то, к чему я привык работать, в основном делая то, что предложил Cerad как альтернативный способ:
$filename = "export_".date("Y_m_d_His").".csv";
$response = $this->render('AppDefaultBundle:Default:csvfile.html.twig', array('data' => $data));
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Description', 'Submissions Export');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
$response->headers->set('Content-Transfer-Encoding', 'binary');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');
$response->prepare();
$response->sendHeaders();
$response->sendContent();
EDIT: после большего количества тестов и увеличения максимально допустимых секунд я понял, что предыдущий код печатал заголовки сверху, поэтому я обновил код.
Ответ 3
Я работал для экспорта CSV и JSON.
Файлы Twig называются: export.csv.twig, export.json.twig
Контроллер:
class PrototypeController extends Controller {
public function exportAction(Request $request) {
$data = array("data" => "test");
$format = $request->getRequestFormat();
if ($format == "csv") {
$response = $this->render('PrototypeBundle:Prototype:export.' . $format . '.twig', array('data' => $data));
$filename = "export_".date("Y_m_d_His").".csv";
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
return $response;
} else if ($format == "json") {
return new Response(json_encode($data));
}
}
}
Маршрутизация:
prototype_export:
pattern: /export/{_format}
defaults: { _controller: PrototypeBundle:Prototype:export, _format: json }
requirements:
_format: csv|json
Веточки:
export.csv.twig(сделайте свою запятую отдельно, это просто тест)
{% for row in data %}
{{ row }}
{% endfor %}
export.json.twig(данные отправляются json_encoded, этот файл пуст)
Надеюсь, это поможет!
Ответ 4
Как насчет использования экспортера сонаты:
use Exporter\Writer\CsvWriter;
/**
* @param array $orders
*/
public function exportToCsv($orders)
{
$rootdir = $this->get('kernel')->getRootDir();
$filename = $rootdir . '/data/orders.csv';
unlink($filename);
$csvExport = new CsvWriter($filename);
$csvExport->open();
foreach ($orders as $order)
{
$csvExport->write($order);
}
$csvExport->close();
return;
}
Сбой, если файл уже существует, поэтому команда unlink-command.