<?php

/*
   ##########################################################################
   This program demonstrates a function to generate a table of geocentric
   lunar phases at any given interval for any given time zone.

   THIS VERSION IS REVISED FOR THE CURRENT MONTH UTC ONLY AND TO DISPLAY THE
   GEOCENTRIC PHASE ANGLES AT 00:00 UT ON EACH DATE.

   AUTHOR   : Jay Tanner - Built around the NASA/JPL Horizons API
   LANGUAGE : PHP v8.2.12
   LICENSE  : Public Domain

   ##########################################################################
*/



   
$cYear date('Y');

// -------------------------------------------------
// Define parameters for function test/demo example.

   
$TimeZone '+00:00'// Time zone offset from UT (+Positive = East)
   
$DaySumYN 'No';     // 'Yes|No'
   
$HeaderYN 'Yes';    // 'Yes|No'

// --------------------------------------------------
// Set up for current month at 00:00 UT on each date.

   
$Y GMDate('Y');
   
$m GMDate('m');
   
$M GMDate('M');
   
$mDays Cal_Days_In_Month (CAL_GREGORIAN$m$Y);

   
$StartDateTimeStr GMDate("Y-M-01  00:00:00");
   
$StopDateTimeStr  GMDate("$Y-") . $M "-$mDays  00:00:00";
   
$StepSize         '1 day';


// ------------------------------------------------
// Compute Time Zone equivalent as fraction of day.

   
list($TZHH$TZmm) = PReg_Split("[\:]"$TimeZone);
   
$TZFracDay = (trim($TZHH) . '.' StrRChr(trim($TZmm)/60'.'))/24;
   
$TZFracDay SPrintF("%+1.10f"$TZFracDay);


// ------------------------------------------------------
// Define standard/Daylight Saving|Summer Time mode text.

   
$DaySumModeStr = (StrToUpper(substr(trim($DaySumYN),0,1)) == 'Y')?
                    
'Day/Summ' 'Standard';


/* --------------------------------------------------------------------
   Compute simple geocentric ecliptical lunar phase angle table for the
   current month at 00:00:00 UTC on each date.
*/

   
$PhaseTable Lunar_Phase_Table ($StartDateTimeStr,$StopDateTimeStr,
                                    
$StepSize,$TimeZone,$DaySumYN,$HeaderYN);



// -----------------------------------------------
// Generate client HTML page to display the table.

print <<< END_OF_HTML_WEB_PAGE

<!DOCTYPE HTML>
<body style='color:black; background:white; font-family:Verdana;'>

<!-- Top yellow source code view link. --->
<br>
<table width="800" align="center" cellspacing="1" cellpadding="3">
<tr>
<td colspan="1" style="font-size:10pt; color:transparent; background:transparent;
                       text-align:left;">
<b><a href='View-Source-Code.php' target='_blank'
style='font-family:Verdana; color:black; background:yellow;
       text-decoration:none; border:1px solid black; padding:4px;'>
       &nbsp;View PHP Source Code&nbsp;</a></b>
</td></tr>

<tr><td>
<pre style='font-size:11pt; font-weight:bold; padding:8px; text-align:left;'>
******************************************************************************
SIMPLE LUNAR PHASE ANGLE TABLE FUNCTION DEMO
Built around the NASA/JPL Horizons API

PHP Program by Jay Tanner - 
$cYear

This program is based on a custom function to generate a simple lunar phase
table over a given range from a single date to multiple dates spanning any
general interval at any given time step size.

This demo program generates a table of the simple geocentric lunar phase
angles for each date of the current month at 00:00:00 UTC on each date.

It is called the 'simple' lunar phase because it is geocentric and based on
the simple difference between  the ecliptical longitudes of the moon and sun
at the same moment and  excludes the  tiny effects of librations, but still
results in a good enough lunar phase approximation  for most practical pur-
poses and general small-scale graphical simulations.

-----------------
CALLING TEMPLATE:

PhaseTable = Lunar_Phase_Table (StartDateTimeStr, StopDateTimeStr, StepSize,
                                TimeZone, DaySumYN, HeaderYN)


*********************************************************
Geocentric Lunar Phase Table

Time Zone       = UT
$TimeZone       (dJDate = $TZFracDay)
Day/Summ Time   = 
$DaySumYN
Table Header    = 
$HeaderYN

START Date/Time = 
$StartDateTimeStr   ($DaySumModeStr Time)
STOP  Date/Time = 
$StopDateTimeStr
Step Size       = 
$StepSize

$PhaseTable

*********************************************************
Table to help visualize the lunar phase angles:

PhaseAng       Description
--------    -----------------
    0&deg;      New Moon
   45       Waxing Crescent
   90       First Quarter
  135       Waxing Gibbous
  180       Full Moon
  225       Waning Gibbous
  270       Last Quarter
  315       Waning Crescent
 360/0      New Moon

