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

本文主要探讨如何解决使用PHP进行文件下载时,文件不被正确下载而是直接在浏览器中打开的问题,重点关注PHP的header函数设置和防止乱码的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

	

《前言》

不知道大家看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();
		}
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值