2012-04-12 4 views
4

Я пытаюсь экспортировать данные из базы данных в .csv. Когда я нажимаю ссылку на экспорт, я не вижу окна сохранения в браузере очень долго, если данных достаточно много. Это может быть довольно запутанным, если сценарий выглядит как повешение в течение некоторого времени, и через довольно долгое время можно увидеть окно сохранения в браузере. код что-то вроде этого в контроллере:Почему не загружается окно в браузере долгое время, когда я экспортирую данные

$this->_helper->layout->disableLayout(); 
     $this->_helper->viewRenderer->setNoRender(); 
     $fileName = $list->list_name . '.csv'; 

     $this->getResponse()->setHeader('Content-Type', 'text/csv; charset=utf-8') 
          ->setHeader('Content-Disposition', 'attachment; filename="'. $fileName . '"');  

     $contacts = new Contact(); 
     $contacts->export($listId); 

Метод экспорта читает записи по одному и печатает это что-то вроде этого:

$fp = fopen('php://output', 'w');   
    foreach ($mongodbCursor as $subscriber) { 
      $row = formRow($subscriber); 
     fputcsv($fp, $row); 
     }  

я вижу на некоторых приложениях, которые экономят winow появляются почти сразу и когда вы нажимаете «Сохранить», вы видите ход загрузки.

Я попытался заменить:

$this->getResponse()->setHeader('Content-Type', 'text/csv; charset=utf-8') 
         ->setHeader('Content-Disposition', 'attachment; filename="'. $fileName . '"'); 

с этим:

header('Content-Type: text/csv; charset=utf-8'); 
    header('Content-Disposition: attachment; filename="'. $fileName . '"'); 

Это не помогло до сих пор. Интересно, можно ли отправлять заголовки, прежде чем все данные будут считываться один за другим из базы данных? Благодарим вас за помощь.

ответ

1

Хмм я не знаком с выходом php: //, мое приложение записывает мою информацию с помощью fopen, fwrite, fclose во временный файл, после чего я выдаю его с похожим заголовком(); опции.

  $filesize = filesize("tmp/export.csv"); 
      header("Content-Type: text/csv"); 
      header("Content-Disposition: attachment; filename=\"export.csv\""); 
      header("Conent-Length: $filesize"); 
      readfile("tmp/export.csv"); 
      unlink("tmp/export.csv"); 
      exit; 

Это дает окно загрузки вашего браузера мгновенно.

+0

Какой максимальный размер файла вы экспортировали следующим образом? – Oleg

+0

Я тебя не понимаю прямо сейчас, какой импорт? Этот кусок кода состоит в том, чтобы выдать cvs, тот же сценарий написал несколько строк над ним. Максимальный размер файла неограничен (в моем случае он считывает записи в базе данных, никаких проблем даже при экспорте тысяч записей одновременно) – peipst9lker

+0

Pardon, я имел в виду экспорт, я его исправляю. – Oleg

1

Вы могли бы попытаться сделать это:

  • вызов заголовка функции вместо $this->getResponse()->setHeader() (содержание ответа может быть сохранен в буфере и outputed только тогда, когда оно будет завершено - время экспорт заканчивается)
  • пытаются повторить содержание непосредственно вместо того, чтобы писать на PHP: // вывод (если установить заголовки перед тем, что все, что вы эхо будет помещен в созданный файл CSV)

EDIT

Заменить fputcsv с функцией как print_row ниже

function print_row($row) { 
     echo '"' . implode('","', $row) . '"' . "\r\n"; 
} 

Функция получает первый параметр как массив, добавляет " и , и эхо к содержимому.

+0

Не могли бы вы рассказать мне, как заменить: \t \t $ fp = fopen ('php: // output', 'w'); \t \t \t fputcsv ($ fp, $ row); Что вы имеете в виду эхо напрямую? Вы хотите эхо-значения полей, команд, новых строк вручную? – Oleg

+0

Да, я имею в виду, что вы можете эхо напрямую привязать каждую строку CSV к «значению», «value2» \ r \ n'. Я отредактирую ответ и добавлю примерную функцию, которую вы могли бы использовать. –

+0

Я попытался заменить функции заголовка вместо методов класса ответа, теперь это не помогло. – Oleg

0
// $file = path of file 

