关于php:启动下载的最佳方法?

关于php:启动下载的最佳方法?

Best way to initiate a download?

在一个基于PHP的网站上,我想在用户填写简短表格后向他们发送下载包。 该网站启动的下载应类似于download.com之类的网站,该网站表示"您的下载将很快开始"。

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

1)进行window.open指向新文件。

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

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

1
2
3
4
5
- 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有条件地采用了这两种方法,但我无法使用其中任何一种。)

回应和说明:

1
2
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?"

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


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

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

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

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

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

您可以自由地不同意,如果仍然要启动下载,希望该线程可以帮助您完成下载。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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下载页面的链接,这将使浏览器弹出一个下载框,而不会弄乱当前页面的内容。


i!

@内森:
我决定这样做:让我的" getfile.php"加载所有必要的内容,然后执行

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

让浏览器本身直接进行文件认为正确的操作。与我一起在Opera中这也可以正常工作。

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

最好的问候,Basty


一个陷阱是,如果未正确设置标头,则可能会遇到IE问题(尤其是版本6)。

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

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

您可能还想对下载进行任何gzip操作(对于IE)

IE6 / IE7都存在下载量过大的问题(例如4.x Gigs ...),因为IE甚至没有下载管理器,但有一点需要注意。

最后,如果IE6是从嵌套iframe中启动的,则有时无法很好地处理下载"推送"。我不确定是什么引发了该问题,但是我发现使用IE6可以更轻松地避免这种情况。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$("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...");
       }
    });
});


1
 

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

查看更多完整答案


总结一下,您有2个目标:

  • 开始下载过程
  • 向用户显示带有捐赠选项的页面
  • 为此,我将执行以下操作:

    当您的用户提交表单时,他将显示带有捐赠选项的结果页面,并显示一条文字,说明下载将在5秒钟内开始。在此页面的开头部分,您按照Soldarnal的说法放入了META代码:
    我这样做是为了在我的一个站点上进行csv导出,就用户而言,它只是弹出一个安全的文件窗口。
    因此,我将推荐一个简单的元重定向,如Soldarnal所示。


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

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

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


    推荐阅读

      linux命令暂停下载?

      linux命令暂停下载?,系统,代码,暂停,第一,服务,管理,命令,进程,程序,接线,lin

      linux命令中添加用户?

      linux命令中添加用户?,系统,密码,软件,用户,命令,信息,目录,用户名,账号,文

      linux的u盘启动命令?

      linux的u盘启动命令?,系统,电脑,工具,信息,软件,网上,名称,工作,设备,通用,从

      linux命令下载jdk?

      linux命令下载jdk?,官网,系统,地址,工作,工具,服务,管理,环境,网上,地方,怎样

      linux中的下载命令行?

      linux中的下载命令行?,软件,系统,网络,电脑,名称,密码,官网,位置,服务,代理,l

      linux防火墙命令启动?

      linux防火墙命令启动?,系统,状态,管理,密码,服务,工具,防火墙,网络,信息,软

      linux命令给用户授权?

      linux命令给用户授权?,系统,数字,管理,权限,命令,密码,工具,时间,软件,信息,l

      linux命令行大全下载?

      linux命令行大全下载?,系统,地址,工作,信息,管理,技术,命令,名家,评论,数据,

      linux命令创建用户组?

      linux命令创建用户组?,系统,代码,密码,用户组,用户,命令,信息,名称,新增,管

      linux启动显示命令行?

      linux启动显示命令行?,系统,密码,终端,状态,首页,情况,基础,电脑,信息,工具,l

      linux命令下载jdk?

      linux命令下载jdk?,官网,系统,地址,工作,工具,服务,管理,环境,网上,地方,怎样

      查看linux用户命令行?

      查看linux用户命令行?,信息,系统,时间,名称,密码,用户,命令,地址,状态,设备,L

      linux所有用户命令行?

      linux所有用户命令行?,系统,信息,地址,工作,密码,命令,用户,时间,电脑,管理,L

      linux用户下的命令是?

      linux用户下的命令是?,系统,工作,管理,地址,命令,密码,基础,信息,目录,新增,L

      linux用户登录的命令?

      linux用户登录的命令?,系统,信息,工作,地址,时间,密码,名称,命令,电脑,软件,l

      linux服务器下载命令?

      linux服务器下载命令?,服务,密码,系统,档案,工具,网络,公共,百度,地址,认证,l

      linux关机用户命令?

      linux关机用户命令?,系统,工作,信息,状态,管理,命令,基础,目录,用户,功能,lin

      linux启动实例的命令?

      linux启动实例的命令?,密码,软件,环境,系统,管理,情况,工具,数据,设备,位置,l

      linux退出启动命令行?

      linux退出启动命令行?,系统,状态,档案,平台,命令,环境,模式,终端,程序,编辑,l

      关闭启动linux的命令?

      关闭启动linux的命令?,服务,系统,命令,代码,手机,软件,密码,管理,信息,状态,l