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

PHP中从Polygon二进制数据提取经纬度遇异常求助

解决PHP解析Polygon WKB十六进制字符串为经纬度数组的问题

你的问题核心是没有将十六进制WKB转换为二进制数据就直接解析,同时存在WKB结构理解错误、坐标顺序搞反的问题,导致解析出异常数值。

错误原因分析

  1. 未转换十六进制到二进制:你传入unpack的是十六进制字符串,但unpack需要处理原始二进制数据,直接解析十六进制会完全破坏数据结构。
  2. 坐标顺序错误:WKB格式中坐标存储顺序是经度(Longitude)在前,纬度(Latitude)在后,你代码中把第一个值当成纬度,第二个当成经度,顺序完全相反。
  3. 未适配字节序:WKB第一个字节是字节序标识(0=大端/网络字节序,1=小端/主机字节序),你用固定的V(小端无符号长整型)等格式,没有根据实际字节序调整解析规则。
  4. 错误的数组截断逻辑:你随意array_shift截断数组,没有按照WKB的标准结构解析,导致后续坐标解析错位。

正确解决方案

以下是修复后的代码,包含完整的WKB解析逻辑:

$wkbHex = '0001e6100000c2cff1357b2a1040af677f02539941403617e48e38781140b738adcb82bb41407c03000000010000006100000a3617e48e387811409111365a67aa414098e4b38b087811400cec49133eab4140fa454eb671771140c8ab4d4c14ac414096d2686574761140f1c11781e9ac4140cafb0a2f117511403028172ebdad414072d940e848731140cdb3a4d08eae414007aea6a41c711140aaeb53e75daf41408145cdb58d6e1140dc2e43f229b04140296b77aa9d6b114092f96a73f2b04140bfcbb04d4e6811408116eceeb6b1414058b4bea5a16411405a8b5ceb76b241409b36ebf299601140b80f13f231b34140e9552bae395c11405ade708fe7b34140d3faa08783571140ccb1295397b441407482f9647a52114044be89d040b541407bd9a95f214d1140c67bb99ee3b54140582c09c37b4711400015ff587fb64140424b4b0a8d4111407950fd9e13b74140affc5bde583b114067cbef14a0b74140e48b9c13e3341140f75ee46324b84140c3fa84a72f2e1140a88af139a0b8414051512abe4227114041c0694a13b94140a69aab9f20201140a66f0b4e7db94140cd3287b5cd18114029b32d03deb94140e81ada874e111140e17ee92d35ba4140b0198bbaa7091140fe373f9882ba4140287f630ade011140199b3812c6ba41403270174af6f9104053db0672ffba4140a9ab3f5ff5f1104035e61c942ebb41406dc6463fe0e91040d2ba455b53bb4140f7e54becbbe1104091c5b6b06dbb4140c708fd718dd9104034341e847dbb41407ef36ae259d11040b738adcb82bb414036ded85226c9104034341e847dbb414005018ad8f7c0104091c5b6b06dbb41408e208f85d3b81040d2ba455b53bb4140523b9665beb0104035e61c942ebb4140c776be7abda8104054db0672ffba4140d56772bad5a01040189b3812c6ba41404bcd4a0a0c991040ff373f9882ba414013ccfb3c65911040e17ee92d35ba414032b44e0fe689104029b32d03deb94140594c2a2593821040a56f0b4e7db94140ac95ab06717b104040c0694a13b9414033ec501d84741040a88af139a0b841401c5b39b1d06d1040f65ee46324b841404eea79e65a67104068cbef14a0b74140bb9b8aba266110407950fd9e13b74140a7bacc01385b10400015ff587fb64140790d2c6592551040c67bb99ee3b541408264dc5f3950104044be89d040b5414017ec343d304b1040ccb1295397b441400591aa167a4610405ade708fe7b341405fb0ead119421040b70f13f231b341409c32171f123e10405a8b5ceb76b24140301b2577653a10407f16eceeb6b14140d07b5e1a1637104090f96a73f2b041406fa1080f26341040d92e43f229b04140f1382f2097311040a8eb53e75daf4140820d95dc6a2f1040ccb3a4d08eae41402bebca95a22d10402f28172ebdad414068146d5f3f2c1040f1c11781e9ac4140ffa0870e422b1040c8ab4d4c14ac414060022239ab2a10400aec49133eab4140c2cff1357b2a10409111365a67aa4140eebeb2c34f2b1040432a9579baa84140f7b74679bd2d10401df983cb11a74140cf6e7529be311040ca4a446671a541405e3767c947371040c6d9344bdda34140dcd11a8b4c3e1040ba76fd5c59a241400c12ea00bb4610406cf50a56e9a04140fb82b7497e5010402db371bf909f41404c8c4c457e5b1040636e4ce8529e4140338f5ed09f671040d7daabdd329d4140e306a207c574104079e92963339c41409aea4491cd821040511e32ec569b4140a66b1dec96911040ed920e969f9a4140a69ccfc3fca01040b468c7220f9a4140caa12349d9b01040e77ae0f4a699414068a5be8d05c110400217ff0b689941407ef36ae259d11040af677f025399414093411737aee110400117ff0b689941402e45b27bdaf11040e77ae0f4a6994140534a0601b7011140b368c7220f9a41404e7bb8d81c111140ef920e969f9a414057fc9033e61f1140501e32ec569b414017e033bdee2d114077e92963339c4140b75777f4133b1140d7daabdd329d4140a95a897f35471140636e4ce8529e4140f9631e7b355211402db371bf909f4140ead4ebc3f85b11406bf50a56e9a041401315bb3967641140ba76fd5c59a241409aaf6efb6b6b1140c6d9344bdda341402078609bf5701140ca4a446671a54140032f8f4bf67411401df983cb11a741400728230164771140432a9579baa841403617e48e387811409111365a67aa4140fe';

