Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Wkb Parser Laravel Package

creof/wkb-parser

A lightweight PHP parser for Well-Known Binary (WKB) geometry data. It converts WKB/EWKB strings into usable PHP geometry objects, making it easy to work with spatial data from databases and GIS tools without heavy dependencies.

Deep Wiki
Context7

Getting Started

creof/wkb-parser is a small, focused reader: you give it WKB/EWKB bytes, it gives you back geometry value objects. There is no encoder, no database layer, and no GeoJSON serializer bundled — treat it as the "decode" half of a geometry pipeline.

Install it with Composer:

composer require creof/wkb-parser

The first place to look is the installed source, not the README, because the package is small and the README is thin:

ls vendor/creof/wkb-parser/src
sed -n '1,200p' vendor/creof/wkb-parser/src/CrEOF/WKB/Parser.php

Check two things in particular: the exact namespace of Parser, and whether parse() expects raw binary or a hex string in your installed version. Then confirm the geometry classes returned (the package depends on/returns geometry objects from the same author's geo namespace — verify the class names with get_class($result) on your first successful parse).

A minimal first use case — decode a PostGIS hex WKB value and inspect the resulting geometry:

use CrEOF\WKB\Parser;

// WKB for POINT(1 1), hex-encoded (as PostGIS often returns it)
$hex = '0101000000000000000000f03f000000000000f03f';
$wkb = hex2bin($hex);

$parser = new Parser();
$geometry = $parser->parse($wkb);

var_dump(get_class($geometry)); // confirm class/namespace for your version

If that works, the day-to-day use is almost always: fetch a geometry column from PostGIS/MySQL, decode it, and hand the coordinates to your application or an API response. If parse() fails on the binary string, pass the hex string directly instead — see Gotchas.

Implementation Patterns

Decode PostGIS output inside a repository. The clean pattern is to keep parsing at the data-access boundary so the rest of the app never sees WKB:

final class PlaceRepository
{
    public function __construct(
        private PDO $pdo,
        private Parser $parser
    ) {}

    public function find(int $id): ?Place
    {
        $stmt = $this->pdo->prepare(
            'SELECT id, name, ST_AsBinary(location) AS location_wkb
             FROM places WHERE id = :id'
        );
        $stmt->execute(['id' => $id]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            return null;
        }

        return new Place(
            $row['id'],
            $row['name'],
            $this->parser->parse($row['location_wkb'])
        );
    }
}

ST_AsBinary (not ST_AsText) keeps the payload smaller and avoids the WKT parser dependency. Because Parser is stateless in normal use, register one instance in your container and inject it.

Use EWKB when SRID matters. PostGIS ST_AsEWKB embeds the SRID; plain ST_AsBinary does not. Use ST_AsEWKB if downstream code (transformations, storage) needs to know which coordinate system the geometry belongs to:

$stmt = $this->pdo->query('SELECT ST_AsEWKB(location) FROM places');
$geometry = $parser->parse($stmt->fetchColumn()); // carries SRID

Keep the WKB payload binary and store the SRID separately (ST_SRID(location)) if you want to be robust against parser version differences in EWKB flag handling.

Normalize hex/binary input at the edge. Many drivers hand back hex or PostGIS bytea escapes. Wrap the parser so callers always pass a clean binary string:

function decodeWkb(Parser $parser, string|resource $value): object
{
    if (is_resource($value)) {
        $value = stream_get_contents($value); // PDO pgsql bytea as a stream
    }

    // PostGIS bytea hex escape: \x0101000000...
    if (str_starts_with($value, '\\x')) {
        $value = substr($value, 2);
    }

    // Heuristic: WKB's first byte is 0x00/0x01 (endianness).
    // Anything longer and all-hex is probably hex-encoded.
    if (strlen($value) > 2 && ctype_xdigit($value)) {
        $value = hex2bin($value);
    }

    return $parser->parse($value);
}

Convert to GeoJSON at the API boundary. The package returns geometry objects, not arrays. Write one explicit adapter and test it heavily; this is where you map each geometry type to {type, coordinates} and recurse into GeometryCollection:

function toGeoJson($geometry): array
{
    // switch on the type accessor exposed by the returned geometry class,
    // e.g. Point -> [x, y], LineString -> [[x,y],...], etc.
    // Recurse for Multi* and GeometryCollection.
}

Keeping this conversion in one place means upgrades or a parser swap only break the adapter, not every controller.

Custom Doctrine type. If you use Doctrine, map geometry columns to a custom type whose convertToPHPValue calls the parser and whose convertToDatabaseValue emits EWKB (or, better, defers to PostGIS functions in the query). This keeps entity code free of Parser calls and centralizes hex/bytea normalization.

Batch parsing. When exporting many rows, reuse a single Parser instance, wrap each parse in try/catch so one malformed geometry doesn't abort the export, and log the offending hex with its primary key. WKB is compact but a large polygon collection can still hold a lot of coordinates — stream rows rather than fetchAll.

Gotchas and Tips

  • Hex vs. binary is the number-one failure mode. A "valid" WKB string passed as hex will produce nonsense or an exception, and vice versa. Always confirm which one your installed parse() expects by parsing a known one-point fixture both ways. The first byte of real WKB is 0x00 or 0x01; if the first character is '0' and the string is all hex digits, you almost certainly have hex.
  • PDO/PostGIS bytea quirks. pgsql PDO returns bytea as a stream resource on some setups and as a \x...-escaped string on others. Normalize both before parsing. Avoid PDO::ATTR_STRINGIFY_FETCHES surprises when comparing test fixtures.
  • Endianness. WKB can be little- or big-endian; MySQL and PostGIS typically emit little-endian, but third-party tooling may not. Verify with a big-endian fixture rather than assuming. If your version fails on big-endian, convert at the source or fork.
  • EWKB flag bits. EWKB overloads the geometry type integer: 0x80000000 = has SRID, 0x40000000 = Z, 0x20000000 = M. If coordinates come back shifted or truncated, dump the type word and decode the flags manually — a type of 0x20000001 is not a typo.
  • Z/M coordinates are the weak spot. Confirm your version's handling of 3D and measured geometries with explicit fixtures; many parsers silently drop M or throw on Z. If you need Z, test before promising it in an API.
  • Empty geometries and nulls. GEOMETRYCOLLECTION EMPTY, POINT EMPTY, and SQL NULL arrive differently. Handle NULL before parsing and add fixtures for empty geometries; don't let a NULL column reach parse().
  • No encoder exists in this package. Round-tripping requires another library (or a WKB writer you maintain), or letting the database produce WKB. Don't design a "parse → modify → re-encode" flow assuming this package covers the second half.
  • Maintenance and PHP versions. The last release was March 2022. Pin the version in composer.json, and run your PHP 8.2/8.3 matrix early. If it breaks, the parser is small enough to fork or vendor, or consider creof/geo-parser / an actively maintained alternative. Abstract it behind a GeometryDecoder interface so the swap is cheap.
  • Error handling is coarse. Wrap parse() in try/catch and convert exceptions into your own domain exception that includes a hex excerpt and the source row id. Raw parser exceptions are hard to trace back to a record.
  • Performance and safety. WKB can encode enormous coordinate counts; parsing is byte-by-byte in PHP. For large polygons, measure before using it in hot paths, cache decoded geometries where sensible, and cap blob size before parsing untrusted input.
  • Extension points are limited, so compose instead. Rather than subclassing Parser, build thin wrappers for input normalization, GeoJSON conversion, and Doctrine integration. That keeps you compatible with upstream changes and gives you clear seams for tests.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle