gasparesganga/php-shapefile
Read and write ESRI Shapefiles in PHP with support for common geometry formats. php-shapefile handles SHP/SHX/DBF data, works with WKT and GeoJSON, and includes docs and examples for parsing, editing, and exporting.
Installation:
composer require gasparesganga/php-shapefile
Add to composer.json if using Laravel's autoloader:
"autoload": {
"psr-4": {
"App\\": "app/",
"Shapefile\\": "vendor/gasparesganga/php-shapefile/src/"
}
}
Run composer dump-autoload.
First Use Case: Read a shapefile:
use Shapefile\ShapefileReader;
$reader = new ShapefileReader('path/to/shapefile.shp');
$record = $reader->fetchRecord(); // Fetch first record
$geometry = $record->getGeometry(); // Get geometry object
$properties = $record->getProperties(); // Get attributes
Reading Shapefiles:
$reader = new ShapefileReader('file.shp', [
Shapefile::OPTION_DBF_CONVERT_TO_UTF8 => true,
Shapefile::OPTION_POLYGON_CLOSED_RINGS_ACTION => Shapefile::ACTION_FORCE,
]);
while ($record = $reader->fetchRecord()) {
$geom = $record->getGeometry();
$props = $record->getProperties();
// Process data
}
Writing Shapefiles:
$writer = new ShapefileWriter('output.shp', [
Shapefile::OPTION_BUFFERED_RECORDS => true,
Shapefile::OPTION_EXISTING_FILES_MODE => Shapefile::MODE_OVERWRITE,
]);
// Add fields
$writer->addField('name', Shapefile::DBF_TYPE_CHAR, 50);
$writer->addField('area', Shapefile::DBF_TYPE_FLOAT, 10, 2);
// Add records
$writer->addRecord([
'name' => 'Region 1',
'area' => 125.5,
'geometry' => new Shapefile\Geometry\Polygon([...])
]);
GeoJSON Conversion:
$reader = new ShapefileReader('file.shp');
$features = [];
while ($record = $reader->fetchRecord()) {
$features[] = $record->toGeoJSON();
}
WKT Conversion:
$geom = new Shapefile\Geometry\Polygon([...]);
$wkt = $geom->toWKT();
Storage facade to handle file paths:
$path = storage_path('app/shapefiles/file.shp');
$reader = new ShapefileReader($path);
public function getGeoJsonAttribute()
{
$geom = new Shapefile\Geometry\Polygon($this->coordinates);
return $geom->toGeoJSON();
}
return response()->json($shapefile->toGeoJSON());
ShapefileProcessor::dispatch('large_file.shp')->onQueue('shapefiles');
File Corruption:
.shx or .dbf), use:
$reader = new ShapefileReader('file.shp', [
Shapefile::OPTION_IGNORE_FILE_DBF => true,
Shapefile::OPTION_IGNORE_FILE_SHX => true,
]);
try {
$reader = new ShapefileReader('file.shp');
} catch (ShapefileException $e) {
Log::error("Shapefile error: " . $e->getMessage());
}
Polygon Orientation:
$polygon = new Shapefile\Geometry\Polygon([...], [
'force_orientation' => Shapefile::ORIENTATION_CLOCKWISE,
]);
forceCounterClockwise() if converting to OGC-compliant formats.Field Name Sanitization:
$writer->addField('Field Name', Shapefile::DBF_TYPE_CHAR, 50, null, null, true);
Shapefile::OPTION_DBF_FORCE_ALL_CAPS for consistency:
$writer = new ShapefileWriter('file.shp', [
Shapefile::OPTION_DBF_FORCE_ALL_CAPS => true,
]);
Performance:
$writer = new ShapefileWriter('file.shp', [
Shapefile::OPTION_BUFFERED_RECORDS => true,
]);
flushBuffer() periodically to reduce memory usage:
$writer->flushBuffer();
Coordinate Systems:
php-proj or geosphp for transformations:
// Example with geosphp
$geom = new Shapefile\Geometry\Polygon([...]);
$wkt = $geom->toWKT();
$transformed = Proj::transform($wkt, 'EPSG:4326', 'EPSG:3857');
Empty Shapefiles:
getTotRecords() returns Shapefile::UNKNOWN. Handle this case:
if ($reader->getTotRecords() === Shapefile::UNKNOWN) {
// Handle empty shapefile
}
DBF Field Limits:
$writer = new ShapefileWriter('file.shp', [
Shapefile::OPTION_DBF_ALLOW_FIELD_SIZE_255 => true,
]);
Enable Detailed Errors:
try {
$reader = new ShapefileReader('file.shp');
} catch (ShapefileException $e) {
Log::error("Error details: " . $e->getDetails());
}
Check Geometry Validity:
isValid() on geometry objects:
if (!$polygon->isValid()) {
$polygon->forceClosedRings();
}
Validate GeoJSON:
json_validate helper or a library like geojson-php to validate GeoJSON output.Custom Geometry Classes:
Shapefile\Geometry classes to add domain-specific logic:
class CustomPolygon extends Shapefile\Geometry\Polygon {
public function calculateCustomArea() {
// Custom logic
}
}
Override Field Encoding:
ShapefileWriter to customize field encoding:
class CustomWriter extends ShapefileWriter {
protected function encodeFieldValue($value, $type, $size, $decimals) {
// Custom encoding logic
}
}
Add Validation:
$validator = Validator::make($properties, [
'name' => 'required|string|max:50',
'area' => 'required|numeric|min:0',
]);
Event Listeners:
shapefile.record.processed):
event(new ShapefileProcessed($record));
How can I help you explore Laravel packages today?