PHP脚本可下载PDF,但无法正常下载根目录外的图片文件
PHP图片下载损坏问题排查与解决
问题现象
- 从根目录外的
uploads文件夹下载PNG/JPG图片时文件损坏,无法正常打开,但PDF文件可正常下载 - 已确认:文件存在、MIME类型正确(
image/png/image/jpeg)、文件非空,服务器本地可正常预览图片 - 触发逻辑:前端点击后通过新窗口打开带GET参数的PHP页面,由前端控制器分发到视图处理
相关代码
前端触发代码
container.addEventListener('click', () => { // ... 获取用户ID和文件名 ... const open = `/view/?user=${user}&file=${file}&open=true`; window.open(open, '_blank'); });
视图处理代码
// 确保用户已认证... if(isset($_GET['open']) && isset($_GET['user']) && isset($_GET['file'])){ if(!Files::open($_GET['file'], $_GET['user'])){ Report::error("Error"); } Report::success("Success"); exit(); }
文件处理核心函数Files::open()
/** * 打开请求的文件。 * * @param string $file 要打开的文件 * @param string $folder 文件所在的文件夹 * @return bool 文件成功打开则返回true,否则返回false */ public static function open(string $file, string $folder = ''): bool { // 路径遍历防护 $file = str_replace(['../', '..\\'], '', $file); $path = dirname(__DIR__, 2) . "/uploads/$folder/$file"; Report::notice("正在打开'$folder'文件夹中的文件'$file'。"); if (!file_exists($path)) { Report::warning("'$folder'文件夹中不存在文件'$file'。"); return false; } $finfo = new finfo(FILEINFO_MIME_TYPE); $mime = $finfo->file($path); Report::notice("文件'$file'的MIME类型为'$mime'。"); header("Content-Type: $mime"); header("Content-Disposition: attachment; filename=$file"); header("Content-Length: " . filesize($path)); readfile($path); return true; }
2023.05.16 更新:问题定位
下载的文件存在前置空白字符,PDF格式对这类冗余内容容错性高,而图片格式严格依赖文件头结构,因此出现损坏。
解决方案
1. 清理输出缓冲区
在输出文件内容前,清空所有缓冲的冗余内容:
// 在Files::open()函数设置HTTP头之前添加 ob_clean(); flush();
2. 禁止日志输出到响应流
Report::notice()/Report::error()等日志函数如果直接输出到浏览器,会导致空白/日志字符混入文件内容。必须将日志写入服务器本地文件(如用error_log()替代),而非HTTP响应流。
3. 移除多余的输出语句
视图文件中Report::success("Success");会在文件内容后添加额外字符,需删除该语句,直接在Files::open()处理完成后退出:
// 优化后的视图代码 if(isset($_GET['open']) && isset($_GET['user']) && isset($_GET['file'])){ if(!Files::open($_GET['file'], $_GET['user'])){ header("HTTP/1.1 404 Not Found"); echo "文件不存在或无权访问"; } exit(); }
4. 修复HTTP头的文件名编码
文件名含特殊字符时会导致头解析异常,需用rawurlencode()处理:
header("Content-Disposition: attachment; filename=\"" . rawurlencode($file) . "\"");
5. 检查所有PHP文件的首尾空白
确保所有被包含的PHP文件(包括类文件、控制器、视图)开头无多余空格/换行,结尾的?>可直接删除(避免意外输出空白)。
内容的提问来源于stack exchange,提问作者Ere Männistö
相关产品推荐
相关产品推荐

