foysal50x/h3-php

PHP FFI bindings for Uber's H3 hexagonal hierarchical geospatial indexing system

Installs: 1

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/foysal50x/h3-php

v1.0.0 2025-11-28 16:40 UTC

This package is auto-updated.

Last update: 2025-11-28 17:25:36 UTC


README

H3 PHP Build Status Tests Latest Stable Version

H3 PHP FFI Bindings

PHP FFI bindings for Uber's H3 hexagonal hierarchical geospatial indexing system.

Based on H3 v4.4.1 - the latest version as of November 2025.

Requirements

  • PHP 8.1 or higher
  • PHP FFI extension enabled (ffi.enable=1 in php.ini)

Installation

1. Enable PHP FFI Extension

The FFI extension must be enabled in your php.ini:

; Enable the FFI extension
extension=ffi

; Enable FFI for all scripts (required for this library)
ffi.enable=true

Note: ffi.enable can be set to:

  • true or 1 - Enable FFI for all scripts (recommended for development)
  • preload - Enable FFI only in preloaded scripts (recommended for production)

To verify FFI is enabled:

php -m | grep FFI
php -i | grep ffi.enable

2. Install the PHP Package

composer require foysal50x/h3-php

This package includes pre-built H3 libraries for common platforms:

  • macOS (Apple Silicon & Intel)
  • Linux (x64 & ARM64)
  • Windows (x64)

The library will automatically detect and use the appropriate bundled binary.

3. (Optional) System H3 Library

If the bundled library doesn't work for your platform, you can install the H3 C library system-wide:

macOS (Homebrew):

brew install h3

Ubuntu/Debian:

sudo apt install libh3-dev

From source:

git clone https://github.com/uber/h3.git
cd h3
cmake -B build
cmake --build build
sudo cmake --install build

Quick Start

<?php

use Foysal50x\H3\H3;

$h3 = new H3();

// Convert coordinates to H3 cell
$cell = $h3->latLngToCell(37.7749, -122.4194, 9);
echo "H3 Index: " . $h3->h3ToString($cell) . "\n";

// Get cell center coordinates
$coords = $h3->cellToLatLng($cell);
echo "Center: {$coords['lat']}, {$coords['lng']}\n";

// Get neighboring cells
$neighbors = $h3->gridDisk($cell, 1);
echo "Neighbors: " . count($neighbors) . "\n";

API Reference

Indexing Functions

// Convert lat/lng to H3 cell
$cell = $h3->latLngToCell(float $lat, float $lng, int $resolution): int

// Convert H3 cell to lat/lng center
$coords = $h3->cellToLatLng(int $cell): array{lat: float, lng: float}

// Get cell boundary vertices
$boundary = $h3->cellToBoundary(int $cell): array

Inspection Functions

$h3->getResolution(int $cell): int
$h3->getBaseCellNumber(int $cell): int
$h3->h3ToString(int $cell): string
$h3->stringToH3(string $str): int
$h3->isValidCell(int $cell): bool
$h3->isResClassIII(int $cell): bool
$h3->isPentagon(int $cell): bool

Traversal Functions

// Get all cells within k distance (filled disk)
$cells = $h3->gridDisk(int $origin, int $k): array

// Get cells with their distances
$results = $h3->gridDiskDistances(int $origin, int $k): array

// Get cells in a hollow ring at exactly k distance
$cells = $h3->gridRing(int $origin, int $k): array

// Get grid distance between two cells
$distance = $h3->gridDistance(int $origin, int $destination): int

// Get path between two cells
$path = $h3->gridPathCells(int $start, int $end): array

Hierarchy Functions

// Get parent cell at coarser resolution
$parent = $h3->cellToParent(int $cell, int $parentRes): int

// Get all children at finer resolution
$children = $h3->cellToChildren(int $cell, int $childRes): array

// Get center child at finer resolution
$child = $h3->cellToCenterChild(int $cell, int $childRes): int

// Compact cells to minimal representation
$compacted = $h3->compactCells(array $cells): array

// Uncompact cells to specific resolution
$cells = $h3->uncompactCells(array $cells, int $res): array

Directed Edge Functions

$h3->areNeighborCells(int $origin, int $destination): bool
$h3->cellsToDirectedEdge(int $origin, int $destination): int
$h3->isValidDirectedEdge(int $edge): bool
$h3->getDirectedEdgeOrigin(int $edge): int
$h3->getDirectedEdgeDestination(int $edge): int
$h3->directedEdgeToCells(int $edge): array{origin: int, destination: int}
$h3->originToDirectedEdges(int $origin): array
$h3->directedEdgeToBoundary(int $edge): array

Vertex Functions

$h3->cellToVertex(int $cell, int $vertexNum): int
$h3->cellToVertexes(int $cell): array
$h3->vertexToLatLng(int $vertex): array{lat: float, lng: float}
$h3->isValidVertex(int $vertex): bool

Measurement Functions

