如何在 PHP 中解压 MySQL 多点几何数据?

How to unpack MySQL Multipoint geometry data in PHP?

好的,我想我已经很接近了,但是我在理解二进制数据方面遇到了限制。

我正在解析一些作为几何类型插入的 MySQL 数据,使用 PHP 的 unpack() 作为我的解析器,一切进展顺利,直到我开始尝试解包复杂几何类型(例如 MULTIPOINT)。

对于 POINT 数据类型,我使用解包模式取得了很好的成功,该模式简单地忽略了第一个块,然后给我一个 typeorder 的关联数组, latlon:

$coords = unpack('x/x/x/x/corder/Ltype/dlat/dlon', $point);
// >>> [
//       'order' => 1,
//       'type' => 1,
//       'lat' => (expected value),
//       'lon' => (expected value)
//     ];

自然地,将完全相同的模式应用到 MULTIPOINT 几何图形并不相同。它得到 order 并且 type 变为 4,但是 latlon 的值根本不是我所期望的。所以,出于好奇想看看整个事情是什么样子,我改变了模式,把它全部吐出来作为 "double (machine dependent size and representation)" 类型:

$coords = unpack('x/x/x/x/corder/Ltype/d*', $multipoint);
// >>> mayhem

解包的内容实际上包括 5 个额外的数组项,而不是我期望的 4 个多点具有两个点 (2x2),并且这些值完全是古怪的。例如,我希望某个值在 40 点左右的任何范围内,似乎读起来像 -1.0977282851114052e-218.

解压缩 MULTIPOINT 的正确方法是什么? 我的直觉告诉我我正在对不应该的字节进行切片或将它们转换为不合适的类型,但我不确定这些应该是什么。

稍微看了一下,但我找到了 a reference 各种几何体的 WKB 格式。正如我通过查看

的输出所猜测的那样
SELECT HEX(ST_GeomFromText('MULTIPOINT(1 1, 2 2, 3 3)'))

订单和类型后有积分。挑战在于顺序和类型 为每个点重新声明 并且 unpack 没有重复一组字节的概念。因此,您需要为每个点提取字节并再次 运行 unpack 。显然,一旦您尝试考虑更多空间类型,这将开始变得更加复杂。

<?php
$multipoint_wkb = hex2bin("000000000104000000030000000101000000000000000000F03F000000000000F03F010100000000000000000000400000000000000040010100000000000000000008400000000000000840");

function unpack_multipoint($multipoint)
{
    $data = unpack("x4/corder/Ltype/Lcount", $multipoint);
    for ($i = 0; $i < $data["count"]; $i++) {
        // the header is 1+4+8 bytes and each point record is 1+4+8+8 bytes
        $offset = ($i * 21) + 13;
        $return[] = unpack("corder/Ltype/dlat/dlon", $multipoint, $offset);
    }
    return $return;
}

print_r(unpack_multipoint($multipoint_wkb));

值得注意的是,这 4 个 NUL 字节是由 MySQL 插入的,但不是实际几何对象的一部分。我根据你的问题将它们留在原地,但如果你使用 ST_AsWKB 函数检索数据:

SELECT HEX(ST_AsWKB(ST_GeomFromText('MULTIPOINT(1 1, 2 2, 3 3)')))

额外的字节不会被添加到前面。