You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 12:12:01