返回损坏数据的PHP readfile()
在我的函数中,我保存了从base64字符串解码的图像:返回损坏数据的PHP readfile(),php,cakephp,header,readfile,Php,Cakephp,Header,Readfile,在我的函数中,我保存了从base64字符串解码的图像: function saveImage(){ //magic... define('UPLOAD_DIR', '../webroot/img/'); $base64string = str_replace('data:image/png;base64,', '', $base64string); $base64string = str_replace(' ', '+', $base64string);
function saveImage(){
//magic...
define('UPLOAD_DIR', '../webroot/img/');
$base64string = str_replace('data:image/png;base64,', '', $base64string);
$base64string = str_replace(' ', '+', $base64string);
$data = base64_decode($base64string);
$id = uniqid();
$file = UPLOAD_DIR.$id.'.png';
$success = file_put_contents($file, $data);
}
上述功能正常工作,图像保存在指定文件夹中,且未损坏
在下一个函数中,我现在尝试将图像强制下载给用户:
function getChart($uniqid= null){
if($uniqid){
$this->layout = null;
header("Content-type: image/png");
header("Content-Disposition:attachment;filename='".$uniqid.".png'");
readfile('../webroot/img/'.$uniqid.'.png');
exit;
} else exit;
}
从服务器下载的图像已损坏,无法显示。在文本编辑器中打开下载的文件后,我注意到在最顶端添加了一个新行字符。删除字符并保存文件后,它将正确打开并正确显示
如何修复此问题?编辑(强制下载):
尝试以下操作(仅用于渲染图像):
此标题告诉浏览器文件有多大。某些浏览器需要它才能正确下载文件。不管怎么说,这是一个很好的方式告诉有多大的文件。这样,任何下载该文件的人都可以预测下载需要多长时间
header("Content-type: $file_type")
此标头告诉浏览器它尝试下载的文件类型
header("Content-Disposition: attachment; filename=$file_name");
这将告知浏览器以指定的名称保存此下载的文件。如果不发送此标题,浏览器将尝试使用脚本名称保存文件
但您需要使用
flush()刷新缓冲区代码>或在您的情况下使用ob_flush()代码>第一个出口正上方 在调用readfile
之前,检查您是否正在输出内容:
// add ob_start() at the very top of your script
function getChart($uniqid= null){
echo strlen(ob_get_clean()); die(); // if it's not 0 then you are definetly echoing something
if($uniqid){
$this->layout = null;
header("Content-type: image/png");
header("Content-Disposition:attachment;filename='".$uniqid.".png'");
readfile('../webroot/img/'.$uniqid.'.png');
exit;
} else exit;
}
您所描述的内容可能有多个问题,这些问题在您实际打开下载的文件之前是隐藏的
相反,要使您的代码更健壮,并检查前提条件,如果已经发送了头,则在此处检查,并清除任何可能的现有输出缓冲区,如果不可能,则给出错误:
function getChart ($uniqid = null) {
if (!$uniqid) exit;
$this->layout = null;
if (headers_sent()) throw new Exception('Headers sent.');
while (ob_get_level() && ob_end_clean());
if (ob_get_level()) throw new Exception('Buffering is still active.');
header("Content-type: image/png");
header("Content-Disposition:attachment;filename='".$uniqid.".png'");
readfile('../webroot/img/'.$uniqid.'.png');
exit;
}
这个问题我已经有好几次了。以下是我使用的解决方案:
几乎总是我忘记关闭download.php
文件中的unicode BOM
编码,这会在下载文件的前面添加一些内容,从而破坏文件
因此,解决方案是在download.php中关闭unicode BOM
只需使用ob_clean();在readfile()之前在调用readline
之前,是否确定没有输出某些内容?代码看起来很好me@Peter:您正在输出某些内容。以防万一,更可能的情况是,你有一个问题,以了解在哪里。当你写的时候,输出的不仅仅是标题和readfile内容。是的,我刚刚检查了缓冲区,输出了一些东西。我不知道为什么。在你的例子中,我怎样才能强制下载图像?@DusanRadojevic:是的,但这不是问题所在。实际上,与原始代码相比,结果是一样的。在OP的环境中可能会出现完全相同的问题。缓冲区中有输出,可能是windows系统的CRLF序列,但这只是猜测。看我的答案,它会帮你清理@Peter检查打开/关闭php标记的位置。也许在标记之前有一个换行符幸运的是,使用输出缓冲的显著优势在于它与数据压缩一起使用。如果您不使用ob_gzhandler,那么就没有什么好处。flush单独提交服务器上仍然存在的任何输出数据。使用ob_start及其对应的ob_flush、ob_end_clean和ob_end_flush,任何等待压缩的内容(将flush和ob_flush视为不同的存储桶-flush将数据发送到ob,ob将数据发送到浏览器-可能不准确,但这正是想法)都将被打包并发送到客户端。
header("Content-Disposition: attachment; filename=$file_name");
// add ob_start() at the very top of your script
function getChart($uniqid= null){
echo strlen(ob_get_clean()); die(); // if it's not 0 then you are definetly echoing something
if($uniqid){
$this->layout = null;
header("Content-type: image/png");
header("Content-Disposition:attachment;filename='".$uniqid.".png'");
readfile('../webroot/img/'.$uniqid.'.png');
exit;
} else exit;
}
function getChart ($uniqid = null) {
if (!$uniqid) exit;
$this->layout = null;
if (headers_sent()) throw new Exception('Headers sent.');
while (ob_get_level() && ob_end_clean());
if (ob_get_level()) throw new Exception('Buffering is still active.');
header("Content-type: image/png");
header("Content-Disposition:attachment;filename='".$uniqid.".png'");
readfile('../webroot/img/'.$uniqid.'.png');
exit;
}