Swiss Ephemeris PHP FFI β€” 106 Functions Complete Mapping

Introduction

100% precise 1:1 FFI mapping of the Swiss Ephemeris C library for PHP.

Overview

My package provides a complete PHP FFI binding to the Swiss Ephemeris C library. I wrap all 106 functions from the official library, giving you direct access to professional-grade astronomical calculations. The binary library (libswe.so/swe.dll) is automatically downloaded on composer install.

106 Functions

Complete 1:1 mapping of all Swiss Ephemeris C library functions

Built-in Moshier

Works without ephemeris files using built-in Moshier algorithm (~1 arcsecond precision)

Milliarcsecond Precision

Optional ephemeris files for research-grade accuracy

Laravel Ready

Includes service provider and facade for seamless Laravel integration

Requirements

  • PHP 8.3+ β€” Required for typed constants, readonly classes
  • FFI Extension β€” Required for Foreign Function Interface
  • Swiss Ephemeris Binary β€” Automatically downloaded via composer

Quick Start

Install Package
composer require jayeshmepani/swiss-ephemeris-ffi

Enable FFI

Add to your php.ini:

php.ini
extension=ffi
ffi.enable=1
Basic Usage
<?php
use SwissEph\FFI\SwissEphFFI;

$sweph = new SwissEphFFI();

$jd = $sweph->swe_julday(2000, 1, 1, 12.0, SwissEphFFI::SE_GREG_CAL);

$xx = $sweph->getFFI()->new("double[6]");
$serr = $sweph->getFFI()->new("char[256]");

$result = $sweph->swe_calc_ut(
    $jd, 
    SwissEphFFI::SE_SUN, 
    SwissEphFFI::SEFLG_SPEED, 
    $xx, 
    $serr
);

echo "Sun Longitude: " . $xx[0] . "Β°\n";
echo "Sun Speed: " . $xx[3] . "Β°/day\n";

Installation & Setup

1. Install Package

Composer
composer require jayeshmepani/swiss-ephemeris-ffi

2. Enable FFI Extension

The FFI extension requires explicit enabling in php.ini. This is a security measure since FFI can execute arbitrary native code.

php.ini
extension=ffi
ffi.enable=1

3. Laravel Integration

config/app.php (Laravel < 11)
'providers' => [
    SwissEph\Service\SwissEphServiceProvider::class,
],
'aliases' => [
    'SwissEph' => SwissEph\Service\SwissEphFacade::class,
]
Laravel Usage
$jd = SwissEph::swe_julday(2000, 1, 1, 12.0, SwissEph::SE_GREG_CAL);

Platform-Specific Setup

Linux (Ubuntu/Debian)

Bash
# Install PHP FFI
sudo apt install php8.3-ffi

# Or for PHP 8.4
sudo apt install php8.4-ffi

Linux (CentOS/RHEL/Fedora)

Bash
sudo dnf install php-ffi
# or
sudo yum install php-ffi

macOS

Bash
# PHP from Homebrew includes FFI by default
brew install php@8.3

Windows

FFI is included with PHP 8.3+ for Windows. Just enable in php.ini as shown above.

Verify Installation

PHP
php -r "echo extension_loaded('ffi') ? 'FFI loaded' : 'FFI not loaded';"
php -r "echo ini_get('ffi.enable') ? 'FFI enabled' : 'FFI not enabled';"

Ephemeris Files (Optional)

Understanding the Two Components

  1. Binary (libswe.so / swe.dll) β€” Provided automatically by my package on composer install. Contains the calculation engine.
  2. Data files (.se1) β€” OPTIONAL. The C library has built-in Moshier algorithm (~1 arcsecond precision) that works WITHOUT any external files. For higher precision (milliarcsecond), download the ephemeris files.

Download Options

Option A β€” From My Releases (Recommended)

Download ephe-files.tar.gz

Trust Note: This archive is exactly the same as the upstream repository β€” I don't modify any files. It's just a mirror for convenience. You can verify by comparing file hashes with the official repo.

Option B β€” From Official Swiss Ephemeris

View on GitHub

