Загрузите 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, но не создает загрузку. Что я делаю неправильно?
Ответы
Ответ 1
Если вы принудительно загружаете, вы можете перенаправить текущую страницу на ссылку загрузки. Поскольку ссылка создаст диалог загрузки, текущая страница (и ее состояние) будет сохранена на месте.
Основной подход:
$('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 script:
@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
, но сохранить копию в кеше. Я не совсем уверен в этом, но кажется довольно многообещающим.
Ответ 2
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'];
}
?>
Ответ 3
Лучший способ добиться этого - использовать URI данных следующим образом:
- Сделать вызов AJAX на сервере в соответствии с нормальным
- Сгенерировать CSV на стороне сервера
- Возвращает данные (как голые, так и внутри структуры JSON)
- Создайте URI данных в Javascript, используя возвращаемые данные
- Установите window.location.href в URI данных
См. эту ссылку для инструкций (пункт 3, в частности): http://en.wikipedia.org/wiki/Data_URI_scheme
Таким образом, вам не нужно сохранять какие-либо файлы на сервере, и вам также не нужно использовать iframes или скрытые элементы формы или любые такие хаки.
Ответ 4
Я не думаю, что вы можете сделать загрузку браузера с помощью запроса AJAX/JS. Попробуйте использовать скрытый iframe, который перемещается на страницу, которая генерирует CSV
Ответ 5
Ну, с точки зрения использования AJAX следует избегать видимой перезагрузки страницы. Если вы хотите загрузить, вам нужно обратное, - новый запрос от браузера. Я бы сказал, просто создайте простую кнопку, указывающую на вашу php-страницу.
Ответ 6
Чтобы эхо и расширять то, что говорили другие, вы не можете отправить файл с помощью AJAX. Одной из причин этого является (и кто-то поправьте меня, если я ошибаюсь в этом, пожалуйста), что страница, на которой вы сейчас находитесь, отправила свои заголовки содержимого; вы не можете отправить их снова в одно и то же окно, даже с запросом AJAX (это то, что пытается сделать ваш PHP файл).
То, что я делал ранее в проектах, - это просто предоставить ссылку (с target = "_ blank" или javascript redirect) на отдельную страницу загрузки PHP. Если вы используете Apache, проверьте также файл mod_xsend.