Загрузите файл CSV, используя «AJAX» - PullRequest
25 голосов
/ 27 июля 2010

Я пытаюсь выполнить довольно простую задачу для своего веб-сайта, но я не уверен, как именно это сделать. Я хочу, чтобы пользователь просматривал таблицу, а затем нажмите кнопку, после чего пользовательможет сохранить содержимое этой таблицы в виде файла 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, но он не генерирует загрузку. Что я делаю не так?

Ответы [ 6 ]

43 голосов
/ 27 июля 2010

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

Базовый подход:

$('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 M Y H: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, а для сохранения копии в кеше.Я не совсем уверен в этом, но кажется довольно многообещающим.

5 голосов
/ 27 июля 2010

РЕДАКТИРОВАТЬ Я только что попробовал это с файлом 10 МБ, и кажется, что val () слишком медленно для вставки данных. Hurrumph.


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

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

ПРИМЕЧАНИЕ: этот тестовый код не тестировался всесторонне и не имеет реальных проверок безопасности (или вообще никаких). Я протестировал его с 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'];
}
?>
3 голосов
/ 15 апреля 2015

Лучший способ сделать это - использовать 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, скрытые элементы формы или любые подобные хаки.

1 голос
/ 27 июля 2010

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

0 голосов
/ 27 июля 2010

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

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

0 голосов
/ 27 июля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...