Javascript 如何将文件传递到PHP并在一个脚本中下载回来?

Javascript 如何将文件传递到PHP并在一个脚本中下载回来?,javascript,php,html,Javascript,Php,Html,对不起,我很确定有一天我也看到过类似的问题,但我找不到,我自己也弄不明白 我需要能够在本地保存JSON文件,但下载属性和文件API对浏览器不够友好,因此我决定将JSON字符串发送到服务器,并让服务器向我发送带有正确HTTP头的文件,以使浏览器下载它 但我不想离开这一页。据我所见,AJAX无法触发文件下载(或者我一直在尝试错误),因此我必须使用隐藏的HTML表单,通过POST发送数据。如何将POST数据发送到php文件,该文件将返回要下载的文件而不离开页面 我在AJAX中尝试的是: sd.requ

对不起,我很确定有一天我也看到过类似的问题,但我找不到,我自己也弄不明白

我需要能够在本地保存JSON文件,但下载属性和文件API对浏览器不够友好,因此我决定将JSON字符串发送到服务器,并让服务器向我发送带有正确HTTP头的文件,以使浏览器下载它

但我不想离开这一页。据我所见,AJAX无法触发文件下载(或者我一直在尝试错误),因此我必须使用隐藏的HTML表单,通过POST发送数据。如何将POST数据发送到php文件,该文件将返回要下载的文件而不离开页面

我在AJAX中尝试的是:

sd.requestDownload = function() {
  if(sd.request && sd.request.readyState != 0) {
    return false; // there's already a request in progress
  }

  sd.request = sd.createRequest();

  sd.request.onreadystatechange = function() {
    if(sd.request.readyState == 4 && (sd.request.status == 200 || sd.request.status == 0)) {
      // download?
    } else if(sd.request.readyState < 4) {
      // show loading screen here
    }
  }

  sd.request.open("POST", "save.php", true);
  sd.request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  sd.request.send("json=" + encodeURIComponent(sd.saveToJSON()));
};
sd.requestDownload=function(){
if(sd.request&&sd.request.readyState!=0){
return false;//已经有一个请求在进行中
}
sd.request=sd.createRequest();
sd.request.onreadystatechange=函数(){
if(sd.request.readyState==4&&(sd.request.status==200 | | sd.request.status==0)){
//下载?
}否则如果(sd.request.readyState<4){
//在此显示加载屏幕
}
}
open(“POST”,“save.php”,true);
setRequestHeader(“内容类型”,“应用程序/x-www-form-urlencoded”);
sd.request.send(“json=“+encodeURIComponent(sd.saveToJSON()));
};
PHP代码:

<?PHP

session_start();

$file = '';

if(isset($_POST['json'])) {
  header('Content-Type: application/json; charset=utf-8');
  header('Content-Disposition: attachment; filename=plan.json');
  $file = $_POST['json'];
} else if(isset($_POST['file'])) {
  header('Content-Type: application/octet-stream; charset=utf-8');
  header('Content-Disposition: attachment; filename=plan');
  $file = $_POST['file'];
} else {
  http_response_code(400);
  $file = '400 ERROR: NO FILE RECEIVED';
}

header('Expires: Sun, 01 Jan 2015 00:00:00 GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', FALSE);
header('Pragma: no-cache');

echo htmlentities($file);

我已经找到了一些可行的方法,但是IE显示了一个关于调试器中缺少doctype的错误。我的解决方案是在JS中创建一个表单,而不将其附加到页面。如果HTTP头表示它是一个文件附件,则页面不会更改。我见过有人谈论将目标设置为iframe或“_blank”以获得额外的安全性,但Chrome将此类调用视为弹出窗口,因此它会阻止它们,如果用户单击“显示弹出窗口”,它不会再次发送POST请求

编辑:如果表单不在页面上,IE似乎会忽略对submit()的调用。因此,我修改了代码

这个问题让我产生了这样的想法:

PHP

JS


如果您导航到发送标题以强制下载的页面,用户将不会被导航到当前页面之外。他们只会被提示下载并停留在同一页面上。
if(isset($_POST['filecontent'])) {
  header('Content-Type: application/octet-stream; charset=utf-8');
  if(isset($_POST['filename'])) {
    header('Content-Disposition: attachment; filename=' . preg_replace('/[^a-zA-Z0-9_\.]+/', "", $_POST['filename']));
  } else {
    header('Content-Disposition: attachment;');
  }
  $file = $_POST['filecontent'];
} else {
  http_response_code(400);
  $file = '400 ERROR: NO FILE RECEIVED';
}

header('Expires: Sun, 01 Jan 2015 00:00:00 GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', FALSE);
header('Pragma: no-cache');

echo $file;
download = function(filename, filecontent) {
  var form = document.createElement("form");
  form.setAttribute("method", "post");
  form.setAttribute("action", "save.php");
  form.style.display = "none";
  var i = document.createElement("input");
  i.setAttribute("type", "hidden");
  i.setAttribute("name", "filename");
  i.setAttribute("value", filename);
  form.appendChild(i);
  i = document.createElement("input");
  i.setAttribute("type", "hidden");
  i.setAttribute("name", "filecontent");
  i.setAttribute("value", filecontent);
  form.appendChild(i);

  document.body.appendChild(form);
  form.submit();
  document.body.removeChild(form);
};