Git Sparse Checkout
git clone --depth 1 --filter=blob:none --sparse https://github.com/aloistr/swisseph
cd swisseph
git sparse-checkout set ephe

File Types

Ephemeris file types and descriptions
File Description Size
sepl*.se1 Planet ephemeris (Sun-Pluto) ~27 MB
semo*.se1 Moon ephemeris ~70 MB
seas*.se1 Asteroid ephemeris (700,000+) ~100 MB
sepm*.se1 Planetary moon files Varies
sefstars.txt Fixed star names Small
seorbel.txt Fictitious planet orbital elements Small

Usage

PHP
$sweph = new SwissEphFFI();
$sweph->swe_set_ephe_path(__DIR__ . '/ephe');

Precision: Moshier vs Swiss Ephemeris

Run php examples/precision_demo.php to see the actual difference on your system.

Example Output (May 15, 1990, 14:30 UT)

This is actual output from running php examples/precision_demo.php on this system.

Without Ephemeris Files (Moshier - built-in)

Moon: 298.45007158851
Sun: 54.496555505961
Mercury: 38.000338678331
Venus: 12.937142407004
Mars: 348.4112182787
Jupiter: 99.561406572401
Saturn: 295.24767492246
Uranus: 279.18135006806
Neptune: 284.35136993429
Pluto: 226.16455507419

With Swiss Ephemeris Files (.se1)

Moon: 298.45019395505
Sun: 54.496545122771
Mercury: 38.000337751223
Venus: 12.937139147687
Mars: 348.41121491329
Jupiter: 99.561460556072
Saturn: 295.24764096018
Uranus: 279.18131332432
Neptune: 284.35134659349
Pluto: 226.16451075759

Difference (Swiss Eph - Moshier) β€” ACTUAL VALUES

Difference
Moon:    0.00012236653799391Β°    =   0.44051953677808 arcseconds
Sun:    -1.0383189994911E-5Β°    =  -0.037379483981681 arcseconds
Mercury: -9.2710805432716E-7Β°   =  -0.0033375889955778 arcseconds
Venus:   -3.2593169319028E-6Β°   =  -0.01173354095485 arcseconds
Mars:    -3.3654127946647E-6Β°   =  -0.012115486060793 arcseconds
Jupiter:  5.398367167686E-5Β°    =   0.1943412180367 arcseconds
Saturn:  -3.3962287091072E-5Β°  =  -0.12226423352786 arcseconds
Uranus:  -3.6743742214185E-5Β°  =  -0.13227747197107 arcseconds
Neptune: -2.3340794655269E-5Β°   =  -0.084026860758968 arcseconds
Pluto:   -4.4316591925053E-5Β°  =  -0.15953973093019 arcseconds

Summary Table

Precision difference by planet
Planet Difference (arcsec) Visual Impact
Moon 0.44" Can change sign near boundaries
Jupiter 0.19" Minor
Pluto 0.16" Minor
Saturn 0.12" Minor
Uranus 0.13" Minor
Neptune 0.08" Minor
Mars 0.01" Negligible
Venus 0.01" Negligible
Sun 0.04" Negligible
Mercury 0.003" Negligible

Key Insights

  • Moon shows the largest difference (~0.44 arcseconds). This can affect zodiac sign boundaries, especially close to 0Β° Aries, Cancer, Libra, Capricorn.
  • Planets show smaller differences (0.003-0.2 arcseconds) but matter for precise calculations.
  • Moshier provides ~1 arcsecond precision (good enough for most purposes)

When Does It Matter?

When to use ephemeris files
Use Case Moshier Enough? Why
General horoscopes Yes 1 arcsecond is invisible to naked eye
Moon sign calculations Maybe 0.5 arcsec can change sign near boundaries
Medical astrology No Requires highest precision
Research/dates No Historical accuracy needed
Solar Returns Yes Sun position clear enough

Complete Examples

Birth Chart (Tropical)

birth_chart.php
<?php
use SwissEph\FFI\SwissEphFFI;

$sweph = new SwissEphFFI();

$jd = $sweph->swe_julday(1990, 5, 15, 14.5, SwissEphFFI::SE_GREG_CAL);

