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