phayes / geoPHP

Advanced geometry operations in PHP
https://geophp.net
Other
863 stars 263 forks source link

Fix empty point behaviour in wkb, ewkb, and hexewkb formats #187

Open tw99 opened 2 years ago

tw99 commented 2 years ago

Issue

When loading an empty point geometry encoded in one of the above formats, the coordinate doubles unpacked in WKB.class#getPoint are both NAN

  function getPoint(&$mem) {
    $point_coords = unpack("d*", fread($mem,$this->dimension*8));
    if (!empty($point_coords)) {
      return new Point($point_coords[1],$point_coords[2]);
    }
    else {
      return new Point(); // EMPTY point
    }
  }

Because of the NAN values, the empty point is able to bypass the safeguards in the Point.class constructor.

    // Basic validation on x and y
    if (!is_numeric($x) || !is_numeric($y)) {
      throw new Exception("Cannot construct Point. x and y should be numeric");
    }

This results in an invalid Point object, where $point->isEmpty() is false.

Observations

Postgres seems to implicitly encode POINT EMPTY as POINT(NAN, NAN), and by default returns the hexewkb representation.

Postgres:

Screen Shot 2021-12-02 at 11 08 25 PM

>>> select st_ashexewkb(st_geomfromtext('POINT EMPTY'));
=> "0101000000000000000000F87F000000000000F87F"

Verifying in PHP:

>>> bin2hex(pack('cLdd', 1, 1, NAN, NAN))
=> "0101000000000000000000f87f000000000000f87f"

Problems

1. Reading the above empty point binary with GeoPhp:

>>> geoPHP::load('0101000000000000000000F87F000000000000F87F')->asArray()
=> [
     NAN,
     NAN,
   ]

>>> geoPHP::load('0101000000000000000000F87F000000000000F87F')->isEmpty()
=> false

2. Empty Point binary output representation is invalid.

>>> bin2hex(geoPHP::load('0101000000000000000000F87F000000000000F87F')->out('ewkb'))
=> "0101000000"
>>> select st_astext('0101000000'::geometry)

=> [XX000] ERROR: WKB structure does not match expected size! Position: 18

Solutions

*Note: this solution works for empty point geometries with different srid's as well.

itamair commented 1 year ago

This repo looks kind of abandoned/un-maintanied FYI, this has been embedded/fixed into this fork repo: https://github.com/itamair/geoPHP throughout this commit: https://github.com/itamair/geoPHP/commit/7de893d413447a0004dd1149c058c682ddd1cd98