PHP实现WKB转WKT:无SpatiaLite扩展下的空间数据解析需求
问题
我们用PHP读取SpatiaLite数据库并返回JSON接口数据,但主机环境无法使用SQLite的SpatiaLite扩展,需要找到替代方案实现类似MySQL中AsText()的功能:
- 曾尝试geoPHP库,但它仅支持小端字节序,不符合需求
- 当前用SQLite3代码可获取二进制数据,但无法解析为文本,也不确定
unpack操作是否正确
初始代码:
$db = new SQLite3($checkDB); $results = $db->query("SELECT * FROM ".$data['table']." LIMIT ". $limit .";"); while ($row = $results->fetchArray(SQLITE3_ASSOC)){ $binary = unpack('H*', $row['GEOMETRY']); }
获取到的二进制样本:
0001110f00002239c4f5464063c1fc6e0077089555419499b113354063c126bce1344b9555417c0600000001000000690300000001000000130000002224b3313d4063c1fc6e007708955541fa546fd1424063c19ea95870109555419b8ff46f464063c12aae85851e9555412239c4f5464063c1c2335e9f27955541764d5fde424063c100ca750124955541bde0a2913f4063c180e53d6a259555417259cb293f4063c1c758a1922d9555419f80bd7c424063c12ed7418c37955541e8c44f97414063c1920795c44395554112ec8cbf3f4063c11b270af44a9555418bf133db374063c126bce1344b9555418ca2a532394063c143208025419555413d9d2d513a4063c1099ca9ac389555410596e3a9374063c1dda0cc0d399555419499b113354063c10e7b1fd0349555417715a655354063c1d917d2662b95554117e2eef3384063c12285daa01e95554156768ba63c4063c18bb65948139555412224b3313d4063c1fc6e007708955541fe
解决方案
方法1:手动解析WKB(Well-Known Binary)
SpatiaLite的GEOMETRY字段存储的是OGC标准WKB格式,你的样本开头00表示大端字节序。可按WKB规范手动解析:
- 读取第一个字节判断字节序:
00为大端,01为小端 - 解析几何类型:读取后续4字节,按字节序转换为十进制,判断几何类型(你的样本对应带Z坐标的Polygon)
- 依次解析环数量、每个环的点数,再逐个解析坐标的X/Y/Z值(每个值为8字节双精度浮点数,按字节序调整后转换)
示例解析代码:
function wkbToWkt($wkb) { $hex = unpack('H*', $wkb)[1]; $offset = 0; // 读取字节序 $endian = substr($hex, $offset, 2); $offset += 2; // 读取几何类型 $typeHex = substr($hex, $offset, 8); $offset += 8; $type = hexdec($endian == '00' ? $typeHex : strrev($typeHex)); // 初始化WKT字符串(按带Z的Polygon处理) $wkt = 'POLYGON Z ('; // 读取环数量 $ringCountHex = substr($hex, $offset, 8); $offset += 8; $ringCount = hexdec($endian == '00' ? $ringCountHex : strrev($ringCountHex)); for ($r = 0; $r < $ringCount; $r++) { $wkt .= '('; // 读取当前环的点数 $pointCountHex = substr($hex, $offset, 8); $offset += 8; $pointCount = hexdec($endian == '00' ? $pointCountHex : strrev($pointCountHex)); for ($p = 0; $p < $pointCount; $p++) { // 解析X坐标 $xHex = substr($hex, $offset, 16); $offset += 16; $x = unpack('d', pack('H*', $endian == '00' ? $xHex : strrev($xHex)))[1]; // 解析Y坐标 $yHex = substr($hex, $offset, 16); $offset += 16; $y = unpack('d', pack('H*', $endian == '00' ? $yHex : strrev($yHex)))[1]; // 解析Z坐标 $zHex = substr($hex, $offset, 16); $offset += 16; $z = unpack('d', pack('H*', $endian == '00' ? $zHex : strrev($zHex)))[1]; $wkt .= ($p > 0 ? ',' : '') . "$x $y $z"; } $wkt .= ')' . ($r < $ringCount - 1 ? ',' : ''); } $wkt .= ')'; return $wkt; } // 代码中调用示例 while ($row = $results->fetchArray(SQLITE3_ASSOC)){ $wkt = wkbToWkt($row['GEOMETRY']); // 将WKT加入返回的JSON数据中 }
方法2:修改geoPHP支持大端字节序
geoPHP默认仅处理小端,可修改其parseWKB方法:
- 在读取几何类型前,先判断第一个字节的字节序
- 对类型、点数等多字节数据,按字节序决定是否反转后解析
- 坐标的双精度浮点数也按字节序调整后再执行
unpack操作
方法3:使用支持大端的纯PHP解析库
选择支持大端WKB的纯PHP库,比如对phayes/geoPHP进行二次修改,或使用其他轻量WKB解析工具,确保能识别并处理大端字节序的WKB数据。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

