使用header()函数在php中强制文件下载

72

我希望用户能够从我的服务器上下载一些文件,但是当我尝试使用互联网上的许多示例时,似乎没有任何一个能够正常工作。我已经尝试了类似这样的代码:

<?php

$size = filesize("Image.png");

header('Content-Description: File Transfer');
header('Content-Type: image/png');
header('Content-Disposition: attachment; filename="Image.png"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $size);
readfile("Image.png");

我甚至尝试了使用我能找到的最基本的例子,就像这样:

<?php
header('Content-type: image/png');
header('Content-Disposition: attachment; filename="Image.png"');
readfile('Image.png');

我测试过这段代码,删除了所有其他代码,只使用一个空文件并添加此代码,以消除外部来源的错误。

当我查看控制台时,该文件会以正确的标头发送,例如

'Content-Disposition: attachment; filename="Image.png"'

但是保存对话框没有显示。

我也尝试了在内容描述头中使用内联而不是附件,但这也没有任何区别,我在Firefox 8.0.1 Chrome 15.0.874.121和Safari 5.1.1中进行了测试。

7个回答

120

我非常确定在文件下载中不需要将MIME类型添加为JPEG:

header('Content-Type: image/png');

这些标头从未让我失望:

$quoted = sprintf('"%s"', addcslashes(basename($file), '"\\'));
$size   = filesize($file);

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $quoted); 
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $size);

当我尝试使用您的头文件时,我得到了与之前相同的结果,但是当我查看Firebug控制台时,我注意到了一些东西,尾随的“引号”由于某种原因不存在,我不知道那是否是个问题,但我尝试将它们都删除,也没有帮助。我测试使用的文件名中没有空格,所以我不知道是否需要? - Kerp

19

对我来说,这个方法非常有效,可以用来下载PNG和PDF文件。

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$file_name.'"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file_url)); //Absolute URL
ob_clean();
flush();
readfile($file_url); //Absolute URL
exit();

7

根据 Farhan Sahibole的回答

        header('Content-Disposition: attachment; filename=Image.png');
        header('Content-Type: application/octet-stream'); // Downloading on Android might fail without this
        ob_clean();

        readfile($file);

这就是让它正常工作所需的全部内容。我剥离了任何不必要的东西。

关键是使用ob_clean();


4
问题在于我使用ajax将消息发送到服务器,当我使用直接链接下载文件时,一切正常。相反,我使用了另一个Stackoverflow Q&A的资料,它对我很有帮助:

1
所以,你的意思是你实际上并没有像你在问题中所说的那样删除所有其他代码。 - Toastgeraet

1

1

它对我有效

$attachment_location = "filePath";
if (file_exists($attachment_location)) {

    header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
    header("Cache-Control: public"); // needed for internet explorer
    header("Content-Type: application/zip");
    header("Content-Transfer-Encoding: Binary");
    header("Content-Length:".filesize($attachment_location));
    header("Content-Disposition: attachment; filename=filePath");
    readfile($attachment_location);
    die();
} else {
    die("Error: File not found.");
}

0
这是我在测试中的一段代码片段……显然通过 GET 传递到脚本可能不是最好的方式……应该发布或只发送一个 ID 并从数据库中获取 GUID……无论如何,这个方法可行。我将 URL 转换为路径。
// Initialize a file URL to the variable
$file = $_GET['url'];
$file = str_replace(Polepluginforrvms_Plugin::$install_url, $DOC_ROOT.'/pole-permitter/', $file );

$quoted = sprintf('"%s"', addcslashes(basename($file), '"\\'));
$size   = filesize($file);

header( "Content-type: application/octet-stream" );
header( "Content-Disposition: attachment; filename={$quoted}" );
header( "Content-length: " . $size );
header( "Pragma: no-cache" );
header( "Expires: 0" );
readfile( "{$file}" );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接