<?php

/*
   ###########################################################################
   DUAL-DATE NASA/JPL HORIZONS GEOCENTRIC INPUT TEMPLATE - WITH 30-DAY COOKIE.

   All the rules that apply to the Horizons app also apply to this template.
   https://ssd.jpl.nasa.gov/horizons/app.html

   AUTHOR   : Jay Tanner - 2026
   LANGUAGE : PHP v8.2.12
   LICENSE  : Public Domain

   This interface template is for operations that require two date arguments.
   More arguments could be added for future interface expansions.

   It can be used as a base template upon which to build an ephemeris program.

   This version does not require location coordinates, so it is ideal for the
   making of geocentric ephemerides.

   The default settings are for a basic geocentric Mars ephemeris.  You can
   replace this demo/example code with your own custom ephemeris code.

   INTERFACE
   Body ID                    The JPL database ID# or code for the body.
   Quantities List            Numerical codes for the requested quantities.
   Optional Location Label    This can be any text lable used for reference.
   Base Time Scale            UT (Default) or TT
   Time Zone Offset from UT   -Negative = West   / +Positive = East
   Day/Sum Time   Yes|No      No = Standard Time / Yes = Daylight/Summer Time
   Start Date/Time            Ephemeris starting date and time.
   Stop  Date/Time            Ephemeris ending date and time.
   Ephemeris Step Size        Time interval used for the ephemeris table.

   NOTE: The Daylight Saving / Summer Time option will have to be handled by
         extended code within the calling function by adding the extra hour
         internally, if indicated.
   ###########################################################################
*/
   
ob_start(); // Oy!

// ---------------------------------------------------------------
// Define the program cookie name and set it to expire in 30 days.
// This can be changed to any valid name (no spaces).

   
$CookieName 'DUAL-DATE-GEOCENTRIC-INPUT-TEMPLATE';
   
$SetToExpireIn30Days time() + 30*86400;

// ------------------------------------------------------------------
// Define JavaScript message to display in (TextArea1) while working.

   
$_COMPUTING_ "TextArea1.innerHTML='W.O.R.K.I.N.G --- This may take a few seconds.';";

// ---------------------------------
// Define PHP program and HTML info.

   
$_AUTHOR_           'Kilroy of Null Island';
   
$_PROGRAM_VERSION_  'v1.00 - '$at "&#97;&#116;&#32;&#84;&#105;&#109;&#101;&#32;"$LTC "&#85;&#84;&#67;";
   
$_SCRIPT_FILE_PATH_ Filter_Input(INPUT_SERVER'SCRIPT_FILENAME');
   
$_REVISION_DATE_    $_PROGRAM_VERSION_ .'Revised: 'GMDate("Y-F-d-l $at H:i:s   ($LTC"FileMTime($_SCRIPT_FILE_PATH_)).")";
   
$_BROWSER_TAB_TEXT_ "DUAL DATE GEOCENTRIC INPUT TEMPLATE";
   
$_INTERFACE_TITLE_  "<span style='font-size:15pt;'>DUAL DATE GEOCENTRIC INPUT TEMPLATE</span><br><span style='font-size:12pt;'>Built Around The NASA/JPL Horizons API</span><br><span style='font-size:10pt;'>PHP Program by $_AUTHOR_</span>";

/* ----------------------------------------
   Define main TextArea text and background
   colors and HTML table row span. If an
   error is reported, then these colors
   will change internally to red/white.
*/
   
$TxColor 'black';
   
$BgColor 'white';

/* -----------------------------------
   Define number of days in each month
   for use with calendar computations.
*/
   
define('MONTHDAYS''312831303130313130313031');

/* ----------------------------------------
   Define 3-letter month name abbreviations
   for use with calendar computations.
*/
   
define('MONTHS''JanFebMarAprMayJunJulAugSepOctNovDec');


/* ------------------------------------------
   Define 3-letter weekday name abbreviations
   for use with calendar computations.
*/
   
define('DOWs''SunMonTueWedThuFriSat');