******************************************************************************
To compute the simple  geocentric lunar phase angle (0 to 360 deg)  based on
the ecliptical longitudes of the moon and sun at the same moment also in the
the range from 0 to 360 degrees:

Let:
PhaseAng = Simple lunar phase angle (0 to 360 deg) based on the
           difference between the ecliptical longitudes.

Given:
Lm = Geocentric ecliptical longitude of the moon (0 to 360 deg).
Ls = Geocentric ecliptical longitude of the sun  (0 to 360 deg).

Then, the simple phase angle may be found
by one of the following simple algorithms:

----------------------------------------
w = 360 - Lm + Ls

if (w > 360) then w = w - 360

PhaseAng = 360 - w

----------------------------------------
Or, the alternate equivalent:

w = 360 - Lm + Ls

PhaseAng = 360 &minus; (w &minus;= (w &gt; 360)? 360:0)

******************************************************************************
</pre>

</td></tr>
</table>


<br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br>

</body>

END_OF_HTML_WEB_PAGE;




/*
   ###########################################################################
   This function generates a table of geocentric lunar phases starting on any
   given date and spanning a given interval at regular time steps.

   It can also be used for a single computation for any given date and time.

   It takes into account the Time Zone and Daylight Saving/Summer Time.
   The table text header is optional.

   DEPENDENCIES:  The NASA/JPL Horizons API

   ###########################################################################
*/

   
function Lunar_Phase_Table ($StartDateTime$StopDateTime$StepSize,
                               
$TimeZone='+00:00'$DaySumYN='No',
                               
$HeaderYN='No')
{
   
$StartDateTime trim($StartDateTime);
   
$StopDateTime  trim($StopDateTime);

   
$HeaderYN substr(StrToUpper(trim($HeaderYN)),0,1);

/* -----------------------------------------------------------
   Adjust for Daylight/Summer Time, if indicated. This assumes
   that the Time Zone string is given in the standard +-HH:mm
   format or an error may occur.
*/
   
$DaySumYN  substr(StrToUpper(trim($DaySumYN)),0,1);
   
$DSSTAdj = ($DaySumYN == 'N')? 0:1;

   list(
$TZHH$TZmm) = PReg_Split("[\:]"$TimeZone);
   
$TZSign substr($TZHH,0,1);
   
$TZHours = (($TZSign == '-')? -1:1)*(abs($TZHH) + $TZmm/60) + $DSSTAdj;
   
$i StrPos($TZHours'.');  if ($i == FALSE) {$TZHours .= '.00';}
   
$i StrPos($TZHours'.');
   
$TZHH $TZSign.SPrintF("%02d"abs(substr($TZHours,0,$i)));
   
$TimeZone URLEncode("$TZHH:$TZmm");

// **********************************************************
// MOON - GEOCENTRIC ECLIPTICAL LONGITUDE AND LATITUDE (GELL)

   
$From_Horizons_API =
   
"https://ssd.jpl.nasa.gov/api/horizons.api?format=text" .
   
"&COMMAND='301'"                  .
   
"&OBJ_DATA='NO'"                  .
   
"&MAKE_EPHEM='YES'"               .
   
"&EPHEM_TYPE='OBSERVER'"          .
   
"&CAL_FORMAT='BOTH'"              .
   
"&CAL_TYPE='MIXED'"               .
   
"&REF_SYSTEM='ICRF'"              .
   
"&APPARENT='AIRLESS'"             .
   
"&RANGE_UNITS='AU'"               .
   
"&CENTER='500@399'"               .
   
"&TIME_DIGITS='SECONDS'"          .
   
"&TIME_ZONE='$TimeZone'"          .
   
"&START_TIME='$StartDateTime UT'" .
   
"&STOP_TIME='$StopDateTime'"      .
   
"&STEP_SIZE='$StepSize'"          .
   
"&EXTRA_PREC='YES'"               .
   
"&CSV_FORMAT='YES'"               .
   
"&QUANTITIES='31,29"              ;

// -----------------------------------------------------------------
// Get the geocentric ecliptical longitude and latitude of the moon.

   
$MoonGELL Str_Replace(",\n"" \n"trim(File_Get_Contents($From_Horizons_API)));

/* ----------------------------------------------------
   Set pointers to start and end of ephemeris table and
   extract ONLY the required ephemeris CSV data lines
   from between the Start/End pointers.
*/
   
$i StrPos($MoonGELL'$$SOE');
   
$j StrPos($MoonGELL'$$EOE');

   
$MoonTable trim(substr($MoonGELL$i+5$j-$i-5));
   
$MoonTable = (substr($MoonTable,0,1) <> 'b')?
                 
$MoonTable$MoonTable;





// *********************************************************
// SUN - GEOCENTRIC ECLIPTICAL LONGITUDE AND LATITUDE (GELL)

   
$From_Horizons_API =
   
"https://ssd.jpl.nasa.gov/api/horizons.api?format=text" .
   
"&COMMAND='10'"                   .
   
"&OBJ_DATA='NO'"                  .
   
"&MAKE_EPHEM='YES'"               .
   
"&EPHEM_TYPE='OBSERVER'"          .
   
"&CAL_FORMAT='BOTH'"              .
   
"&CAL_TYPE='MIXED'"               .
   
"&REF_SYSTEM='ICRF'"              .
   
"&APPARENT='AIRLESS'"             .
   
"&RANGE_UNITS='AU'"               .
   
"&CENTER='500@399'"               .
   
"&TIME_DIGITS='SECONDS'"          .
   
"&TIME_ZONE='$TimeZone'"          .
   
"&START_TIME='$StartDateTime UT'" .
   
"&STOP_TIME='$StopDateTime'"      .
   
"&STEP_SIZE='$StepSize'"          .
   
"&EXTRA_PREC='YES'"               .
   
"&CSV_FORMAT='YES'"               .
   
"&QUANTITIES='31,29"              ;

// ----------------------------------------------------------------
// Get the geocentric ecliptical longitude and latitude of the sun.

   
$SunGELL Str_Replace(",\n"" \n"trim(File_Get_Contents($From_Horizons_API)));

/* ----------------------------------------------------
   Set pointers to start and end of ephemeris table and
   extract ONLY the required ephemeris CSV data lines
   from between the Start/End pointers.
*/
   
$i StrPos($SunGELL'$$SOE');
   
$j StrPos($SunGELL'$$EOE');

   
$SunTable trim(substr($SunGELL$i+5$j-$i-5));
   
$SunTable = (substr($SunTable,0,1) <> 'b')? $SunTable$SunTable;

/* ------------------------------------------
   PARSE THE TABLES AND CONSTRUCT A SINGLE
   CUSTOMIZED GEOCENTRIC LUNAR PHASE TABLE.

=========================================================
  Loc_Date    Loc_Time  Cnst   Julian_Date_UT   Phase_Ang
============  ========  ==== =================  =========
 2025-Feb-01  00:00:00  Aqr  2460707.708333333   35.36319
 ...

*/

   
$LunarPhaseAngleTable '';

/* --------------------------------------------
   Store lunar and solar ecliptical coordinates
   in their respective work arrays.
*/
   
$MoonLonArray PReg_Split("[\n]"$MoonTable);
   
$MoonLonCount count($MoonLonArray);

   
$SunLonArray PReg_Split("[\n]"$SunTable);
   
$SunLonCount count($SunLonArray);


/* -----------------------------------
   Fatal error if unequal array count.
*/
   
if ($MoonLonCount <> $SunLonCount)
      {exit (
"FATAL ERROR: Unequal array count.");}

/* -------------------------------------------
   Construct geocentric ecliptical coordinates
   and lunar phase table.
*/
   
for ($i=0;   $i $MoonLonCount;   $i++)
       {
        
$CurrMoonLine $MoonLonArray[$i];
        
$CurrSunLine  $SunLonArray[$i];

        list (
$DateTimeStr,$JDate,$w,$w,$CurrMoonLon,$w$MoonCnst) = PReg_Split("[,]"$CurrMoonLine);
        list (
$w,$JDate,$w,$w,$CurrSunLon) = PReg_Split("[,]"$CurrSunLine);

        
$DateTimeStr Str_Replace(' ''  'trim($DateTimeStr));
        
$DateTimeStr = (substr($DateTimeStr,0,1) <> 'b')? $DateTimeStr$DateTimeStr;

//      ----------------------------------------------------------
//      Get IAU symbol for constellation in which moon is located.

        
$MoonCnst trim($MoonCnst);

//      -------------------------------
//      Get longitudes of moon and sun.

        
$Lm trim($CurrMoonLon);
        
$Ls trim($CurrSunLon);

//      -------------------------------
//      Compute the simple phase angle.

        
$w 360 $Lm $Ls;

        
$PhaseAng SPrintF("% 9.5f"360 - ($w -= ($w 360)? 360:0));

//      -----------------------------------------
//      Construct current output table text line.

        
$LunarPhaseAngleTable .= "$DateTimeStr  $MoonCnst $JDate  $PhaseAng\n";
       }
        
$LunarPhaseAngleTable RTrim($LunarPhaseAngleTable);

// --------------------------------------------
// Return table with header text, if indicated.

   
if ($HeaderYN == 'Y')
  {
   return
"=========================================================
  Loc_Date    Loc_Time  Cnst   Julian_Date_UT   Phase_Ang
============  ========  ==== =================  =========
$LunarPhaseAngleTable";
  }

// --------------------------------------------
// Otherwise, return table without header test.

   
return $LunarPhaseAngleTable;

// End of  Lunar_Phase_Table (...)






?>