Как принудительно загрузить CSV файл в Symfony 2, используя объект Response? - программирование
Подтвердить что ты не робот

Как принудительно загрузить 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 раньше? Если да, то что я делаю неправильно?

4b9b3361

Ответ 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.