使用PDO从MSSQL读取二进制数据无法显示PDF/图片的问题
问题排查与解决步骤
1. 先解决输出污染问题
乱码/异常内容最常见的原因是输出响应头之前有隐性内容,比如PHP文件开头的BOM、空格,或者之前代码残留的echo/var_dump输出。这些内容会混入PDF数据流,导致浏览器无法解析:
- 检查所有关联PHP文件,确保编码为
UTF-8无BOM - 在
header()调用前添加缓冲区清理代码,避免残留输出:ob_clean(); flush();
2. 修正MSSQL LOB读取逻辑
MSSQL的PDO驱动处理LOB时,需要注意流指针的位置和读取时机,以下是修正后的完整代码:
<?php // 清空输出缓冲区,确保header能正常发送 ob_clean(); flush(); $stmt = $pdo->prepare($sql); $stmt->execute([$id]); // 确认查询返回有效行 if ($stmt->rowCount() === 0) { die("附件不存在"); } // 绑定列时注意:PDO bindColumn的索引从1开始计数,确认第10列确实是LOB字段 $stmt->bindColumn(10, $lob, PDO::PARAM_LOB); $stmt->bindColumn(11, $attachment, PDO::PARAM_STR, 256); // 绑定后获取数据 $stmt->fetch(PDO::FETCH_BOUND); // 重置流指针到起始位置,避免读取到空内容 rewind($lob); // 根据扩展名设置正确的Content-Type $ext = strtolower(substr(strrchr($attachment, '.'), 1)); $contentType = match($ext) { 'pdf' => 'application/pdf', 'jpg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', default => 'application/octet-stream' }; // 设置完整响应头 header("Content-Type: $contentType"); header("Content-Disposition: inline; filename=\"$attachment\""); // inline表示浏览器直接打开,改为attachment则触发下载 header("Content-Length: " . stream_get_size($lob)); // 告诉浏览器文件大小,提升解析稳定性 // 输出LOB内容 fpassthru($lob); exit; // 输出后立即终止脚本,避免后续代码产生额外输出
3. 优化PDO连接配置
给MSSQL的PDO连接添加必要属性,优化LOB读取兼容性:
$pdo = new PDO("sqlsrv:Server=你的服务器;Database=你的库", "账号", "密码", [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true, PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8 ]);
4. 验证LOB数据本身完整性
如果以上步骤仍无效,先把LOB内容写入本地文件,确认数据库中的数据是否损坏:
file_put_contents('本地测试文件.pdf', stream_get_contents($lob));
打开生成的本地文件,若文件无法正常打开,说明数据库中存储的附件本身已损坏。
内容的提问来源于stack exchange,提问作者nequ2k
相关产品推荐
相关产品推荐