// 1. 移除末尾多余的无效字节(你的WKB最后有个"fe",属于无效数据)
$wkbHex = rtrim($wkbHex, 'fe');

// 2. 将十六进制字符串转换为二进制数据
$wkbBin = hex2bin($wkbHex);

// 3. 解析字节序(第一个字节:0=大端,1=小端)
$endian = ord(substr($wkbBin, 0, 1));
$format = $endian === 0 ? 'N' : 'V'; // 大端用N,小端用V
$doubleFormat = $endian === 0 ? 'd' : 'e'; // 大端用d,小端用e(注意:PHP中e对应小端双精度)

// 4. 解析WKB头部信息
$offset = 1; // 跳过字节序字节
$type = unpack($format, substr($wkbBin, $offset, 4))[1];
$offset +=4;

// 对于Polygon类型(WKB类型代码3),解析环数和点数
if ($type !== 3) {
    throw new Exception('不是有效的Polygon WKB数据');
}

$numRings = unpack($format, substr($wkbBin, $offset,4))[1];
$offset +=4;

$return = [];

// 5. 解析每个环的坐标
for ($r=0; $r<$numRings; $r++) {
    $numPoints = unpack($format, substr($wkbBin, $offset,4))[1];
    $offset +=4;
    
    // 解析每个点的坐标(每个点是两个双精度:lon, lat)
    $pointBytes = substr($wkbBin, $offset, 8 * $numPoints * 2);
    $offset += 8 * $numPoints *2;
    
    // 解包双精度数组
    $coords = unpack($doubleFormat.'*', $pointBytes);
    
    // 转换为lat/lng数组,注意WKB是lon在前,lat在后
    for ($i=0; $i<$numPoints; $i++) {
        $lng = $coords[$i*2 +1];
        $lat = $coords[$i*2 +2];
        $return[] = [
            'lat' => $lat,
            'lng' => $lng
        ];
    }
}

print_r($return);

关键说明

  1. 十六进制转二进制:必须用hex2bin()将WKB十六进制字符串转换为原始二进制,这是解析的前提。
  2. 字节序适配:根据WKB第一个字节判断字节序,选择对应的unpack格式(大端N/d,小端V/e)。
  3. 坐标顺序修正:WKB中坐标存储顺序是经度→纬度,所以解包后要把第二个值作为纬度,第一个作为经度。
  4. 移除无效字节:你的WKB字符串末尾有多余的fe字节,需要先移除,否则会导致解析错位。

内容的提问来源于stack exchange,提问作者Maher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 20:57:00