如何在PHP中读取GeneXus存储在SQL Server的Image类型属性图片
核心原因
GeneXus的Image类型属性存入SQL Server的VARBINARY(MAX)字段时,不会直接写入原始图片二进制,会在二进制内容最前端追加一段GeneXus内部使用的元数据头。你之前直接对全量内容做转码,相当于把元数据头当成了图片内容的一部分,必然导致图片文件头损坏,无法正常渲染。
GeneXus存储Image字段的具体规则:
- 元数据头默认固定长度为28字节(对应十六进制串最开头的56个字符,1个字节对应2位十六进制值),内部存储图片格式、尺寸、内部标识等GeneXus管控用的信息,不属于图片文件本身的内容
- 元数据头之后的所有二进制内容,就是和本地文件完全一致的原始图片字节,没有做任何额外编码
- 数据库查询时返回的带
0x前缀的内容,是SQL Server对VARBINARY类型的默认十六进制展示格式,前缀本身不属于实际存储内容
PHP端正确实现步骤
- 优先使用PDO或sqlsrv扩展连接SQL Server,配置结果直接返回二进制流格式,不要取十六进制字符串,能减少转码误差
- 如果拿到的是带
0x前缀的十六进制结果,先去掉前缀,再转成二进制字符串 - 从二进制字符串起始位置跳过28字节的元数据头,剩余内容就是可用的原始图片数据
- 直接输出图片时匹配对应格式的Content-Type头即可;需要转base64嵌入页面时,仅对截断后的原始图片内容做编码
可直接参考以下代码:
<?php // 示例值为数据库返回的带0x前缀的十六进制串 $hexFromDb = '0x89504E470D0A1A0A000000...'; // 1. 去除开头的0x标识前缀 $pureHex = substr($hexFromDb, 2); // 2. 十六进制转二进制串 $fullBinary = hex2bin($pureHex); // 3. 跳过28字节的GeneXus元数据头,拿到原始图片二进制 $rawImage = substr($fullBinary, 28); // 场景A:直接输出图片到浏览器 // 根据实际图片格式替换Content-Type,示例为PNG格式 header('Content-Type: image/png'); echo $rawImage; exit; // 场景B:转Base64嵌入HTML // $base64Img = base64_encode($rawImage); // echo '<img src="data:image/png;base64,'.$base64Img.'" alt="图片" />'; ?>
截断后可以取前4个字节转十六进制做格式校验:
- 结果为
89504e47对应PNG格式- 结果以
ffd8ff开头对应JPG格式- 结果为
47494638对应GIF格式
如果校验结果不匹配,可尝试将跳过的头长度调整为4字节,部分GeneXus早期版本的元数据头长度为4字节,其余逻辑完全一致。
内容的提问来源于stack exchange,提问作者Paulo Sapuppo
相关产品推荐
相关产品推荐