// Average hexagon area at resolution
$h3->getHexagonAreaAvgKm2(int $res): float
$h3->getHexagonAreaAvgM2(int $res): float

// Exact cell area
$h3->cellAreaKm2(int $cell): float
$h3->cellAreaM2(int $cell): float
$h3->cellAreaRads2(int $cell): float

// Average edge length at resolution
$h3->getHexagonEdgeLengthAvgKm(int $res): float
$h3->getHexagonEdgeLengthAvgM(int $res): float

// Exact edge length
$h3->edgeLengthKm(int $edge): float
$h3->edgeLengthM(int $edge): float
$h3->edgeLengthRads(int $edge): float

// Great circle distance between coordinates
$h3->greatCircleDistanceKm(float $lat1, float $lng1, float $lat2, float $lng2): float
$h3->greatCircleDistanceM(float $lat1, float $lng1, float $lat2, float $lng2): float

Utility Functions

$h3->getNumCells(int $res): int
$h3->getRes0Cells(): array
$h3->getPentagons(int $res): array
$h3->degsToRads(float $degrees): float
$h3->radsToDegs(float $radians): float

Local IJ Coordinates

$h3->cellToLocalIj(int $origin, int $cell, int $mode = 0): array{i: int, j: int}
$h3->localIjToCell(int $origin, int $i, int $j, int $mode = 0): int

Error Handling

All methods that can fail will throw an H3Exception:

use Foysal50x\H3\H3;
use Foysal50x\H3\H3Exception;

try {
    $h3 = new H3();
    $cell = $h3->latLngToCell(37.7749, -122.4194, 20); // Invalid resolution
} catch (H3Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
    echo "H3 Error Code: " . $e->getH3ErrorCode() . "\n";

    if ($e->isInvalidResolution()) {
        echo "Resolution must be between 0 and 15\n";
    }
}

Common Exceptions

The library will throw H3Exception in these cases:

  1. FFI Extension Not Loaded

    The FFI extension is not loaded. Please enable it in your php.ini by adding "extension=ffi".
    
  2. FFI Not Enabled

    FFI is not enabled. Please set "ffi.enable=true" or "ffi.enable=preload" in your php.ini.
    
  3. H3 Library Not Found

    Could not find H3 library. Please install H3 or provide the library path.
    

Custom Library Path

If the H3 library is not in a standard location:

$h3 = new H3('/custom/path/to/libh3.so');

Singleton Pattern

For convenience, you can use the singleton pattern:

$h3 = H3::getInstance();
// ... use $h3 ...

// Reset if needed (required before using a different library path)
H3::resetInstance();

Note: If you try to get an instance with a different library path than the existing singleton, an exception will be thrown. Call resetInstance() first if you need to change the library path.

Security & Safety Features

This library includes several security and safety measures to prevent common FFI-related vulnerabilities:

Input Validation

All user inputs are validated before being passed to the C library:

// Coordinate validation (rejects NaN, Inf, out of range)
$h3->latLngToCell(NAN, 0.0, 9);  // Throws H3Exception

// H3 string validation (rejects null bytes, invalid hex, too long)
$h3->stringToH3("invalid!");     // Throws H3Exception
$h3->stringToH3("abc\0def");     // Throws H3Exception (null byte)

// Resolution relationship validation
$h3->cellToChildren($cell, 3);   // Throws if cell resolution >= 3
$h3->cellToParent($cell, 10);    // Throws if cell resolution <= 10

Memory Safety

Grid operations have configurable limits to prevent memory exhaustion:

// Default max k value is 500 (results in ~751,501 cells)
$h3->gridDisk($cell, 1000);  // Throws H3Exception

// Adjust the limit if needed for your use case
H3::setMaxGridK(1000);
$h3->gridDisk($cell, 1000);  // Now works

// Check current limit
$maxK = H3::getMaxGridK();

Descriptive Error Messages

Exceptions include detailed error information:

try {
    $h3->cellToChildren($cell, 3);
} catch (H3Exception $e) {
    // "Failed to get children cells: Resolution mismatch (code: 12)"
    echo $e->getMessage();
    echo $e->getCode();  // H3 error code
}

Resolution Guide

Resolution Avg Hex Area Avg Edge Length
0 4,357,449.416 km² 1,281.256 km
1 609,788.441 km² 483.057 km
2 86,801.780 km² 182.512 km
3 12,393.434 km² 68.979 km
4 1,770.347 km² 26.071 km
5 252.903 km² 9.854 km
6 36.129 km² 3.724 km
7 5.161 km² 1.406 km
8 0.737 km² 531.414 m
9 0.105 km² 200.786 m
10 0.015 km² 75.863 m
11 0.002 km² 28.663 m
12 307.092 m² 10.830 m
13 43.870 m² 4.092 m
14 6.267 m² 1.546 m
15 0.895 m² 0.584 m

Running Tests

composer install
composer test

License

MIT License - see LICENSE file.

Links