header('Content-Description: File Transfer'); 
header('Content-Type: application/octet-stream'); 
header('Content-Disposition: attachment; filename='.basename($file)); 
header('Content-Transfer-Encoding: binary'); 
header('Expires: 0'); 
header('Cache-Control: must-revalidate'); 
header('Pragma: public'); 
header('Content-Length: ' . filesize($file)); 
ob_clean(); 
flush(); 
readfile($file); 
exit; 

Источник: http://php.net/manual/en/function.readfile.php

+0

Не могли бы вы объяснить свою идею и что не так с моим кодом? – Oleg

+0

Моя идея заставляет скачивать файлы из файла, и я понятия не имею, что не так с вашим кодом. – MakuraYami

+0

Это, похоже, не отвечает на мой вопрос. – Oleg

0

Попробуйте использовать application/force-download вместо text/csv в вашем Content-Type значения.

header("Content-Type: application/force-download; name=\"" . $fileName . "\""); 

Это заставит фактическое окно загрузки вместо того, чтобы просто показывать содержимое в браузере.

Вот некоторые документы из MIME Application:

Мим приложение/принудительная загрузка, которая обычно выражаются как приложения мима/X-Force-загрузка, как правило, используется в сочетании с PHP кодом, чтобы вызвать загрузку а не для отображения содержимого в веб-браузере.

Например, если у вас есть файл на вашем веб-сайте, который вы хотите загрузить, а не просматривать в веб-браузере, вы можете ввести соответствующее поле mime application/force-download в поле типа содержимого заголовка файла. Обратите внимание: mime application/force-download не является зарегистрированным типом MIME. Кроме того, при использовании в PHP-коде предпочтительная написание mime-приложения/force-download содержит префикс «x-».

+0

Вы хотите использовать такие заголовки: header ('Content-Type: application/force-download; charset = utf-8'); \t \t \t \t \t header ('Content-Disposition: attachment; filename = "'. $ FileName. '"'); – Oleg

+0

Кажется, проблема заключается в том, что мои заголовки отправляются только после получения данных из базы данных, за это время заголовки не отправляются клиенту. Поэтому я не уверен, что это проблема с каким-то заголовком, поскольку они не отправляются довольно долго. Это не похоже на стандартный мим, который может вызвать много проблем, – Oleg

+0

Я попытался использовать вышеупомянутые заголовки, это не похоже на помощь. – Oleg

0

Я не знаю, было ли это хорошим решением, я не исследовал его много, но, похоже, он работает. Это котроллер после добавления некоторых данных в буфер после заголовков, перед экспортом.

header('Content-Type: text/csv; charset=utf-8'); 
    header('Content-Disposition: attachment; filename="'. $fileName . '"'); 

    echo str_pad('', ini_get('output_buffering'));  
    ob_flush(); 
    flush(); 

    Model_Subscriber1::exportList($listId); 

Для того, чтобы он работает в контроллере я добавил в Zend Bootstrap.php:

/** 
* hint to the dispatcher that it should not use output buffering to capture output generated by action controllers. 
* By default, the dispatcher captures any output and appends it to the response object body content. 
*/ 
protected function _initFront() 
{ 
    $frontController = Zend_Controller_Front::getInstance(); 
    $frontController->setParam('disableOutputBuffering', 1);   
} 

Он выглядит в этом случае я получаю окно загрузки в браузере быстро, а затем данные экспорта, которые могли бы занять довольно долго. Я не знаю, приемлемо ли это решение сейчас. Я был бы рад узнать ваше мнение об этом. Это вызывает проблемы с добавлением пустых данных для экспорта файла. Итак, я меняю его на контроллер.

header('Content-Type: text/csv; charset=utf-8'); 
    header('Content-Disposition: attachment; filename="'. $fileName . '"'); 

    Model_Subscriber1::exportList($listId); 

И функция чан для экспорта в чем-то вроде этого:

foreach ($mongodbCursor as $subscriber) { 
      $row = formRow($subscriber); 
    echo '"' . implode('","', $row) . '"' . "\r\n"; 
    ob_flush(); 
    flush();      

    }  
0

Ваша функция может понадобиться вызвать флеш/ob_flush непосредственно перед длительной эксплуатации и пусть заголовок HTTP отправить клиента перед длительным процессом.