$xx = $sweph->getFFI()->new('double[6]');
$serr = $sweph->getFFI()->new('char[256]');

$signs = ['Ari', 'Tau', 'Gem', 'Can', 'Leo', 'Vir', 'Lib', 'Sco', 'Sag', 'Cap', 'Aqu', 'Pis'];

$planets = [
    'Sun' => SwissEphFFI::SE_SUN,
    'Moon' => SwissEphFFI::SE_MOON,
    'Mercury' => SwissEphFFI::SE_MERCURY,
    'Venus' => SwissEphFFI::SE_VENUS,
    'Mars' => SwissEphFFI::SE_MARS,
    'Jupiter' => SwissEphFFI::SE_JUPITER,
    'Saturn' => SwissEphFFI::SE_SATURN,
    'Uranus' => SwissEphFFI::SE_URANUS,
    'Neptune' => SwissEphFFI::SE_NEPTUNE,
    'Pluto' => SwissEphFFI::SE_PLUTO,
];

echo "Birth Chart - May 15, 1990, 14:30 UT\n";
echo str_repeat("=", 40) . "\n\n";

foreach ($planets as $name => $p) {
    $result = $sweph->swe_calc_ut($jd, $p, SwissEphFFI::SEFLG_SPEED, $xx, $serr);
    $lon = $xx[0];
    $signIdx = floor($lon / 30);
    $deg = $lon % 30;
    echo sprintf("%-8s %7.2fΒ° %3s %2.2fΒ° (%s)\n", $name . ':', $lon, $signs[$signIdx], $deg, $xx[3] . "Β°/day");
}

Sidereal Lahiri Ayanamsa

sidereal_lahiri.php
<?php
use SwissEph\FFI\SwissEphFFI;

$sweph = new SwissEphFFI();

$jd = $sweph->swe_julday(2000, 1, 1, 12.0, SwissEphFFI::SE_GREG_CAL);

$xx = $sweph->getFFI()->new('double[6]');
$serr = $sweph->getFFI()->new('char[256]');

$sweph->swe_set_sid_mode(SwissEphFFI::SE_SIDM_LAHIRI, 0, 0);
$ayan = $sweph->swe_get_ayanamsa($jd);

echo "Ayanamsa (Lahiri): " . $ayan . "Β°\n";

$result = $sweph->swe_calc_ut($jd, SwissEphFFI::SE_SUN, 0, $xx, $serr);
$tropical = $xx[0];
$sidereal = $tropical - $ayan;
if ($sidereal < 0) $sidereal += 360;

echo "Tropical Sun: " . $tropical . "Β°\n";
echo "Sidereal Sun:  " . $sidereal . "Β°\n";

House Systems

houses.php
<?php
use SwissEph\FFI\SwissEphFFI;

$sweph = new SwissEphFFI();

$jd = $sweph->swe_julday(2000, 1, 1, 12.0, SwissEphFFI::SE_GREG_CAL);

$hsys = $sweph->getFFI()->new("char[1]");
$hsys[0] = ord('P');

$cusps = $sweph->getFFI()->new("double[13]");
$ascmc = $sweph->getFFI()->new("double[10]");
$serr = $sweph->getFFI()->new("char[256]");

$sweph->swe_houses($jd, SwissEphFFI::SE_GREG_CAL, 23.2, 72.8, ord('P'), $cusps, $ascmc, $serr);

echo "Placidus House Cusps:\n";
for ($i = 1; $i <= 12; $i++) {
    echo "House $i: " . $cusps[$i] . "Β°\n";
}
echo "\nAscendant: " . $ascmc[0] . "Β°\n";
echo "MC: " . $ascmc[1] . "Β°\n";
House system codes
Code System
'P' Placidus
'K' Koch
'R' Regiomontanus
'C' Campanus
'E' Equal
'W' Whole Sign

Function Coverage

My package provides 106 functions, which is 100% coverage of the official Swiss Ephemeris C library. This is more than competitors:

