12

在一个基于 PHP 的网站上,我想在用户填写一个简短的表格后向他们发送一个下载包。由站点启动的下载应该类似于像 download.com 这样的站点,它们说“您的下载将立即开始”。

我知道的几种可能的方法,以及浏览器兼容性(基于快速测试):

1)做一个window.open指向新文件。

- FireFox 3 blocks this.  
 - IE6 blocks this.  
 - IE7 blocks this.

2) 创建一个指向新文件的 iframe。

- FireFox 3 seems to think this is OK. (Maybe it's because I already accepted it once?)  
 - IE6 blocks this.  
 - IE7 blocks this.

How can I do this so that at least these three browsers will not object? 

奖励:是否有不需要浏览器条件语句的方法?

(我相信 download.com 有条件地使用了这两种方法,但我无法让其中任何一种工作。)

回应和澄清:

Q: "Why not point the current window to the file?"  
A: That might work, but in this particular case, I want to show them some other content while their download starts - for example, "would you like to donate to this project?"

更新:我已经放弃了这种方法。原因请参阅下面的答案。

4

11 回答 11

16

您还可以进行大多数浏览器支持的元刷新。Download.com 将一个放在 noscript 标记中。

<meta http-equiv="refresh" content="5;url=/download.php?doc=123.zip"/>
于 2008-09-13T15:18:14.707 回答
15

更新:我决定放弃这种方法,而只是向用户提供指向实际文件的链接。我的理由是这样的:

浏览器阻止了我最初尝试从服务器启动的下载。这让我想到:“浏览器是正确的。怎么知道这是合法下载?它应该阻止显然不是用户启动的下载。”

我可以用于服务器启动下载的任何方法可以被想要发送恶意软件的人使用。因此,只有当用户通过单击文件的链接来明确请求文件时,才应进行下载。

你可以不同意,如果你仍然想开始下载,希望这个帖子能帮助你。

于 2008-09-16T14:52:18.050 回答
5

我通常只有一个 PHP 脚本,它使用适当的 Content-Type 将文件直接输出到浏览器

if(file_exists($filename)) {
    header("Pragma:  public");
    header("Expires:  0");
    header("Cache-Control:  must-revalidate, pre-check=0");
    header("Cache-Control:  private", false);
    header("Content-Type:  " . $content-type);
    header("Content-Disposition:  attachment; filename=\"" . basename($filename) . "\";" );
    header("Content-Transfer-Encoding:  binary");
    header("Content-Length:  " . filesize($filename));

    readfile("$filename");
}else{
    print "ERROR:  the file " . basename($filename) . " could not be downloaded because it did not exist.";
}

唯一的缺点是,由于这设置了 HTTP 标头,因此在您获得任何其他输出之前已调用它。

但是你可以有一个指向 PHP 下载页面的链接,它会导致浏览器弹出一个下载框,而不会弄乱当前页面的内容。

于 2008-09-13T15:13:45.717 回答
1

一个问题是,如果标头没有“正确”设置,您可能会遇到 IE(特别是版本 6)的问题。

确保设置正确的 Content-Type,但也要考虑为 IE 设置缓存选项(至少)以允许缓存。如果文件是一个用户可以打开而不是保存的文件(例如 MS Word 文档),IE 的早期版本需要缓存文件,因为他们将“打开”请求传递给适用的应用程序,指向下载的文件在缓存中。

还有一个相关的问题,如果 IE6 用户的缓存已满,它将无法正确保存文件(因此当适用的应用程序伸手打开它时,它会抱怨文件已损坏。

您可能还想关闭下载的任何 gzip 操作(对于 IE)

IE6/IE7 都存在大量下载问题(例如 4.x Gigs...),这不太可能发生,因为 IE 甚至没有下载管理器,但需要注意一些事情。

最后,如果从嵌套 iframe 中启动下载“推送”,IE6 有时不能很好地处理它。我不确定是什么触发了这个问题,但我发现使用 IE6 更容易避免这种情况。

于 2008-09-15T13:32:27.020 回答
1

喂!

@Nathan:我决定这样做:让我的“getfile.php”加载所有必要的东西,然后做一个

header("Location: ./$path/$filename");

让浏览器本身并直接对文件执行它认为正确的任何操作。这甚至在我的 Opera 中也能正常工作。

但这在不允许直接访问文件的环境中是个问题,在这种情况下,您将不得不找到不同的方法!(感谢 Discordia,我的文件是公共 PDF!)

最好的问候, 巴斯蒂

于 2008-09-22T13:03:01.733 回答
0

如何更改位置以指向新文件?(例如通过改变 window.location)

于 2008-09-13T15:06:41.770 回答
0

我一直只是制作一个指向该文件的 iframe。

<iframe src="/download.exe" frameborder="0" height="0" width="0"><a href="/download.exe">Click here to download.</a></iframe>
于 2008-09-13T15:37:52.240 回答
0

关于不将当前窗口指向下载。根据我的经验,您仍然可以显示您的“请捐赠”页面,因为下载(只要它们发送正确的标题)实际上不会更新浏览器窗口。我在我的一个站点上为 csv 导出执行此操作,就用户而言,它只是弹出一个安全文件窗口。所以我会推荐一个简单的元重定向,就像 Soldarnal 展示的那样。

于 2008-09-15T11:56:47.700 回答
0

总结一下,你有两个目标:

  1. 开始下载过程
  2. 向用户显示带有捐赠选项的页面

为此,我将执行以下操作:

当您的用户提交表单时,他会得到带有捐赠选项的结果页面和一条说明他的下载将在 5 秒后开始的文字。在此页面的头部,您将 META 代码作为 Soldarnal 所说: <meta http-equiv="refresh" content="5;url=/download.php?doc=123.zip>

就这样。

于 2008-09-15T12:49:01.490 回答
0
<a href="normaldownload.zip" onclick="use_dhtml_or_ajax_to_display_page()">

如果保存下载,当前页面不受影响。只要确保下载不会在同一窗口中打开(正确的 MIME 类型或Content-Disposition),您就可以显示任何内容。

查看更多完整答案

于 2009-04-07T23:40:30.300 回答
0

您可以使用 Javascript/jQuery 来启动下载。这是一个示例 - 您可以摆脱 Ajax 请求,只使用 setTimeout() 块。

$("btnDownloadCSV").on('click', function() {
    $.ajax({
        url: "php_backend/get_download_url",
        type: 'post',
        contentType: "application/x-www-form-urlencoded",
        data: {somedata: "somedata"},
        success: function(data) {
            // If iFrame already exists, remove it.
            if($("[id^='iframeTempCSV_"]).length) { 
                $("[id^='iframeTempCSV_"]).remove();
            }
            setTimeout(function() {
                //  If I'm creating an iframe with the same id, it will permit download only the first time.
                // So randHashId appended to ID to trick the browser.
                var randHashId = Math.random().toString(36).substr(2);
                // Create a fresh iFrame for auto-downloading CSV
                $('<iframe id="iframeTempCSV_'+randHashId+'" style="display:none;" src="'+data.filepath+'"></iframe>').appendTo('body');
            }, 1000);
        },
        error: function(xhr, textStatus, errorThrown) {
           console.error("Error downloading...");
       }
    });
});
于 2015-04-17T07:01:30.633 回答