Загрузите CSV-файл с помощью «AJAX»

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

Я многое выяснял, кроме собственно генерации файла csv. (Я использую jQuery и PHP)

код jQuery запускается при нажатии:

hmis_query_csv_export: function(query_name) { $.uiLock('<p>Query Loading.</p><img src="/images/loading.gif" />') $.get({ url: '/php_scripts/utils/csv_export.php', data: {query_name: query_name}, success: function(data) { $.uiUnlock(); } });} 

соответствующий PHP:

 header("Content-type: text/x-csv"); header("Content-Disposition: attachment; filename=search_results.csv"); // //Generate csv // echo $csvOutput exit(); 

То, что это делает, отправляет текст как файл PHP, но он не создает загрузку. Что я делаю не так?

Related of "Загрузите CSV-файл с помощью «AJAX»"

Если вы принудительно загружаете, вы можете перенаправить текущую страницу на ссылку загрузки. Поскольку ссылка создаст диалог загрузки, текущая страница (и ее состояние) будет сохранена на месте.

Основной подход:

 $('a#query_name').click(function(){ $('#wait-animation').show(); document.location.href = '/php_scripts/utils/csv_export.php?query_name='+query_name; $('#wait-animation').hide(); }); 

Сложнее:

 $('a#query_name').click(function(){ MyTimestamp = new Date().getTime(); // Meant to be global var $('#wait-animation').show(); $.get('/php_scripts/utils/csv_export.php','timestamp='+MyTimestamp+'&query_name='query_name,function(){ document.location.href = '/php_scripts/utils/csv_export.php?timestamp='+MyTimestamp+'&query_name='+query_name; $('#wait-animation').hide(); }); }); 

В скрипте PHP:

 @header("Last-Modified: " . @gmdate("D, d MYH:i:s",$_GET['timestamp']) . " GMT"); @header("Content-type: text/x-csv"); // If the file is NOT requested via AJAX, force-download if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') { header("Content-Disposition: attachment; filename=search_results.csv"); } // //Generate csv // echo $csvOutput exit(); 

URL-адрес для обоих запросов должен быть одинаковым, чтобы обмануть браузер, чтобы не запускать новую загрузку в document.location.href , но сохранить копию в кеше. Я не совсем уверен в этом, но кажется довольно многообещающим.

EDIT Я просто попробовал это с 10 МБ-файлом, и кажется, что val () слишком медленный, чтобы вставлять данные. Hurrumph.


Хорошо, поэтому я дал это другому. Это может быть или не быть абсолютно безумным! Идея состоит в том, чтобы сделать запрос AJAX для создания данных, затем использовать обратный вызов для вставки данных в скрытую форму на текущей странице, которая имеет действие третьей страницы «загрузки»; после вставки, форма автоматически отправляется, страница загрузки отправляет заголовки и перекликается с POST и et voila, загружается.

Все это время на исходной странице есть указание, что файл готов, а когда он заканчивается, индикатор обновляется.

ПРИМЕЧАНИЕ. Этот тестовый код не тестируется широко и не имеет реальных проверок безопасности (или вообще никаких). Я протестировал его с файлом CSV размером 1,5 МБ, который я проложил, и это было достаточно быстро.

Index.html

 <a id="downloadlink" href="#">Click Me</a> <div id="wait"></div> <form id="hiddenform" method="POST" action="download.php"> <input type="hidden" id="filedata" name="data" value=""> </form> 

test.js

 $(document).ready(function(){ $("#downloadlink").click(function(){ // click the link to download lock(); // start indicator $.get("create.php",function(filedata){ // AJAX call returns with CSV file data $("#filedata").val(filedata); // insert into the hidden form unlock(); // update indicator $("#hiddenform").submit(); // submit the form data to the download page }); }); function lock(){ $("#wait").text("Creating File..."); } function unlock(){ $("#wait").text("Done"); } }); 

create.php

 <?php //create $data print $data; ?> 

download.php

 <?php header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Content-Type: text/x-csv"); header("Content-Disposition: attachment;filename=\"search_results.csv\""); if($_POST['data']){ print $_POST['data']; } ?> 

Лучший способ добиться этого – использовать URI данных следующим образом:

  1. Сделать вызов AJAX сервером в соответствии с нормальным
  2. Сгенерировать CSV на стороне сервера
  3. Верните данные (как голые, так и внутри структуры JSON)
  4. Создайте URI данных в Javascript, используя возвращаемые данные
  5. Установите window.location.href в URI данных

См. Эту ссылку для инструкций (пункт 3, в частности): http://en.wikipedia.org/wiki/Data_URI_scheme

Таким образом, вам не нужно сохранять какие-либо файлы на сервере, и вам также не нужно использовать iframes или скрытые элементы формы или любые подобные хаки.

Я не думаю, что вы можете сделать загрузку браузера с помощью запроса AJAX / JS. Попробуйте использовать скрытый iframe, который перемещается на страницу, которая генерирует CSV

Ну, с точки зрения использования AJAX следует избегать видимой перезагрузки страницы. Если вы хотите загрузить, вам нужно обратное, – новый запрос от браузера. Я бы сказал, просто создайте простую кнопку, указывающую на вашу php-страницу.

Чтобы повторять и расширять то, что говорили другие, вы не можете отправить файл с помощью AJAX. Одной из причин этого является (и кто-то поправьте меня, если я ошибаюсь в этом, пожалуйста), что страница, на которой вы сейчас находитесь, отправила свои заголовки содержимого; вы не можете отправить их снова в одно и то же окно, даже с помощью запроса AJAX (это то, что пытается сделать ваш PHP-файл).

То, что я делал раньше в проектах, – это просто предоставить ссылку (с target = "_ blank" или javascript redirect) на отдельную страницу загрузки PHP. Если вы используете Apache, проверьте также файл mod_xsend.