Comparison with other PHP Swiss Ephemeris packages
Package Functions Coverage
swiss-ephemeris-ffi (mine) 106 100%
php-sweph (cyjoelchen) 100 94%
swephe-php (nastal) 2 2%

Function Categories

  • Calendar & Time: swe_julday, swe_date_conv, etc. (4 functions)
  • Planetary Calculations: swe_calc, swe_calc_ut, swe_fixstar, etc. (8 functions)
  • Houses: swe_houses, swe_houses_ex, swe_houses_armc (4 functions)
  • Ayanamsa: swe_get_ayanamsa, swe_set_sid_mode (2 functions)
  • Ephemeris Files: swe_set_ephe_path, swe_load_ephe, etc. (5 functions)

All 106 Functions

Complete list of all 106 Swiss Ephemeris functions
Category Functions Count
Date & Time Conversions swe_julday, swe_revjul, swe_date_conversion, swe_utc_time_zone, swe_utc_to_jd, swe_jdet_to_utc, swe_jdut1_to_utc, swe_time_equ, swe_lmt_to_lat, swe_lat_to_lmt 10
Planet & Body Calculation swe_calc, swe_calc_ut, swe_calc_pctr, swe_get_planet_name 4
Fixed Stars swe_fixstar, swe_fixstar_ut, swe_fixstar_mag, swe_fixstar2, swe_fixstar2_ut, swe_fixstar2_mag 6
Houses & Angles swe_houses, swe_houses_ex, swe_houses_ex2, swe_houses_armc, swe_houses_armc_ex2, swe_house_pos, swe_house_name 7
Sidereal / Ayanamsa swe_set_sid_mode, swe_get_ayanamsa, swe_get_ayanamsa_ut, swe_get_ayanamsa_ex, swe_get_ayanamsa_ex_ut, swe_get_ayanamsa_name 6
Legacy Placalc swe_csnorm, swe_difcsn, swe_difdegn, swe_difcs2n, swe_difdeg2n, swe_difrad2n, swe_csroundsec, swe_d2l, swe_day_of_week, swe_cs2timestr, swe_cs2lonlatstr, swe_cs2degstr 12
Phenomena swe_pheno, swe_pheno_ut, swe_azalt, swe_azalt_rev, swe_refrac, swe_refrac_extended, swe_set_lapse_rate 7
Heliacal Phenomena swe_heliacal_ut, swe_heliacal_pheno_ut, swe_vis_limit_mag, swe_heliacal_angle, swe_topo_arcus_visionis 5
Solar Eclipses swe_sol_eclipse_where, swe_sol_eclipse_how, swe_sol_eclipse_when_loc, swe_sol_eclipse_when_glob 4
Lunar Eclipses swe_lun_eclipse_how, swe_lun_eclipse_when, swe_lun_eclipse_when_loc 3
Lunar Occultations swe_lun_occult_where, swe_lun_occult_when_loc, swe_lun_occult_when_glob 3
Nodes & Apsides swe_nod_aps, swe_nod_aps_ut, swe_get_orbital_elements, swe_orbit_max_min_true_distance 4
Planetary Crossings swe_solcross, swe_solcross_ut, swe_mooncross, swe_mooncross_ut, swe_mooncross_node, swe_mooncross_node_ut, swe_helio_cross, swe_helio_cross_ut 8
Rise / Set / Transit swe_rise_trans, swe_rise_trans_true_hor 2
Delta T swe_deltat, swe_deltat_ex, swe_set_tid_acc, swe_get_tid_acc, swe_set_delta_t_userdef 5
Sidereal Time swe_sidtime, swe_sidtime0 2
Setup / Configuration swe_set_ephe_path, swe_set_jpl_file, swe_close, swe_set_topo, swe_version, swe_get_library_path, swe_get_current_file_data 7
Coordinate Transforms swe_cotrans, swe_cotrans_sp 2
Math Utilities swe_degnorm, swe_radnorm, swe_rad_midp, swe_deg_midp, swe_split_deg 5
Astro Models swe_set_astro_models, swe_get_astro_models 2
Gauquelin swe_gauquelin_sector 1
Nutation swe_set_interpolate_nut 1
TOTAL 106

