Я пытаюсь выполнить довольно простую задачу для своего веб-сайта, но я "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, но это, не генерирует загрузку. Что я делаю неправильно?
Если вы принудительно загружаете файл, вы можете перенаправить текущую страницу на ссылку загрузки. Поскольку ссылка создаст диалог загрузки, текущая страница (и ее состояние) будет сохранена.
Основной подход:
$('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
, а сохранить копию в кэше. Я не совсем уверен в этом, но выглядит довольно многообещающе.
Ну, смысл использования AJAX в том, чтобы избежать видимой перезагрузки страницы. Если вам нужна загрузка, вы хотите обратного - совершенно нового запроса от браузера. Я бы сказал, просто создайте простую кнопку, указывающую на вашу php-страницу.
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'];
}
?>
Чтобы повторить и расширить сказанное другими, вы действительно не можете отправить файл с помощью AJAX. Одна из причин этого заключается в том (и кто-нибудь поправьте меня, если я ошибаюсь, пожалуйста), что страница, на которой вы сейчас находитесь, уже отправила свои заголовки содержимого; вы не можете отправить их снова в то же окно, даже с помощью AJAX-запроса (что и пытается сделать ваш PHP-файл).
То, что я делал раньше в проектах, это просто предоставлял ссылку (с target="_blank" или javascript-перенаправлением) на отдельную PHP-страницу загрузки. Если вы используете Apache, проверьте также mod_xsendfile.
Я не думаю, что вы можете загрузить браузер с помощью запроса AJAX / JS. Попробуйте использовать скрытый iframe, который ведет на страницу, генерирующую CSV