【问题标题】:Best way to initiate a download?启动下载的最佳方式?
【发布时间】:2010-09-08 19:16:57
【问题描述】:

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

更新:我已经放弃了这种方法。原因见下面我的回答。

【问题讨论】:

    标签: php javascript download


    【解决方案1】:

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

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

    【讨论】:

    • 讨厌那些。我必须等待几秒钟才能下载,有时需要 1 秒钟。我的浏览器保存了浏览会话,这意味着当我重新启动浏览器时文件开始无处弹出。我无法复制链接或必须在页面上查找“如果...请单击此处”并停止自动下载。
    • 同意,但这是他最初要求的。
    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

      我通常只有一个 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下载页面的链接,它会导致浏览器弹出一个下载框,而不会弄乱当前页面的内容。

      【讨论】:

      • 马克 - 这一定是我的头;我不了解有关标题的任何内容。此方法是否允许您在下载开始时转到另一个页面?
      • 基本上你正在做的是读取文件的二进制内容并将二进制数据发送到浏览器而不是 HTML。 Content-Type 只是告诉浏览器它是什么类型的文件。尝试创建一个简单的页面,它只是我的代码 sn-p 并插入文件名和内容类型。
      • 需要了解的一些方便的内容类型是 application/zip pplication/pdf application/octet-stream application/access application/msword application/vnd.ms-excel application/vnd.ms-powerpoint image/gif image /png 图片/jpg
      • 您忽略了部分问题。 '由站点启动的下载应该类似于 download.com 之类的站点,上面写着“您的下载将在稍后开始。”'
      • 注意:您可以在snipplr.com/view.php?codeview&id=1937 以 $extension=>$mimeString 格式获得一个不错的 mime 类型数组
      【解决方案4】:

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

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

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

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

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

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

      【讨论】:

        【解决方案5】:

        喂!

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

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

        让浏览器自己直接对文件做任何它认为正确的事情。这甚至在我的 Opera 中也能正常工作。

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

        最好的问候,巴斯蒂

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            我一直只是创建一个指向该文件的 iframe。

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

            【讨论】:

              【解决方案8】:

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

              【讨论】:

                【解决方案9】:

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

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

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

                当您的用户提交表单时,他会得到一个带有捐赠选项的结果页面和一条说明他的下载将在 5 秒后开始的文字。在此页面的头部,您将 META 代码作为 Soldarnal 所说:

                【讨论】:

                  【解决方案10】:
                  <a href="normaldownload.zip" onclick="use_dhtml_or_ajax_to_display_page()">
                  

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

                  See more complete answer

                  【讨论】:

                    【解决方案11】:

                    您可以使用 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...");
                           }
                        });
                    });
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2011-08-17
                      • 1970-01-01
                      • 2020-11-03
                      • 2019-03-05
                      • 2010-10-04
                      • 1970-01-01
                      • 2010-11-03
                      • 2013-12-01
                      相关资源
                      最近更新 更多