迁移至DigitalOcean Spaces后图片二进制无法在浏览器显示求助
从S3迁移至DigitalOcean Spaces后图片无法在浏览器显示的排查思路
近期将存储从S3迁移至DigitalOcean Spaces,其他各类文件均能正常工作,但发现图片的二进制内容无法在浏览器中显示。以下是相关PHP代码:
require_login(); $db = new db(); $sql = "SELECT * FROM uploads WHERE id = {$id}"; if (!super()) $sql .= " AND empresa = " . session('empresa'); $file = $db->row($sql); if (!$file || !session('empresa')) { return json_encode( [ 'error' => true, 'message' => 'File not found or you do not have access to it.' ] ); } $content = Storage::read( $file->empresa . '/' . $file->modulo . '/' . $file->nome_atual ); header("Content-Type: {$file->ext}"); header('Content-Disposition: inline; filename="' . $file->nome . '"'); header('Cache-Control: private, max-age=0, must-revalidate'); header('Pragma: public'); header('Content-Transfer-Encoding: binary'); header('Accept-Ranges: bytes'); echo $content;
排查思路:
修正Content-Type字段:代码中直接用
$file->ext作为Content-Type是错误的。比如JPG图片的正确MIME类型是image/jpeg,而非jpg。建议:- 数据库中存储完整的MIME类型(如
image/png、image/jpeg)替代单纯的扩展名 - 或读取内容后用
finfo函数获取正确类型:$finfo = new finfo(FILEINFO_MIME_TYPE); $mime = $finfo->buffer($content); header("Content-Type: {$mime}");
- 数据库中存储完整的MIME类型(如
确认文件读取完整性:
- 对比
strlen($content)和Spaces上原文件的大小,判断是否读取了完整二进制内容 - 将
$content写入本地文件(如file_put_contents('test.jpg', $content)),检查本地文件能否正常打开,排除读取截断或编码问题
- 对比
优化响应头配置:
- 添加
Content-Length头帮助浏览器确认文件完整度:header("Content-Length: " . strlen($content)); - 尝试注释掉
Content-Transfer-Encoding: binary头,部分场景下该头会导致图片解析异常 - 输出前清空缓冲区,避免多余字符干扰:
ob_clean(); flush(); echo $content;
- 添加
检查存储端文件状态:
- 直接通过DigitalOcean Spaces的文件URL在浏览器打开,确认文件本身未损坏且权限正确(私有文件需生成临时签名URL测试)
修复SQL注入漏洞(额外提示):当前代码直接拼接
$id到SQL语句,存在严重安全风险,建议改用参数化查询:$sql = "SELECT * FROM uploads WHERE id = ?"; if (!super()) $sql .= " AND empresa = ?"; $stmt = $db->prepare($sql); if (!super()) { $stmt->bind_param("ii", $id, session('empresa')); } else { $stmt->bind_param("i", $id); } $stmt->execute(); $file = $stmt->get_result()->fetch_assoc();
内容的提问来源于stack exchange,提问作者Gustavo
相关产品推荐
相关产品推荐

