mjaschen/phpgeo
PHPGeo is a lightweight geospatial library for PHP. Model geographic coordinates (with ellipsoid support) and compute high‑precision distances and related calculations between points. Compatible with modern PHP versions (8.2+ for latest).
Installation:
composer require mjaschen/phpgeo
Ensure your composer.json targets PHP 8.2+ (recommended: ^6.0).
First Use Case: Calculate distance between two coordinates (e.g., Mauna Kea and Haleakala):
use Location\Coordinate;
use Location\Distance\Vincenty;
$pointA = new Coordinate(19.820664, -155.468066); // Mauna Kea
$pointB = new Coordinate(20.709722, -156.253333); // Haleakala
$distance = (new Vincenty())->getDistance($pointA, $pointB); // 128130.850 meters
Key Classes to Explore:
Coordinate: Represents latitude/longitude.Vincenty/Haversine: Distance calculators.Polygon: For geofencing (e.g., "Is this point inside my area?").Polyline: For GPS tracks or routes.Documentation: Start with the official docs for class references and examples.
$calculator = new Vincenty(); // or Haversine for simpler (but less accurate) results
$distance = $calculator->getDistance($coord1, $coord2);
$distanceKm = $distance / 1000;
$geofence = new Polygon();
$geofence->addPoint(new Coordinate(/* ... */));
if ($geofence->contains($userLocation)) {
// Allow access
}
scopeGeofenced() query builder method:
// app/Models/User.php
public function scopeGeofenced($query, Polygon $geofence) {
return $query->where(function($q) use ($geofence) {
$q->whereRaw("ST_Contains(ST_GeomFromText('POLYGON(...')), ST_Point(longitude, latitude))");
});
}
$polyline = new Polyline();
$polyline->addPoint(new Coordinate(/* ... */));
$simplified = (new \Location\Simplify($polyline))->simplify(1000); // Tolerance: 1km
Cache::remember("user_{$userId}_route", now()->addHours(1), function() use ($polyline) {
return $polyline->format(new \Location\Formatter\Polyline\GeoJSON());
});
$bearing = $coord1->getBearingTo($coord2); // Degrees (0-360)
$destination = $coord1->getDestinationPoint($bearing, 1000); // 1km away
$formatter = (new \Location\Formatter\Coordinate\DMS())
->setSeparator(", ")
->useCardinalLetters(true);
echo $coord->format($formatter); // "18° 54' 41" N, 155° 40' 42" W"
decimal(10,8) for latitude/longitude (e.g., latitude DECIMAL(10,8)).GEOGRAPHY type for advanced queries:
// Using Laravel Scout with PostGIS
use Laravel\Scout\Builder;
class LocationScout extends Builder {
public function geofenced($polygon) {
return $this->whereRaw("ST_Intersects(geography, ST_GeomFromText('POLYGON(...)'))");
}
}
return response()->json([
'location' => [
'decimal' => $coord->format(new \Location\Formatter\Coordinate\DecimalDegrees()),
'dms' => $coord->format(new \Location\Formatter\Coordinate\DMS()),
],
]);
Cache::remember("distance_{$fromId}_{$toId}", now()->addHours(1), function() use ($from, $to) {
return (new Vincenty())->getDistance($from, $to);
});
Location\Test\Assertions for assertions:
$this->assertTrue($geofence->contains($point));
$this->assertAlmostEqual(128130.850, $distance, 0.001);
Ellipsoid Assumptions:
phpgeo uses the WGS-84 ellipsoid (correct for most GPS data). Gotcha: If working with non-Earth data (e.g., Mars), explicitly set the ellipsoid:
$coord = new Coordinate(..., ..., new \Location\Ellipsoid\Custom(/* ... */));
Polygon Edge Cases:
contains() method may return false positives.Floating-Point Precision:
$coord = new Coordinate(round($lat, 6), round($lon, 6));
Immutable Objects:
Line, Polyline, and Polygon are immutable post-construction. To "modify" them, create a new instance:
// Wrong (throws exception):
$polyline->addPoint($newPoint);
// Correct:
$newPolyline = clone $polyline;
$newPolyline->addPoint($newPoint);
Performance:
$polyline = (new \Location\Simplify($rawPolyline))->simplify(1000)->getPolyline();
GeoJSON Quirks:
[longitude, latitude], but phpgeo uses [latitude, longitude]. Use GeoJSON formatter carefully:
$geoJson = $coord->format(new \Location\Formatter\Coordinate\GeoJSON());
// Output: { "type": "point", "coordinates": [ -155.678268, 18.911306 ] }
Visualize Geometries:
// Dump GeoJSON to a view
return view('debug', [
'geojson' => $polygon->format(new \Location\Formatter\Polygon\GeoJSON()),
]);
Log Coordinates:
if (
How can I help you explore Laravel packages today?