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

Geophp Laravel Package

phayes/geophp

GeoPHP is a PHP library for reading, writing, and manipulating geospatial data. It supports WKT, WKB, GeoJSON, KML, GPX, and other formats, with optional GEOS integration for advanced geometry operations. Ideal for importing, converting, and analyzing spatial data in PHP applications.

Deep Wiki
Context7

Getting Started

Install via Composer (the package has no Laravel service provider — it is a plain library):

composer require phayes/geophp

The package ships a geoPHP.inc file and registers a global geoPHP class plus a family of geometry classes (Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection). Everything is static on geoPHP or instance methods on the geometry objects returned.

First sanity check — confirm what you actually got installed, because almost every capability question hinges on GEOS:

use geoPHP;

geoPHP::version();        // library version
geoPHP::geosInstalled();  // true only if ext-geos is compiled in

geosInstalled() returns a cached boolean. If you install the extension mid-process you must call geoPHP::geosInstalled(true) to reset the cache.

Your first real use case is almost always stored WKT → GeoJSON for a frontend map, plus a cheap measurement:

$geom = geoPHP::load('POLYGON((0 0,0 10,10 10,10 0,0 0))', 'wkt');

$geom->area();          // 100.0 (planar units)
$geom->centroid()->out('wkt');   // 'POINT (5 5)'
$geom->out('geojson');  // array, ready for json_encode()

Look first at:

  • geoPHP::load() and its second argument (the adapter name),
  • Geometry::out($format) for serialization,
  • Geometry::area(), length(), centroid(), envelope(), boundary(), convexHull(),
  • the GEOS-gated predicates (intersects, contains, distance, buffer, union, …).

Implementation Patterns

Normalize on the way in, serialize on the way out. Pick one canonical storage format per project — WKT is the most debuggable, WKB is the most compact — and convert at the boundary. A thin wrapper keeps geoPHP calls out of your controllers:

final class Geometry
{
    public static function fromWkt(string $wkt): \Geometry
    {
        $g = geoPHP::load($wkt, 'wkt');
        if (! $g) {
            throw new InvalidArgumentException('Unparseable WKT');
        }
        return $g;
    }

    public static function toGeoJson(\Geometry $g): array
    {
        return $g->out('geojson');
    }
}

Use format detection for untrusted / mixed input. When the source could be GeoJSON, KML, GPX or WKT (uploads, third-party APIs, imported shapefiles-as-text), let the library sniff it rather than branching yourself:

$format = geoPHP::detectFormat($payload);   // 'json', 'kml', 'gpx', 'wkt', ...
$geom   = geoPHP::load($payload, $format);

Database round-trips. For MySQL/MariaDB spatial columns, read as text and let geoPHP parse it; write back via the DB's constructor so the SRID sticks:

// read
$wkt = DB::table('parcels')->value(DB::raw('ST_AsText(shape)'));

// write
DB::statement('UPDATE parcels SET shape = ST_GeomFromText(?, ?) WHERE id = ?',
    [$geom->out('wkt'), 4326, $id]);

Do the heavy spatial predicates (ST_Intersects, ST_Contains) in the database whenever the data lives there — geoPHP has no spatial index, so intersects() across a collection is O(n·m) in PHP. Reserve the in-PHP predicates for small, already-fetched sets.

GeoJSON Feature vs. bare geometry. out('geojson') emits a bare geometry object ({"type":"Polygon","coordinates":…}). If your client expects a Feature, wrap it and add properties yourself — geoPHP does not model properties/attributes.

Ingesting KML / GPX. geoPHP::load($kml, 'kml') returns the geometry (often a GeometryCollection), not a document model. For GPX you typically get a collection of tracks/routes/waypoints; iterate with getComponents() and branch on getGeometryType().

Validation gate before persisting. Cheap checks that catch most bad input:

if ($geom->isEmpty()) { /* reject */ }
if (geoPHP::geosInstalled() && ! $geom->isValid()) { /* reject or buffer(0) fix */ }

buffer(0) is the classic self-intersection repair, and it requires GEOS.

Keep it in a queued job for anything involving large KML/GPX files or per-feature loops. Parsing is CPU-bound and allocates a lot of small objects.

Gotchas and Tips

  • GEOS is optional and gates half the API. intersects(), contains(), touches(), crosses(), overlaps(), distance(), buffer(), union(), intersection(), difference(), convexHull(), isValid() and isSimple() throw (Exception('GEOS not installed') or a fatal on missing method) when ext-geos is absent. Plan for it: either install the extension in your image, or feature-detect and fall back to DB-side PostGIS/MySQL spatial functions. Do not assume CI has it — pin it in the Dockerfile explicitly.
  • "GEOS not installed" is cached. Calling geosInstalled() after a runtime dl() returns the stale value unless you pass true.
  • SRID is metadata only — there is no reprojection. getSRID()/setSRID() tag a geometry; nothing transforms it. Mixing 4326 and 3857 and then calling area() or distance() silently yields nonsense. Convert coordinates yourself (proj4 bindings, or do it in the database) before they reach geoPHP.
  • Licensing is ambiguous and flagged as NOASSERTION. geoPHP has historically been distributed under GPL-2.0-or-later (with some files under BSD/MIT). Treat it as GPL until your legal review says otherwise — that is a real constraint for closed-source products.
  • geoPHP::load() returns false, not an exception, on parse failure. Every call site needs a null/false check; a false leaking into ->area() is a fatal, not an error page.
  • Adapter names are specific strings, not MIME types: 'wkt', 'wkb', 'json'/'geojson', 'kml', 'gpx', 'georss', 'google_geojson'. Passing the wrong name gives you a confusing parse failure rather than a clear "unknown format".
  • EWKT (SRID=4326;POINT(...)) is not universally handled. Strip the SRID=…; prefix before parsing, or feed it through the WKB adapter if you're on a version that supports EWKB. Test it rather than assuming.
  • GeoJSON coordinate order is [x, y] = [lon, lat] — geoPHP follows the spec. KML is always 4326 as well, so importing KML into a projected pipeline needs an explicit transform step.
  • getComponents() is nested — a MultiPolygon gives you Polygons, each of which gives you LineString rings via getComponents() again (use exteriorRing() / interiorRing() for the first/last). Off-by-one traversal is the most common source of bugs here.
  • Empty geometry methods return null — centroid(), envelope() and friends on an empty geometry will bite you downstream. Guard with isEmpty().
  • asText() / asBinary() are legacy aliases for out('wkt') / out('wkb'). Prefer out() in new code; the aliases have drifted across versions.
  • Performance: no spatial index, no prepared geometries across calls, and pure-PHP WKB parsing is noticeably slower than GEOS-backed reads. For bulk imports, batch by file, stream where the format allows, and avoid calling area()/centroid() inside a tight loop over thousands of features if you can precompute or push it to SQL.
  • Autoloading quirk: on older 1.x installs the library relies on its bundled geoPHP.inc autoloader; if you skip the Composer autoload or vendor a copy manually, classes silently fail to resolve. Always require vendor/autoload.php and confirm class_exists('geoPHP').
  • Extension points are static and global. geoPHP::registerAdapter() lets you add a custom format adapter (e.g. a TopoJSON reader) by implementing the adapter interface and registering the name — useful when you need a format the package doesn't ship, but remember it mutates global state for the whole process, which is awkward under long-running workers (Octane, queue daemons).
  • The package is largely unmaintained. Pin the version in composer.json, vendor a fork if you need patches, and keep an eye on brick/geo or a PostGIS-centric design as the migration path if you find yourself needing reprojection, spatial indexes, or robust topological ops.
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.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections