使用PHP无法显示Oracle BLOB中的图片问题排查
问题描述
我在Oracle数据库中有一个SCREENSHOT字段,类型为BLOB,是通过Java JDBC的setBinaryStream方法存储的图片。但使用PHP代码尝试显示图片时,页面只出现黑屏,无法正常展示图片。
问题代码
<?php $id = $_GET['serial_id']; $id1 = $_GET['serial_id1']; $id2 = $_GET['serial_id2']; $sql2 = "SELECT * FROM Mapping WHERE PRODUCT ='" . $id1 . "' and (ID='" . $id . "' or VALUE='" . $id2 . "')"; echo $sql2; $array2 = oci_parse($conn, $sql2); oci_execute($array2,OCI_NO_AUTO_COMMIT); $result = oci_fetch_assoc($array2); if (is_object($result['SCREENSHOT'])) { $result11 = $result['SCREENSHOT']->load(); header("Content-type: image/JPEG"); echo $result11; } ?>
现象截图

排查与解决步骤
我帮你梳理了几个可能的问题点,你可以按顺序排查:
先确认SQL查询是否拿到有效数据
你代码里echo $sql2;会输出完整的SQL语句,把这条语句复制到Oracle客户端(比如PL/SQL Developer)执行,看看SCREENSHOT字段是否真的有非空的BLOB数据。如果查询结果里这个字段是空的,那肯定显示不了,得先去检查Java存储数据的逻辑是否正确。移除多余的输出内容
代码里的echo $sql2;会在图片二进制数据前输出一段文本,这会彻底破坏图片的结构,浏览器根本解析不了,自然显示黑屏。一定要把这行删掉,确保输出的只有图片的二进制内容,没有任何额外字符。确认图片MIME类型是否匹配
你现在固定设置header("Content-type: image/JPEG");,但如果存储的是PNG、GIF等其他格式的图片,这个类型就不对了。可以试试两种方法:- 存储图片时在数据库额外加个字段记录原始MIME类型,读取时对应设置header;
- 用PHP的
getimagesizefromstring()自动识别图片类型,修改代码如下:<?php ob_clean(); flush(); $id = $_GET['serial_id']; $id1 = $_GET['serial_id1']; $id2 = $_GET['serial_id2']; $sql2 = "SELECT * FROM Mapping WHERE PRODUCT ='" . $id1 . "' and (ID='" . $id . "' or VALUE='" . $id2 . "')"; $array2 = oci_parse($conn, $sql2); oci_execute($array2,OCI_NO_AUTO_COMMIT); $result = oci_fetch_assoc($array2); if (is_object($result['SCREENSHOT'])) { $result11 = $result['SCREENSHOT']->load(); $imageInfo = getimagesizefromstring($result11); if ($imageInfo) { header("Content-type: " . $imageInfo['mime']); echo $result11; } else { header("Content-type: text/plain"); echo "无法识别图片格式"; } } ?>
检查BLOB数据是否完整
有时候Java的setBinaryStream可能会出现数据截断,你可以用SQL查询BLOB的长度,和原始图片的文件大小对比:SELECT DBMS_LOB.GETLENGTH(SCREENSHOT) FROM Mapping WHERE PRODUCT = '你的PRODUCT值' and (ID='你的ID值' or VALUE='你的VALUE值')如果查询出的长度和原始图片字节数不一致,说明存储过程有问题,得检查Java代码里的流处理是否正确(比如有没有正确关闭流、是否读取了全部数据)。
清空输出缓冲区避免干扰
除了echo $sql2;,还要确保没有其他隐性输出(比如PHP错误提示、空格换行)。可以在代码开头加上ob_clean();和flush();来清空输出缓冲区,确保只有图片数据输出。
内容的提问来源于stack exchange,提问作者Md Imran

