发起下载的最佳方式?

时间:2008-09-13 15:00:29

标签: php javascript download

在基于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? 

Bonus:有没有一个方法不需要浏览器条件语句?

(我相信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?"

更新:我放弃了这种做法。请参阅下面的答案。

11 个答案:

答案 0 :(得分:16)

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

<meta http-equiv="refresh" content="5;url=/download.php?doc=123.zip"/>

答案 1 :(得分:15)

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

我最初尝试在服务器启动的下载时被浏览器阻止了。这让我想到:“浏览器是正确的。如何知道这是一个合法的下载?应该阻止显然不是用户启动的下载。 “

我可以用于服务器启动的下载的任何方法可供想要发送恶意软件的人使用。因此,只有当用户通过单击链接专门请求文件时才会发生下载。

您可以自由地反对意见,如果您仍想开始下载,希望此主题可以帮助您完成此任务。

答案 2 :(得分: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下载页面,这将导致浏览器弹出下载框而不会弄乱当前页面的内容。

答案 3 :(得分:1)

如果标题未正确设置,您可能会遇到IE(特别是版本6)的问题。

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

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

您可能还希望在下载中转换任何gzip操作(对于IE)

IE6 / IE7都存在大量下载问题(例如4.x Gigs ......),因为IE甚至没有下载管理器,所以不太可能出现问题,但需要注意的事项。

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

答案 4 :(得分:1)

海!

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

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

让浏览器本身并直接做任何它认为正确的文件。这对我来说甚至在Opera中运行良好。

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

最好的问候,Basty

答案 5 :(得分:0)

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

答案 6 :(得分:0)

我总是制作一个指向文件的iframe。

<iframe src="/download.exe" frameborder="0" height="0" width="0"><a href="/download.exe">Click here to download.</a></iframe>

答案 7 :(得分:0)

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

答案 8 :(得分:0)

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

  1. 开始下载过程
  2. 向用户显示包含捐赠选项的页面
  3. 要实现这一点,我会做以下事情:

    当您的用户提交表单时,他会在结果页面中显示捐赠选项和文本,说明他的下载将在5秒后开始。在本页的头部,您将META代码作为Soldarnal说: &lt; meta http-equiv =“refresh”content =“5; url = / download.php?doc = 123.zip&gt;

    就是这样。

答案 9 :(得分:0)

<a href="normaldownload.zip" onclick="use_dhtml_or_ajax_to_display_page()">

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

See more complete answer

答案 10 :(得分: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...");
       }
    });
});