牛骨文教育服务平台(让学习变的简单)
博文笔记

一步一步分析解决PHP文件下载直接在网页中打开问题

创建时间:2014-01-17 投稿人: 浏览次数:7051
	

不知道大家看PHP函数的时候,有没有注意到这样一个句话 -

认识到一点很重要,即必须在任何实际的输出被发送之前调用 header() 函数

(在 PHP 4 以及更高的版本中,您可以使用输出缓存来解决此问题)


 哎~~ 一个困扰了我一天的问题,最终以

这句话结束。



在使用TestLink的时候,发现Testlink中的附件在选择下载都是直接在网页中打开,图片,word都显示成乱码。各种困惑,开始了以下的调研:


1)查看代码,未见端倪。


我 直接检查PHP代码中实现下载的代码,查看Header是否正确:

@ob_end_clean();
require_once("../../config.inc.php");
require_once("../functions/common.php");
require_once("../functions/attachments.inc.php");
testlinkInitPage($db,false,false,"checkRights");

$args = init_args();
if ($args->id)
{
	$attachmentRepository = tlAttachmentRepository::create($db);
	$attachmentInfo = $attachmentRepository->getAttachmentInfo($args->id);
	if ($attachmentInfo && checkAttachmentID($db,$args->id,$attachmentInfo))
	{
		$content = $attachmentRepository->getAttachmentContent($args->id,$attachmentInfo);
		if ($content != "")
		{
			@ob_end_clean();
			header("Pragma: public");
			header("Cache-Control: ");
			if (!(isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on" && preg_match("/MSIE/",$_SERVER["HTTP_USER_AGENT"])))
				header("Pragma: no-cache");
			header("Content-Type: ".$attachmentInfo["file_type"]);
			header("Content-Length: ".$attachmentInfo["file_size"]);
			header("Content-Disposition: attachment; filename="{$attachmentInfo["file_name"]}"");
			header("Content-Description: Download Data");
			echo $content;
			exit();
		}
	}
}


2)各种尝试,奈何是南辕北辙。


看完代码第一反应是没错啊.

header("Content-Disposition: attachment; filename="{$attachmentInfo["file_name"]}""); //这个指名了文件时附件而不是直接在网页中打开
header("Content-Type: ".$attachmentInfo["file_type"]);//这个也是或去了文件的类型

下一反应是,难道是 content-Type出问题了,让我们直接hard code改之成为二进制流试试吧

header("Content-Type: "application/octet-stream);
header("Content-Disposition: attachment; filename="{$attachmentInfo["file_name"]}"");


结果非常的失望,图片还是在浏览器中打开,显示乱码。
好吧,我选择一个不存在的content-Type试试吧,这样浏览器肯定是不认识的。尝试的结果,还是失败。

header("Content-Type: "application/download);

3)山不起就我,我就去就山。

各种尝试无果,我开始怀疑我是不是Header的函数写错了,于是,我开始了新的尝试,建立一个test.php文件,就测试这个download。

事实证明,test.php运行非常正常,点击下载链接,图片正确下载。

<?php
//文件 test.php
//=================================文件下载
if ($_GET["down"]) {
    $file_name = "a.png";
    $file_dir = "./";

    if (!file_exists($file_dir . $file_name)) { //检查文件是否存在
        echo "文件找不到";
        exit;
    } else {
        // 输入文件标签
        Header("Content-type: application/octet-stream"); //指定以下输出的字符将以下载文件形式保存在客户端
        Header("Accept-Ranges: bytes");//指定下载的文件大小单位
        Header("Accept-Length: " . filesize($file_dir . $file_name));//指定下载的文件大小
        Header("Content-Disposition: attachment; filename=" . $file_name); //指定下载的文件名.扩展名
        $file = fopen($file_dir . $file_name, "r"); // 打开文件
        // 输出文件内容,除了下载文件编码之外该页面不能有任何其他输出
        echo fread($file, filesize($file_dir . $file_name));
        fclose($file);
        exit; //防止读取下面的其他输出
    }
}
?>


<a href="?down=1">下载</a>

4)从果推因,柳暗花明。


为什么测试的程序工作,而之前的程序不工作呢?
通过Chrome的dev tool,我又得到了一个有意思的发现 - 
无论我在程序中设定的Content-Type 是什么,实际上Content-Type并没有生效。


从结果的表现,我们可以分析出来 - 我们调用的Header 并没生效。
我们回去查看源代码,问题出在哪里呢?


回到了前言!!


认识到一点很重要,即必须在任何实际的输出被发送之前调用 header() 函数

(在 PHP 4 以及更高的版本中,您可以使用输出缓存来解决此问题)


强烈怀疑是在这个函数testlinkInitPage($db,false,false,"checkRights")中有提前的Echo!!所以 header失效了。。

本着这个原则,我把Header的生命提前,程序终于work了。。


@ob_end_clean();
header("Pragma: public");
header("Cache-Control: ");
require_once("../../config.inc.php");
require_once("../functions/common.php");
require_once("../functions/attachments.inc.php");
testlinkInitPage($db,false,false,"checkRights");

$args = init_args();
if ($args->id)
{
	$attachmentRepository = tlAttachmentRepository::create($db);
	$attachmentInfo = $attachmentRepository->getAttachmentInfo($args->id);
	if ($attachmentInfo && checkAttachmentID($db,$args->id,$attachmentInfo))
	{
		$content = $attachmentRepository->getAttachmentContent($args->id,$attachmentInfo);
		if ($content != "")
		{
			@ob_end_clean();
			
			if (!(isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on" && preg_match("/MSIE/",$_SERVER["HTTP_USER_AGENT"])))
				header("Pragma: no-cache");
			header("Content-Type: ".$attachmentInfo["file_type"]);
			header("Content-Length: ".$attachmentInfo["file_size"]);
			header("Content-Disposition: attachment; filename="{$attachmentInfo["file_name"]}"");
			header("Content-Description: Download Data");
			echo $content;
			exit();
		}
	}
}
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。