API Reference

Main Class

SwissEphFFI::__construct()

Initialize Swiss Ephemeris FFI

public function __construct(?string $pathToLibrary = null)
Parameters:
  • $pathToLibrary (string|null) β€” Path to libswe.so/swe.dll. Auto-detected if null.

SwissEphFFI::swe_calc_ut()

Calculate planetary position (Universal Time)

public function swe_calc_ut(float $jd, int $ipl, int $iflag, CData $xx, CData $serr): int
Parameters:
  • $jd (float) β€” Julian Day in UT
  • $ipl (int) β€” Planet constant (SE_SUN, SE_MOON, etc.)
  • $iflag (int) β€” Calculation flags (SEFLG_SPEED, etc.)
  • $xx (CData) β€” Output array (double[6])
  • $serr (CData) β€” Error message buffer (char[256])
Returns:int β€” OK or error code

SwissEphFFI::swe_julday()

Calculate Julian Day number

public function swe_julday(int $year, int $month, int $day, float $hour, int $cal): float
Parameters:
  • $year, $month, $day β€” Date
  • $hour (float) β€” Hour (0-24)
  • $cal (int) β€” Calendar (SE_GREG_CAL or SE_JUL_CAL)
Returns:float β€” Julian Day

All Constants

See the Constants section for complete list.

Constants

Planets

Planet constants
Constant Value
SE_SUN 0
SE_MOON 1
SE_MERCURY 2
SE_VENUS 3
SE_MARS 4
SE_JUPITER 5
SE_SATURN 6
SE_URANUS 7
SE_NEPTUNE 8
SE_PLUTO 9
SE_MEAN_NODE 10
SE_TRUE_NODE 11
SE_MEAN_APOG 12
SE_CHIRON 15

Flags

Calculation flags
Constant Description
SEFLG_SPEED Calculate speed
SEFLG_SWIEPH Use Swiss Ephemeris files
SEFLG_MOSEPH Use Moshier algorithm
SEFLG_HELCTR Heliocentric calculation
SEFLG_TRUEPOS True position (not mean)
SEFLG_J2000 J2000 equinox
SEFLG_NONUT No nutation
SEFLG_NOSATEX No satellite ephemeris

Calendar

Calendar constants
Constant Description
SE_GREG_CAL Gregorian calendar
SE_JUL_CAL Julian calendar

Ayanamsa

Ayanamsa modes
Constant Description
SE_SIDM_LAHIRI Lahiri
SE_SIDM_KRISHNAMURTI Krishnamurti
SE_SIDM_RAMAN Raman
SE_SIDM_YUKTESHWAR Yukteshwar
SE_SIDM_SRIBATTAMS Sri Battams

Understanding Julian Day

What is Julian Day?

Julian Day (JD) is a continuous count of days since the beginning of the Julian Period (January 1, 4713 BC). It's the standard way astronomers represent time for calculations.

Converting to/from JD

Date to JD
// January 1, 2000 at noon UT = 2451545.0
$jd = $sweph->swe_julday(2000, 1, 1, 12.0, SwissEphFFI::SE_GREG_CAL);

// Or use a float directly
$jd = 2451545.0;
JD to Date
$year = $month = $day = $hour = null;
$sweph->swe_jdet_to_date(2451545.0, $year, $month, $day, $hour);
echo "$year-$month-$day $hour";

UT vs TT

  • UT (Universal Time) β€” Civil time, based on Earth's rotation
  • TT (Terrestrial Time) β€” Uniform time, based on atomic clocks
  • swe_calc_ut() β€” Takes JD in UT
  • swe_calc() β€” Takes JD in TT (TT = UT + deltaT)

Coordinates

Geographic Coordinates

Most functions requiring location accept:

  • Latitude β€” Degrees, positive = North, negative = South (-90 to +90)
  • Longitude β€” Degrees, positive = East, negative = West (-180 to +180)

Ecliptic Coordinates

  • Longitude β€” Degrees along ecliptic (0-360Β°)
  • Latitude β€” Degrees above/below ecliptic (-90 to +90)

