Загрузите файл CSV с помощью “Ajax”

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

25
задан The_Denominater 27 July 2010 в 17:11
поделиться

5 ответов

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

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

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

43
ответ дан 28 November 2019 в 20:40
поделиться

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

0
ответ дан 28 November 2019 в 20:40
поделиться

EDIT Я только что попробовал это с файлом размером 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'];
}
?>
5
ответ дан 28 November 2019 в 20:40
поделиться

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

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

0
ответ дан 28 November 2019 в 20:40
поделиться

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

2
ответ дан 28 November 2019 в 20:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: