如何用PHP解码解析SRID=4326的十六进制空间数据
解析SQLite中SRID=4326的十六进制空间数据(PHP实现)
问题背景
处理SQLite数据库中存储的十六进制编码空间数据,参数如下:
- 空间参考系统:SRID=4326(WGS84,度单位)
- 几何类型:
POLYGON, XY, SRID=4326 - 十六进制数据示例:
0001e61000006acf313a5111464092eae373eb9640405fbb039ef0254640353a492fb9ab40407c030000000100000022000000d0b02b40ee194640353a492fb9ab40405fbb039ef02546404c39fd643d994040ea9d859fcf244640d957040691984040a2fc5e159a234640eb79d71100984040b4fc82a953224640fec95f3f8c97404067779d3800214640001545ed369740405fb273c6a31f4640e34ed01d01974040b871d371421e464092eae373eb96404072933368e01c46409ed41231f69640406b272ad9811b4640219cdb3421974040c260dce92a1a464094050afd6b974040b5cc8ca8df18464012ec3da7d5974040e2ef6b00a41746409b0293f35c984040a4c5cead7b164640d5bd614800994040cd9ded326a154640157a0eb7bd994040ce7c4ccd72144640c8d7d801939a40402471ec6b981346408d529aa27d9b4040a44963a6dd1246409b4d60d27a9c40403cbbf4b444124640bc39cb91879d4040aa56c569cf114640381e1ab2a09e404060b13c2b7f1146401bb6c7dec29f404013dfa8ef541146402f849ca7eaa040406acf313a51114640abc1178b14a24040d35d2719741146405be20f013da34040c5e8b025bd114640349b6a8560a44040b223e1842b124640c4e8cba27ba540400c982ceabd1246404c861bfd8aa6404006fa3c9b72134640659dc05b8ba740407124177547144640743274b379a840404a4a85f2391546403df38b2f53a9404025c5b233471646403a90a03a15aa40409fede2066c1746405eac7486bdaa404020ae28f2a4184640e5ab03134aab4040d0b02b40ee194640353a492fb9ab4040fe
尝试使用geoPHP解析时触发报错:
Fatal error: Uncaught Exception: Only NDR (little endian) SKB format is supported at the moment in C:\xampp\htdocs\vendor\geoPHP\lib\adapters\WKB.class.php:52
报错原因
当前使用的geoPHP版本仅支持小端(NDR)字节序的WKB格式,但目标数据是大端(XDR)的EWKB(扩展WKB)——开头的00字节标识了大端字节序,与geoPHP的解析要求冲突。
解决方案
方法1:利用SQLite空间扩展直接转换为WKT(推荐)
如果SQLite启用了SpatiaLite扩展,可直接在查询时将十六进制空间数据转换为易于解析的WKT格式:
SELECT ST_AsText(CAST(X'你的十六进制数据' AS BLOB)) AS wkt_geometry;
随后在PHP中用geoPHP解析WKT:
<?php require_once('vendor/geoPHP/geoPHP.inc'); // 从SQL查询获取的WKT字符串 $wktData = 'POLYGON((...))'; $geom = geoPHP::load($wktData, 'wkt'); $coordinates = $geom->getCoordinates(); // 输出经纬度坐标(SRID=4326,顺序为[经度, 纬度]) print_r($coordinates); ?>
方法2:手动转换字节序并适配geoPHP
无法使用SpatiaLite时,需将大端EWKB转换为geoPHP支持的小端格式,完整代码如下:
<?php require_once('vendor/geoPHP/geoPHP.inc'); $hexData = '0001e61000006acf313a5111464092eae373eb9640405fbb039ef0254640353a492fb9ab40407c030000000100000022000000d0b02b40ee194640353a492fb9ab40405fbb039ef02546404c39fd643d994040ea9d859fcf244640d957040691984040a2fc5e159a234640eb79d71100984040b4fc82a953224640fec95f3f8c97404067779d3800214640001545ed369740405fb273c6a31f4640e34ed01d01974040b871d371421e464092eae373eb96404072933368e01c46409ed41231f69640406b272ad9811b4640219cdb3421974040c260dce92a1a464094050afd6b974040b5cc8ca8df18464012ec3da7d5974040e2ef6b00a41746409b0293f35c984040a4c5cead7b164640d5bd614800994040cd9ded326a154640157a0eb7bd994040ce7c4ccd72144640c8d7d801939a40402471ec6b981346408d529aa27d9b4040a44963a6dd1246409b4d60d27a9c40403cbbf4b444124640bc39cb91879d4040aa56c569cf114640381e1ab2a09e404060b13c2b7f1146401bb6c7dec29f404013dfa8ef541146402f849ca7eaa040406acf313a51114640abc1178b14a24040d35d2719741146405be20f013da34040c5e8b025bd114640349b6a8560a44040b223e1842b124640c4e8cba27ba540400c982ceabd1246404c861bfd8aa6404006fa3c9b72134640659dc05b8ba740407124177547144640743274b379a840404a4a85f2391546403df38b2f53a9404025c5b233471646403a90a03a15aa40409fede2066c1746405eac7486bdaa404020ae28f2a4184640e5ab03134aab4040d0b02b40ee194640353a492fb9ab4040fe'; // 清理无效字符 $hexData = str_replace(["\n", "\r", " "], '', $hexData); // 转换为二进制 $binary = pack('H*', $hexData); // 大端转小端处理EWKB $handle = fopen('php://memory', 'r+'); fwrite($handle, $binary); rewind($handle); // 读取字节序(当前是00=大端) $endian = fread($handle, 1); if ($endian === "\x00") { // 修改为小端标识 fseek($handle, 0); fwrite($handle, "\x01"); rewind($handle); // 读取几何类型(4字节,大端转小端) $typeHex = bin2hex(strrev(fread($handle, 4))); $type = hexdec($typeHex); // 读取SRID(4字节,大端转小端) $sridHex = bin2hex(strrev(fread($handle, 4))); $srid = hexdec($sridHex); // 读取多边形环数量(4字节,大端转小端) $ringCountHex = bin2hex(strrev(fread($handle, 4))); $ringCount = hexdec($ringCountHex); // 处理每个环的坐标 $coordinates = []; for ($r = 0; $r < $ringCount; $r++) { // 读取点数量(4字节,大端转小端) $pointCountHex = bin2hex(strrev(fread($handle, 4))); $pointCount = hexdec($pointCountHex); $ringCoords = []; for ($p = 0; $p < $pointCount; $p++) { // 读取经度(8字节,大端转小端) $lonBin = strrev(fread($handle, 8)); $lon = unpack('d', $lonBin)[1]; // 读取纬度(8字节,大端转小端) $latBin = strrev(fread($handle, 8)); $lat = unpack('d', $latBin)[1]; $ringCoords[] = [$lon, $lat]; } $coordinates[] = $ringCoords; } fclose($handle); // 输出坐标(SRID=4326,格式为[[[lon1, lat1], [lon2, lat2], ...]]) print_r($coordinates); } else { // 小端格式直接用geoPHP解析 $geom = geoPHP::load($binary, 'wkb'); print_r($geom->getCoordinates()); } ?>
方法3:升级/替换为支持大端EWKB的库
若频繁处理这类数据,建议使用支持完整EWKB标准的库,比如phayes/geophp的最新分支,或spatie/geojson结合geoPHP使用,避免手动处理字节序的繁琐。
相关见解
- SRID=4326的坐标顺序为**[经度, 纬度]**,解析后可直接用于地图渲染(如Google Maps、OpenStreetMap)。
- EWKB是WKB的扩展格式,包含SRID信息,常见于PostGIS、SQLite(SpatiaLite)等空间数据库。
- 字节序分为大端(XDR)和小端(NDR),不同数据库/工具默认使用的字节序可能不同,解析时需注意匹配。
内容的提问来源于stack exchange,提问作者Ali Ghassan
相关产品推荐
相关产品推荐

