jayeshmepani/jpl-moshier-ephemeris-php
PHP 8.3+ FFI wrapper for the JPL Moshier Ephemeris C library, exposing all 204 jme_* functions and native JME_* constants. Supports JPL, Moshier, and VSOP87/ELP2000/Meeus engines with no hidden rounding or output reshaping. Requires ext-ffi and a compiled libjme shared library.
Installation
composer require jayeshmepani/jpl-moshier-ephemeris-php:^2.0
Ensure your PHP version is 8.3+ (FFI requirement). Version 2.0.0 ships JME 2.0.0 native runtimes (Linux/macOS/Windows with matching CALCEPH).
First Use Case: Basic Ephemeris Query
use JPL\Ephemeris\Ephemeris;
// Initialize the ephemeris engine (auto-detects native lib)
$ephemeris = new Ephemeris();
// Register the ephemeris directory (relative kernel names resolve here in 2.0)
$ephemeris->setEphemerisDir(__DIR__.'/vendor/jayeshmepani/jpl-moshier-ephemeris-php/resources');
// High-level JPL calculations open the configured kernel automatically
$time = 0.0; // JD - 2451545.0
$result = $ephemeris->jme_ephem($time, 3, 0); // 3 = Earth (core body)
if ($result['status'] === JME\JME_OK) {
echo "Position: ["
. $result['state'][0] . ", "
. $result['state'][1] . ", "
. $result['state'][2] . "]";
}
Where to Look First
src/Ephemeris.php: Core class with auto-detection for native libraries.resources/: Pre-bundled ephemeris files (e.g., de440.bsp) — also the default kernel directory root.libs/: OS-specific native libraries (auto-resolved; rebuilt from JME 2.0.0 C17 source).tests/: Example use cases and contract tests that document the 2.0 behaviors.Automatic Native Library Resolution
// No manual path needed - auto-detects:
// - Ubuntu 22/24 (glibc detection)
// - macOS arm64 (Darwin kernel 14/15)
// - Windows MSVC 2022
$ephemeris = new Ephemeris(); // Uses default constructor
$ephemeris = new Ephemeris('/custom/path/to/libjme.so');
Kernel Loading (v2 behavior)
loadEphemeris() before calling jme_ephem() etc.$ephemeris = new Ephemeris();
$ephemeris->setEphemerisDir('/var/ephemeris');
// 'de440.bsp' is now looked up under /var/ephemeris/
$ephemeris->jme_ephem($time, 3, 0);
loadEphemeris('/path/to/custom.bsp') still work if you prefer to be explicit.Time Handling
JD - 2451545.0 (J2000 epoch).$jd = JME\jme_jd2cal(2451545.0 + $time); // Convert back to Gregorian
Query Patterns
jme_ephem):
$result = $ephemeris->jme_ephem($time, $bodyId, 0); // 0 = position + velocity
use const JME\JME_BODY_*; // see libjme constants
// Extended-body IDs moved to JME's reserved NEGATIVE range in 2.0.
// Do NOT store raw numeric extended-body IDs; persist the symbolic name instead.
$result = $ephemeris->jme_ephem($time, $extendedBodyConstant, 0);
jme_ltex):
$correctedTime = $ephemeris->jme_ltex($time, $bodyId, $observerId);
Laravel Integration
// app/Providers/EphemerisServiceProvider.php
public function register()
{
$this->app->singleton(Ephemeris::class, function () {
$ephemeris = new Ephemeris(); // Auto-resolves native lib
$ephemeris->setEphemerisDir(config('ephemeris.dir'));
return $ephemeris;
});
}
Caching Results
$cacheKey = "ephemeris:{$bodyId}:{$time}";
if (!Cache::has($cacheKey)) {
$result = $ephemeris->jme_ephem($time, $bodyId, 0);
Cache::put($cacheKey, $result, now()->addHours(1));
}
BREAKING: Extended-Body Identifiers (2.0.0)
Unsupported Rise/Set Options Now Error
rise/set options return explicit errors instead of being silently ignored. If you relied on the old "silent no-op" behavior, validate inputs and handle the new error status.Kernel Resolution Behavior Changed
loadEphemeris() is optional.resources/.$ephemeris = new Ephemeris();
error_log("Using library: " . $ephemeris->getNativeLibraryPath());
FFI Requirements
php.ini:
extension=ffi
if (!extension_loaded('ffi')) {
throw new \RuntimeException('FFI extension required');
}
Error Handling
$result['status']:
if ($result['status'] !== JME\JME_OK) {
throw new \RuntimeException("JME Error: {$result['status']} - " . $result['errbuf']);
}
Precision Warnings
double precision:
$time = 123456789.123456789; // High precision
Thread Safety
libjme is NOT thread-safe. Use a single Ephemeris instance per request in Laravel.Log Library Path
error_log("Native library path: " . $ephemeris->getNativeLibraryPath());
Confirm the 2.0 Runtime
Validate Auto-Detection
$ephemeris = new Ephemeris();
$libPath = $ephemeris->getNativeLibraryPath();
if (strpos($libPath, 'default') !== false) {
error_log("Warning: Using fallback library");
}
FFI Debugging
FFI::debug(true);
Custom Library Paths
// Override auto-detection for specific environments
if (app()->environment('staging')) {
$ephemeris = new Ephemeris('/staging/libs/libjme.so');
}
Wrap Additional Functions
public function getBodyPosition($time, $bodyId) {
$result = $this->jme_ephem($time, $bodyId, 0);
return $result['state'] ?? null;
}
Laravel Observers
// app/Observers/AstronomicalEventObserver.php
public function calculatingPosition($event) {
$position = app(Ephemeris::class)->getBodyPosition($event->time, $event->bodyId);
$event->position = $position;
}
Performance Optimization
parallel: for batch processing.ephemeris.dir in config/) so relative kernel names resolve consistently.ubuntu22/ubuntu24 variants.libs/default/ (may require manual setup).How can I help you explore Laravel packages today?