// ---------------------------------------------
// Do this only if [SUBMIT] button was clicked.

   
$w Filter_Input(INPUT_POST'SubmitButton');

   if (!IsSet(
$w))
  {

/* ----------------------------------------------------------------------
   If this program is being called externally, rather than being executed
   by clicking the [SUBMIT] button, and an active cookie also exists,
   then restore the previously saved interface settings from it. If
   the user leaves and comes back later, all the interface settings
   will be remembered and restored if the cookie was not deleted.
*/
   
$w Filter_Input(INPUT_COOKIE$CookieName);

   if (IsSet(
$w))
      {
       
$CookieDataString Filter_Input(INPUT_COOKIE$CookieName);
       list
      (
       
$BodyID,
       
$TimeScale,
       
$StartBCAD,
       
$StartYear,
       
$StartMonth,
       
$StartDay,
       
$StartTime,
       
$TimeZone,
       
$StopBCAD,
       
$StopYear,
       
$StopMonth,
       
$StopDay,
       
$StopTime,
       
$DaySumYN,
       
$StepSize,
       
$LocLabel,
       
$Quantities
      
) = Preg_Split("[\|]"$CookieDataString);
      }

   else

/* -----------------------------------------------------------
   If there is no previous cookie with the interface settings,
   then set the initial default interface startup values and
   store them in a new cookie.
*/

 
{
  
$BodyID     '499';
  
$TimeScale  'UT';
  
$StartBCAD  'AD';
  
$StartYear  date('Y');
  
$StartMonth date('M');
  
$StartDay   date('d');
  
$StartTime  '00:00:00';
  
$TimeZone   '+00:00'// -Negative = West
  
$DaySumYN   'No';
  
$StopBCAD   'AD';
  
$StopYear   date('Y');
  
$StopMonth  date('M');
  
$StopDay    date('d');
  
$StopTime   '23:00:01';
  
$StepSize   '1 hour';
  
$LocLabel   '---';
  
$Quantities '1,20,9';

// -------------------------------------------
// Store current interface settings in cookie.

   
$CookieDataString "$BodyID|$TimeScale|$StartBCAD|$StartYear|$StartMonth|$StartDay|$StartTime|$TimeZone|$StopBCAD|$StopYear|$StopMonth|$StopDay|$StopTime|$DaySumYN|$StepSize|$LocLabel|$Quantities";
   
SetCookie ($CookieName$CookieDataString$SetToExpireIn30Days);
  } 
// End of  else {...}

  
// End of  if (!isset(_POST['SubmitButton']))


// ------------------------------------------
// Read values of all interface arguments and
// set any empty arguments to default values.

   
$w Filter_Input(INPUT_POST'SubmitButton');

   if (isset(
$w))
{
   
$BodyID     trim(Filter_Input(INPUT_POST'BodyID'));
                 if (
$BodyID == '') {$BodyID '499';}

   
$TimeScale StrToUpper(trim(Filter_Input(INPUT_POST'TimeScale')));
                if (
$TimeScale == '') {$TimeScale 'UT';}
   
$TimeScale = (substr($TimeScale0,1) == 'T')? 'TT' 'UT';

   
$StartBCAD trim(Filter_Input(INPUT_POST'StartBCAD'));
                if (
$StartBCAD == '') {$StartBCAD 'AD';}

   
$StartYear  trim(Filter_Input(INPUT_POST'StartYear'));
                 if (
$StartYear == '') {$StartYear date('Y');}
   
$StartYear  SPrintF("%04d"$StartYear);

/* -------------------------------------------
   Get START month as a number (1 to 12) or as
   a 3-letter abbreviation ('Jan' to 'Dec').
   NOT case-sensitive.
*/
   
$StartMonth UCFirst(substr(StrToLower(trim(Filter_Input(INPUT_POST'StartMonth'))),0,3));
                 if (
$StartMonth == '') {$StartMonth date('M');}

   if (
Is_Numeric($StartMonth) and $StartMonth == 0) {$StartMonth 'Jan';}

   for (
$ii=0;  $ii 1;  $ii++)
  {
   if (
Is_Numeric($StartMonth))
      {
       
$m IntVal($StartMonth);
            if (
$m or $m 12) {$StartMonth 0; break;}
       
$StartMonth substr(MONTHS3*($m-1), 3);
      }
        
$jj StrPos(MONTHS$StartMonth);
              if (
$jj === FALSE) {$StartMonth 0; break;}
        
$StartMonth substr(MONTHS$jj3);
  }

   
$StartDay  trim(Filter_Input(INPUT_POST'StartDay'));
                if (
$StartDay == '') {$StartDay IntVal(date('d'));}
   
$StartDay  SPrintF("%02d"$StartDay);

   
$StartTime trim(Filter_Input(INPUT_POST'StartTime'));
                if (
$StartTime == '') {$StartTime date('H:i:s');}
   
$StartTime = (!Is_Numeric(substr($StartTime,0,1)))? '00:00:00'$StartTime;
                 
$w HMS_to_Hours($StartTime);
   
$StartTime Hours_to_HMS($w,0);


   
$TimeZone  trim(Filter_Input(INPUT_POST'TimeZone'));
                if (
$TimeZone == '') {$TimeZone '+00:00';}
   
$TZHours   = @HMS_to_Hours($TimeZone); // suppress a harmless warning.
   
$TimeZone  Hours_to_HMS($TZHours);
   
$TZSign    = ($TZHours >= 0)? '+':'';
   
$TimeZone  substr($TZSign.$TimeZone,0,6);


   
$DaySumYN  trim(Filter_Input(INPUT_POST'DaySumYN'));
   
$DaySumYN  = (substr(StrToUpper($DaySumYN),0,1) == 'Y')? 'Yes':'No';

   
$StopBCAD  trim(Filter_Input(INPUT_POST'StopBCAD'));
                if (
$StopBCAD == '') {$StopBCAD 'AD';}

   
$StopYear  trim(Filter_Input(INPUT_POST'StopYear'));
                if (
$StopYear == '') {$StopYear date('Y');}
   
$StopYear  SPrintF("%04d"$StopYear);

/* ------------------------------------------
   Get STOP month as a number (1 to 12) or as
   a 3-letter abbreviation ('Jan' to 'Dec').
*/
   
$StopMonth UCFirst(substr(StrToLower(trim(Filter_Input(INPUT_POST'StopMonth'))),0,3));
                if (
$StopMonth == '') {$StopMonth date('M');}
   if (
Is_Numeric($StopMonth) and $StopMonth == 0) {$StopMonth 'Dec';}

   for (
$ii=0;  $ii 1;  $ii++)
  {
   if (
Is_Numeric($StopMonth))
      {
       
$m IntVal($StopMonth);
            if (
$m or $m 12) {$StopMonth 0; break;}
       
$StopMonth substr(MONTHS3*($m-1), 3);
      }
        
$jj StrPos(MONTHS$StopMonth);
              if (
$jj === FALSE) {$StopMonth 0; break;}
        
$StopMonth substr(MONTHS$jj3);
  }

   
$StopDay   trim(Filter_Input(INPUT_POST'StopDay'));
                if (
$StopDay == '') {$StopDay IntVal(date('d'));}
   
$StopDay   SPrintF("%02d"$StopDay);


   
$StopTime  trim(Filter_Input(INPUT_POST'StopTime'));
                if (
$StopTime == '') {$StopTime date('H:i:s');}
   
$StopTime  = (!Is_Numeric(substr($StopTime,0,1)))? '00:00:00'$StopTime;
                
$w HMS_to_Hours($StopTime);
   
$StopTime  Hours_to_HMS(HMS_to_Hours($w), 0);


   
$StepSize  trim(Filter_Input(INPUT_POST'StepSize'));
                 if (
$StepSize == '') {$StepSize '1 hour';}
   
$StepSize .= (Is_Numeric($StepSize))? ' hour' '';

   
$LocLabel  =  trim(Filter_Input(INPUT_POST'LocLabel'));
                 if (
$LocLabel == '') {$LocLabel '---';}

   
$Quantities trim(Filter_Input(INPUT_POST'Quantities'));
                 if (
$Quantities == '') {$Quantities '1,20,9';}

// -------------------------------------
// Store interface argument in a cookie.

   
$CookieDataString "$BodyID|$TimeScale|$StartBCAD|$StartYear|$StartMonth|$StartDay|$StartTime|$TimeZone|$StopBCAD|$StopYear|$StopMonth|$StopDay|$StopTime|$DaySumYN|$StepSize|$LocLabel|$Quantities";
   
SetCookie ($CookieName$CookieDataString$SetToExpireIn30Days);
}


/* -----------------------------------------------------------
   Put code here to optionally  check individual arguments for
   validity in reverse input order.  If errors found, then set
   error flag and message values accordingly.

   NOTE: Horizons will catch some errors, such as invalid date
   errors.
*/
   
$ErrorReported FALSE;
   
$ErrMssg '';


// -----------------------------
// Set initial uniform width for
// tables alignment in pixels.

   
$TableWidth '780';


// -------------------------------------------
// If error was reported (TRUE), then display
// the error message on a red background.

   
if ($ErrorReported)
  {
   
$TxColor 'white';
   
$BgColor '#CC0000';
   
$TextArea2Text '';

   
$TextArea1Text =
"=== ERROR ===

$ErrMssg";
  }

else


  {
// *********************************************************
// BEGIN MAIN COMPUTATIONS HERE IF NO ERRORS DETECTED ABOVE.
// *********************************************************


/* ------------------------------------------------------
   Construct full date and time strings for Horizons API.
*/
   
$StartDateTime "$StartBCAD $StartYear-$StartMonth-$StartDay  $StartTime $TimeScale";
   
$StopDateTime  "$StopBCAD $StopYear-$StopMonth-$StopDay  $StopTime";


/* -------------------
   Call main function.
   Replace with your own custom function.
*/
   
$EphemerisTable Geocentric_Ephem ($BodyID$StartDateTime$StopDateTime,
                                       
$TimeZone$StepSize$Quantities);

// ********************************************
// DROP THROUGH HERE AFTER COMPUTATIONS ABOVE
// TO PARSE THE RETURNED EPHEMERIS TABULATIONS.
// ********************************************

   
$TextArea1Text =
"#############################################################################
MAIN OUTPUT TEXT AREA 1

The results of computations can be printed in this area and/or the optional
second text area below as well.

For JPL Database Body ID =  
$BodyID

Ephemeris Time Scale     =  
$TimeScale
Local Time Zone Offset   =  UT
$TimeZone (Ignored if using the TT scale.)
Daylight / Summer Time   =  
$DaySumYN

Optional Location Label  =  
$LocLabel

START Era / Date / Time  =  
$StartBCAD $StartYear-$StartMonth-$StartDay  $StartTime
STOP  Era / Date / Time  =  
$StopBCAD $StopYear-$StopMonth-$StopDay  $StopTime
Ephemeris Step Size      =  
$StepSize

******************************************************************************
The basic concept is to design a function to perform a NASA/JPL Horizons API
computation and create a custom interface to call and make use of it.
******************************************************************************

EPHEMERIS OUTPUT

$EphemerisTable
"
;
  }


// ****************************
// Define TextArea2 text block.

   
$TextArea2Text =
"TEXT AREA 2 = OPTIONAL SECOND TEXT AREA

For optional program info or other use or it can be removed entirely or more
text areas could be added as needed.    This text area is independent of the
text area above.
"
;



/* --------------------------------------------------------------------------
   Determine number of text columns and rows to use in the output text areas.
   These values vary randomly according to the text block width and length.
   The idea is to eliminate the need for scroll-bars within the text areas
   or worry as much about the variable dimensions of a text display area.
*/

// --------------------------------------------
// Text Area 1 - Default = At least 80 columns.

   
$Text1Cols Max(Array_Map('StrLen'PReg_Split("[\n]"trim($TextArea1Text))));
   if (
$Text1Cols 80) {$Text1Cols 80;}  // Default
   
$Text1Rows Substr_Count($TextArea1Text"\n");

// --------------------------------------------
// Text Area 2 - Default = At least 80 columns.

   
$Text2Cols Max(Array_Map('StrLen'PReg_Split("[\n]"trim($TextArea2Text))));
   if (
$Text2Cols 80) {$Text2Cols 80;} // Default
   
$Text2Rows Substr_Count($TextArea2Text"\n");



// ******************************************
// GENERATE CLIENT WEB PAGE TO DISPLAY OUTPUT

   
print <<< _HTML

<!DOCTYPE HTML>
<HTML>

<head>
<title>
$_BROWSER_TAB_TEXT_</title>

<meta name='viewport'           content='width=device-width, initial-scale=0.8'>
<meta http-equiv='content-type' content='text/html; chrset=UTF-8'>
<meta http-equiv='pragma'       content='no-cache'>
<meta http-equiv='expires'      content='-1'>
<meta name='description'        content='DUAL DATE INPUT TEMPLATE'>
<meta name='keywords'           content='NeoProgrammics  / PHP Science Labs'>
<meta name='author'             content='Jay Tanner - https://www.NeoProgrammics.com'>
<meta name='robots'             content='index,follow'>
<meta name='googlebot'          content='index,follow'>

<style>

 BODY {color:white; background:black; font-family:Verdana; font-size:12pt; line-height:125%;}

 TABLE
{font-size:13pt; border: 1px solid black;}


 TD
{
 color:black; background:white; line-height:150%; font-size:10pt;
 padding:6px; text-align:center;
}


 UL
{font-family:Verdana; font-size:12pt; line-height:150%; text-align:justify;}


 PRE
{
 background:white; color:black; font-family:monospace; font-size:12.5pt;
 font-weight:bold; text-align:left; line-height:125%; padding:6px;
 border:2px solid black; border-radius:8px;
 page-break-before:page;
}


 DIV
{
 background:white; color:black; font-family:Verdana; font-size:11pt;
 font-weight:normal; line-height:125%; padding:6px;
}


 TEXTAREA
{
 background:white; color:black; font-family:monospace; font-size:12pt;
 font-weight:bold; padding:4pt; white-space:pre; border-radius:8px;
 line-height:125%;
}


 INPUT[type='text']::-ms-clear {width:0; height:0;}

 INPUT[type='text']
{
 font-family:monospace; color:black; background:white; font-size:12pt;
 font-weight:bold; text-align:center; box-shadow:2px 2px 3px #666666;
 border:2px solid black; border-radius:4px;
}
 INPUT[type='text']:focus
{
 font-family:monospace; background:white; box-shadow:2px 2px 3px #666666;
 font-size:12pt; border:2px solid blue; text-align:center; font-weight:bold;
 border-radius:4px;
}



 INPUT[type='submit']
{
 background:black; color:cyan; font-family:Verdana; font-size:10pt;
 font-weight:bold; border-radius:4px; border:4px solid #777777;
 padding:3pt;
}
 INPUT[type='submit']:hover
{
 background:black; color:white; font-family:Verdana; font-size:10pt;
 font-weight:bold; border-radius:4px; border:4px solid red;
 padding:3pt;
}





// Link states MUST be set in the following order:
// :link, :visited, :hover, :active

 A:link
{
 font-size:10pt; background:transparent; color:#8080FF; border-radius:4px;
 font-family:Verdana; font-weight:bold; text-decoration:none;
 line-height:175%; padding:3px; border:1px solid transparent;
}
 A:visited
{
 font-size:10pt; background:transparent; color:DarkCyan; border-radius:4px;
}
 A:hover
{
 font-size:10pt; background:yellow; color:black; border:1px solid black;
 box-shadow:1px 1px 3px #222222; border-radius:4px;
}
 A:active
{
 font-size:10pt; background:yellow; color:black; border-radius:4px;
}


 HR {background:red; height:4px; border:0px;}


[title-text]:hover:after
{
 opacity:1.0;
 transition:all 1.0s ease 1.0s;
 text-align:left;
 visibility:visible;
}

[title-text]:after
{
 opacity:1.0;
 content:attr(title-text);
 text-align:left;
 left:50%;
 background-color:yellow;
 color:black;
 font-size:10pt;
 position:absolute;
 padding:1px 5px 2px 5px;
 white-space:pre;
 border:1px solid red;
 z-index:1;
 visibility:hidden;
}

[title-text] {position: relative;}


::selection{background-color:yellow !important; color:black !important;}
::-moz-selection{background-color:yellow !important; color:black !important;}
</style>

</head>

<body>

<!-- Define container form --->
<form name="form1" method="post" action="">

<!-- Define main page title/header. --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">


<tr><td colspan="99" style="color:white; background-color:#000066; border:2px solid white; border-radius:8px 8px 0px 0px;">
$_INTERFACE_TITLE_</td></tr>
</table>

<!-- Define input (BodyID) text box  --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td style='line-height:175%; background:LightCyan;' width='25%'
title='&nbsp;MAJOR BODY  IDs&nbsp;
10   = Sun
199 = Mercury
299 = Venus
301 = Moon (Luna)&nbsp;
399 = Earth
499 = Mars
599 = Jupiter
699 = Saturn
799 = Uranus
899 = Neptune
999 = Pluto

&nbsp;ASTEROID  IDs
1;    = Ceres;
2;    = Pallas;
3;    = Juno;
4;    = Vesta;
5;    = Astraea;
6;    = Hebe;
7;    = Iris;
8;    = Flora;
9;    = Metis;
10;  = Hygiea;

301  = Voyager 1
-32  = Voyager 2
'>NASA/JPL&nbsp;Database&nbsp;Body&nbsp;ID<br>
<input name="BodyID"  type="text" value="
$BodyID" size="65" maxlength="64"></td>
</tr>

<tr>
<td style='line-height:175%; background:LightYellow;' width='25%'
title=''>Quantities&nbsp;List<br>
<input name="Quantities"  type="text" value="
$Quantities" size="65" maxlength="64"></td>
</tr>

<tr>
<td style='line-height:175%; background:#CCFFCC;' width='25%'
title=''>Optional&nbsp;Location&nbsp;Label<br>
<input name="LocLabel"  type="text" value="
$LocLabel" size="65" maxlength="64"></td>
</tr>
</table>

<!-- Define input (TimeScale) text box  --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td style='line-height:175%; background:LightYellow;' width='25%' title=' UT = Universal Time (Default)\n TT = Terrestrial (Dynamical) Time '>Base&nbsp;Time&nbsp;Scale<br><input name="TimeScale"  type="text" value="
$TimeScale" size="3" maxlength="2"></td>

<td title=' START Date/Time must be EARLIER than STOP Date/Time '><b>START</b>&nbsp;Date&nbsp;and&nbsp;Time<br><input name="StartBCAD"  type="text" value="
$StartBCAD" size="3" maxlength="2">
<input name="StartYear"  type="text" value="
$StartYear" size="6" maxlength="5"><input name="StartMonth"  type="text" value="$StartMonth" size="4" maxlength="3"><input name="StartDay"  type="text" value="$StartDay" size="3" maxlength="2">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input name="StartTime"  type="text" value="
$StartTime" size="9" maxlength="8"></td>

<td style='line-height:175%; background:LightYellow;' width='25%' title=' Local Time Zone Offset From UT. \n &minus;Negative = W&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &plus;Positive = E '>Time Zone<br><input name="TimeZone"  type="text" value="
$TimeZone" size="7" maxlength="6"></td>
</tr>

<tr>
<td style='line-height:175%; background:LightYellow;' width='25%' title=' N = No = Standard Time (Default) \n Y = Yes = Daylight / Summer Time '>Daylight&nbsp;/&nbsp;Summer&nbsp;Time<br><input name="DaySumYN"  type="text" value="
$DaySumYN" size="4" maxlength="3">

<td title=' STOP Date/Time must be LATER than START Date/Time '><b>STOP</b>&nbsp;Date&nbsp;and&nbsp;Time<br><input name="StopBCAD"  type="text" value="
$StopBCAD" size="3" maxlength="2">
<input name="StopYear"  type="text" value="
$StopYear" size="6" maxlength="5"><input name="StopMonth"  type="text" value="$StopMonth" size="4" maxlength="3"><input name="StopDay"  type="text" value="$StopDay" size="3" maxlength="2">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input name="StopTime"  type="text" value="
$StopTime" size="9" maxlength="8"></td>

<td style='line-height:175%; background:LightYellow;'>Step&nbsp;Size<br><input name="StepSize"  type="text" value="
$StepSize" size="15" maxlength="14"></td>
</tr>
</table>


<!-- Top yellow source code view link. --->
<br>
<table width="
$TableWidth" align="center" cellspacing="1" cellpadding="3">
<tr>
<td colspan="1" style='font-size:10pt; color:black; background:black;
                       text-align:center;' title=' Tries to Open in a New Tab. '>
<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;
            border-radius:4px; font-weight:normal;'>
&nbsp;View/Copy Source Code&nbsp;</a></b>
</td>
</tr>
</table>




<!-- Define [SUBMIT] button --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr><td colspan="99" style="background-color:black;"><input type="submit" name="SubmitButton" value=" S U B M I T " OnClick="
$_COMPUTING_"
></td></tr>
</table>


<!-- Define TextArea1 --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="text-align:center; color:GreenYellow; background-color:black;">Double-Click Within Text Area to Select ALL Text<br>
<textarea ID="TextArea1" name="TextArea1" style="color:
$TxColor; background:$BgColor; padding:6px; border:2px solid white;" cols="$Text1Cols" rows="$Text1Rows" ReadOnly OnDblClick="this.select();" OnMouseUp="return true;">
$TextArea1Text
</textarea>
</td>
</tr>
</table>


<!-- Define TextArea2 --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="text-align:center; color:GreenYellow; background:black;">Double-Click Within Text Area to Select ALL Text<br>
<textarea ID="TextArea2" name="TextArea2" style="color:black; background:white; padding:6px;" cols="
$Text2Cols" rows="$Text2Rows" ReadOnly OnDblClick="this.select();" OnMouseUp="return true;">
$TextArea2Text
</textarea>
</tr>
</table>


<!-- Define page footer --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="color:GreenYellow; background:black;">PHP Program by 
$_AUTHOR_<br><span style="color:silver; background:black;">$_REVISION_DATE_</span></td>
</tr>
</table>

</form>
<!-- End of container form --->


<!-- Extra bottom scroll space --->
<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>
</HTML>



_HTML;




/*
   ###########################################################################
   This function returns the decimal hours equivalent to the given HMS string.

   Generic. No special error checking is done.

   NO DEPENDENCIES
   ###########################################################################
*/

   
function HMS_to_Hours ($HMSString$Decimals=16)
{
   
$HHmmss   trim($HMSString);
   
$decimals trim($Decimals);

/* ------------------------------------------------
   Account for and preserve any numerical +/- sign.
   Internal work will use absolute values and any
   numerical sign will be reattached the output.
*/
   
$NumSign substr($HHmmss,0,1);
   if (
$NumSign == '-')
      {
$HHmmss substr($HHmmss,1,StrLen($HHmmss));}
   else
      {
       if (
$NumSign == '+')
          {
$HHmmss substr($HHmmss,1,StrLen($HHmmss));}

       
$NumSign '+';
      }

// ------------------------------------------------------------------
// Replace any colons : with blank spaces and remove any white space.

   
$HHmmss PReg_Replace("/\s+/"" "Str_Replace(":"" "$HHmmss));

// ----------------------------------------
// Count the HMS time elements from 1 to 3.

   
$n  Substr_Count($HHmmss' ');

   
$hh $mm $ss 0;

/* ----------------------------------------------------------------------
   Collect all given time element values.  They can be integer or decimal
   values. Only counts up to three HMS values and any values beyond those
   are simply ignored.
*/
   
for ($i=0;   $i 1;   $i++)
  {
   if (
$n == 1){list($hh)         = PReg_Split("[ ]"$HHmmss);}
   if (
$n == 2){list($hh,$mm)     = PReg_Split("[ ]"$HHmmss);}
   if (
$n == 3){list($hh,$mm,$ss) = PReg_Split("[ ]"$HHmmss);}
  }

// ------------------------------------------------------------------------
// Compute HMS equivalent in decimal hours to the given number of decimals.

   
return $NumSign.(round((3600*$hh 60*$mm $ss)/3600,$decimals));

// End of  HMS_to_Hours(...)



/*
   ###########################################################################
   This function returns an HMS string equivalent to an hours argument rounded
   to the specified number of decimals.

   Generic. No special error checking is done.

   NO DEPENDENCIES
   ###########################################################################
*/

   
function Hours_to_HMS ($Hours$Decimals=0)
{
   
$hours trim($Hours);  $NumSign = ($hours 0)? '-':'';
   
$hours Str_Replace('+'''Str_Replace('-'''$hours));

// ---------------------
// Set working decimals.

   
$Q 32;
   
$decimals floor(abs(trim($Decimals)));
   
$decimals = ($decimals $Q)? $Q $decimals;
   
$decimals = ($decimals <  0)?  $decimals;

// ------------------------------------
// Compute hours,minutes and seconds to
// the specified number of decimals.

   
$hh  bcAdd($hours'0');
   
$min bcMul('60'bcSub($hours$hh$Q),$Q);
   
$mm  bcAdd($min'0');
   
$sec bcMul('60'bcSub($min$mm$Q),$Q);
   
$ss  SPrintF("%1.$decimals"."f"$sec);
          if (
$ss 10){$ss "0$ss";}

// -------------------------------------------
// Try to account for that blasted 60s glitch.

   
if ($ss == 60) {$mm += 1;  $ss 0;}
   if (
$mm == 60) {$hh += 1;  $mm 0;}

// ------------------------------------------
// Construct and return time elements string.

   
$hh SPrintF("%02d"$hh);
   
$mm SPrintF("%02d"$mm);
   
$ss SPrintf("%1.$decimals"."f"$ss);
         if (
$ss 10){$ss "0$ss";}

   return 
"$NumSign$hh:$mm:$ss";

// End of  Hours_to_HMS (...)







/*
   THIS IS THE MAIN FUNCTION AROUND WHICH THE PROGRAM IS BUILT.
   THIS DEMO CAN BE REPLACED WITH YOUR OWN CUSTOM FUNCTION.
*/

   
function Geocentric_Ephem ($BodyID$StartTime$StopTime$TimeZone$StepSize$Quantities)
{
   
$Command URLEncode($BodyID);

   
$From_Horizons_API =
   
"https://ssd.jpl.nasa.gov/api/horizons.api?format=text" .
   
"&MAKE_EPHEM='YES'"                                     .
   
"&EPHEM_TYPE='OBSERVER'"                                .
   
"&CENTER='500@399'"                                     .
   
"&COMMAND='$Command'"                                   .
   
"&OBJ_DATA='YES'"                                       .
   
"&TIME_ZONE='$TimeZone'"                                .
   
"&START_TIME='$StartTime'"                              .
   
"&STOP_TIME='$StopTime'"                                .
   
"&STEP_SIZE='$StepSize'"                                .
   
"&SUPPRESS_RANGE_RATE='YES'"                            .
   
"&CSV_FORMAT='YES'"                                     .
   
"&QUANTITIES='$Quantities'"                             ;

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

}







// END OF PROGRAM

?>