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

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规范手动解析:

  1. 读取第一个字节判断字节序:00为大端,01为小端
  2. 解析几何类型:读取后续4字节,按字节序转换为十进制,判断几何类型(你的样本对应带Z坐标的Polygon)
  3. 依次解析环数量、每个环的点数,再逐个解析坐标的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:54:57