php 使用“AJAX”下载 CSV 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3346072/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 09:24:53  来源:igfitidea点击:

Download CSV file using "AJAX"

phpajaxcsv

提问by The_Denominater

I'm trying to accomplish a fairly simple task for my website, but I"m not sure exactly how to go about it. I want the user to be viewing a table, then click a button, at which point the user can save the contents of that table as a csv file. This request can sometimes be quite complicated so I generate a progress page to alert the user.

我正在尝试为我的网站完成一项相当简单的任务,但我不确定如何去做。我希望用户查看表格,然后单击一个按钮,此时用户可以保存该表的内容作为 csv 文件。这个请求有时可能非常复杂,所以我生成了一个进度页面来提醒用户。

I have most things figured out except actually generating the csv file. (I use jQuery and PHP)

除了实际生成 csv 文件之外,我已经弄清楚了大多数事情。(我使用 jQuery 和 PHP)

the jQuery code run on click:

单击时运行的 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();
        }
    });}

the relevant PHP:

相关的PHP:

header("Content-type: text/x-csv");
header("Content-Disposition: attachment; filename=search_results.csv");
//
//Generate csv
//
echo $csvOutput
exit();

What this does is sends the text as the PHP file, but it's doesn't generate a download. What am I doing wrong?

这样做是将文本作为 PHP 文件发送,但它不会生成下载。我究竟做错了什么?

回答by Ast Derek

If you are forcing a download, you can redirect the current page to the download link. Since the link will generate a download dialog, the current page (and its state) will be kept in place.

如果您要强制下载,则可以将当前页面重定向到下载链接。由于该链接将生成一个下载对话框,因此当前页面(及其状态)将保持不变。

Basic approach:

基本方法:

$('a#query_name').click(function(){
    $('#wait-animation').show();
    document.location.href = '/php_scripts/utils/csv_export.php?query_name='+query_name;
    $('#wait-animation').hide();
});

More complicated:

更复杂:

$('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();
    });
});

At PHP script:

在 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();

The URL for both requests must be the same to trick the browser not to start a new download at document.location.href, but to save the copy at the cache. I'm not totally sure about it, but seems pretty promising.

两个请求的 URL 必须相同,以诱使浏览器不从 开始新的下载document.location.href,而是将副本保存在缓存中。我不完全确定,但似乎很有希望。

回答by godheadatomic

EDITI just tried this with a 10MB file and it seems that val() is too slow to insert the data. Hurrumph.

编辑我刚刚用一个 10MB 的文件尝试了这个,似乎 val() 插入数据太慢了。哼哼。



Okay, so I gave this one another go. This may or may not be completely insane! The idea is to make an AJAX request to create the data, then use the callback to insert the data into a hidden form on the current page which has an action of a third "download" page; after the insertion, the form is automatically submitted, the download page sends headers and echoes the POST, and et voila, download.

好的,所以我又试了一次。这可能是也可能不是完全疯了!这个想法是发出一个 AJAX 请求来创建数据,然后使用回调将数据插入到当前页面的隐藏表单中,该表单具有第三个“下载”页面的动作;插入后,表单会自动提交,下载页面发送标题并响应 POST,等等,下载。

All the while, on the original page you've got an indication that the file is being prepared, and when it finishes the indicator is updated.

一直以来,在原始页面上,您都会收到文件正在准备的指示,当它完成时,指示器会更新。

NOTE: this test code isn't tested extensively, and has no real security checks (or any at all) put in place. I tested it with a 1.5MB CSV file I had laying about and it was reasonably snappy.

注意:这个测试代码没有经过广泛的测试,也没有真正的安全检查(或根本没有)。我用一个 1.5MB 的 CSV 文件对它进行了测试,它相当活泼。

Index.html

索引.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

测试.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

<?php
//create $data
print $data;
?>

download.php

下载.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'];
}
?>

回答by Aquarelle

The best way to accomplish this is to use a Data URI as follows:

完成此操作的最佳方法是使用数据 URI,如下所示:

  1. Make the AJAX call to the server as per normal
  2. Generate the CSV on the server-side
  3. Return the data (either bare or inside a JSON structure)
  4. Create a Data URI in Javascript using the returned data
  5. Set window.location.href to the Data URI
  1. 按正常方式对服务器进行 AJAX 调用
  2. 在服务器端生成 CSV
  3. 返回数据(裸数据或在 JSON 结构内)
  4. 使用返回的数据在 Javascript 中创建数据 URI
  5. 将 window.location.href 设置为数据 URI

See this link for instructions (paragraph #3, specifically): http://en.wikipedia.org/wiki/Data_URI_scheme

请参阅此链接以获取说明(特别是第 3 段):http: //en.wikipedia.org/wiki/Data_URI_scheme

This way, you don't need to save any files on the server, and you also don't need to use iframes or hidden form elements or any such hacks.

这样,您不需要在服务器上保存任何文件,也不需要使用 iframe 或隐藏的表单元素或任何此类技巧。

回答by Bob Fincheimer

I don't think you can make the browser download using a AJAX/JS request. Try using a hidden iframe that navigates to the page which generates the CSV

我认为您不能使用 AJAX/JS 请求进行浏览器下载。尝试使用导航到生成 CSV 的页面的隐藏 iframe

回答by Nicolas78

Well the point of using AJAX is to avoid a visible reload of the page. If you want a download, you want the opposite,- a brand new request from the browser. I'd say, just create a simple button pointing to your php page.

嗯,使用 AJAX 的目的是避免页面的可见重新加载。如果您想要下载,则需要相反的内容——来自浏览器的全新请求。我想说,只需创建一个指向您的 php 页面的简单按钮即可。

回答by godheadatomic

To echo and expand on what others have said, you can't really send the file using AJAX. One of the reasons for this is (and someone correct me if I'm wrong on this, please) that the page you're currently on already has sent its content headers; you can't send them again to the same window, even with an AJAX request (which is what your PHP file is attempting to do).

为了回应和扩展其他人所说的内容,您不能真正使用 AJAX 发送文件。原因之一是(如果我错了,请纠正我)您当前所在的页面已经发送了其内容标题;即使使用 AJAX 请求(这是您的 PHP 文件试图执行的操作),您也无法将它们再次发送到同一个窗口。

What I've done before in projects is to simply provide a link (with target="_blank" or javascript redirect) to a separate download PHP page. If you're using Apache, check out mod_xsendfile as well.

我之前在项目中所做的只是提供一个链接(使用 target="_blank" 或 javascript 重定向)到单独的下载 PHP 页面。如果您使用的是 Apache,也请查看 mod_xsendfile。