Equatorial Coordinates

  • Right Ascension β€” Degrees (0-360Β°) from vernal equinox
  • Declination β€” Degrees (-90 to +90) from celestial equator

Common Pitfalls

1. Array Allocation

Always allocate C arrays using FFI, not PHP arrays:

Wrong
// WRONG - PHP arrays won't work
$xx = [0, 0, 0, 0, 0, 0];
Correct
// CORRECT - Allocate with FFI
$xx = $sweph->getFFI()->new("double[6]");

2. Float vs Int for Flags

Always use integers for planet and flag constants, not strings:

Correct
// Use constants, not strings
$result = $sweph->swe_calc_ut($jd, SwissEphFFI::SE_SUN, SwissEphFFI::SEFLG_SPEED, $xx, $serr);

3. Julian Day Fraction

The hour in swe_julday() includes the fraction. Noon = 12.0, midnight = 0.0:

Example
// Jan 1, 2000 at midnight UT
$jd = $sweph->swe_julday(2000, 1, 1, 0.0, SwissEphFFI::SE_GREG_CAL);

// Jan 1, 2000 at noon UT  
$jd = $sweph->swe_julday(2000, 1, 1, 12.0, SwissEphFFI::SE_GREG_CAL);

// Jan 1, 2000 at 6:00 AM UT
$jd = $sweph->swe_julday(2000, 1, 1, 6.0, SwissEphFFI::SE_GREG_CAL);

Performance

Tips for Optimal Performance

  1. Reuse the instance β€” Create SwissEphFFI once, reuse for all calculations.
  2. Batch calculations β€” If calculating multiple planets, use swe_calc() in a loop.
  3. Skip unnecessary flags β€” Only use SEFLG_SPEED if you need velocity.
  4. Use Moshier when possible β€” Faster than loading ephemeris files.

Benchmark

Typical performance on modern hardware:

  • Single planet calculation: ~0.1ms
  • Full chart (10 planets): ~1ms
  • With ephemeris files: ~5-10ms (disk I/O)

Comparison with Other Packages

Comparison with other PHP Swiss Ephemeris implementations
Feature swiss-ephemeris-ffi php-sweph swephe-php
Function Coverage 106 (100%) 100 (94%) 2 (2%)
FFI Support Yes No No
Built-in Binary Yes No No
Composer Package Yes No No
Laravel Support Yes No No
Last Updated Active 2021 2019

Laravel Integration

This package includes a Laravel Service Provider and Facade for convenient access.

Configuration

PHP
// config/app.php (for Laravel < 11)
'providers' => [
    SwissEph\Service\SwissEphServiceProvider::class,
],

'aliases' => [
    'SwissEph' => SwissEph\Service\SwissEphFacade::class,
],

Usage

PHP
use SwissEph\Service\SwissEphFacade;

// Calculate Julian Day
$jd = SwissEph::swe_julday(2000, 1, 1, 12.0, SwissEph::SE_GREG_CAL);

// Get planet position
$xx = SwissEph::swe_calc_ut($jd, SwissEph::SE_SUN, SwissEph::SEFLG_SPEED);

Testing

Run the test suite to verify the package is working correctly.

Bash
# Run all tests
composer test

# Check code quality
composer quality

Troubleshooting

FFI Extension Not Loaded

Ensure both lines are present in your php.ini:

php.ini
extension=ffi
ffi.enable=1

Library Not Found

Linux: Add library path to ldconfig:

Bash
echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/swisseph.conf
sudo ldconfig

macOS:

Bash
export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH

Windows:

PowerShell
# Add to PATH
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\php\ext", "Machine")

License

My Package

My package is MIT Licensed. You're free to use it in commercial and personal projects.

Swiss Ephemeris Itself

The underlying Swiss Ephemeris C library has its own licensing:

  • Free Edition (AGPL-3.0) β€” Can be redistributed with attribution
  • Commercial License β€” Available from Astrodienst for proprietary software

For details, see astro.com/swisseph.

Support

Getting Help

  • GitHub Issues: Report bugs
  • GitHub Discussions: Q&A
  • Email: jayeshmepani777@gmail.com

Resources