Steve White ae9ece5266 *** Initial Commit of Files for APRS.TO Backend Administration Panel ***
This code is non-functional at this point.
2025-02-02 15:53:34 -05:00

3040 lines
80 KiB
PHP

<?php
/**
* Returnes true if user prefers Imperial Units
*
* @return boolean
*/
function isImperialUnitUser()
{
return defined('IMPERIAL_UNITS') ? IMPERIAL_UNITS : $GLOBALS['tdSession']->isImperialUnitUser();
}
/**
* Convert km to miles (or kmh to mph)
*
* @param {float} value
* @return float
*/
function convertKilometerToMile($value)
{
return $value * 0.621371192;
}
/**
* Convert meter to feet
*
* @param {float} value
* @return float
*/
function convertMeterToFeet($value)
{
return $value * 3.2808399;
}
/**
* Convert meter per second to miles per second
*
* @param {float} value
* @return float
*/
function convertMpsToMph($value)
{
return $value * 2.23693629;
}
/**
* Convert meter to yard
*
* @param {float} value
* @return float
*/
function convertMeterToYard($value)
{
return $value * 1.0936133;
}
/**
* Convert mm to inches
*
* @param {float} value
* @return float
*/
function convertMmToInch($value)
{
return $value * 0.0393700787;
}
/**
* Convert celcius to fahrenheit
*
* @param {float} value
* @return float
*/
function convertCelciusToFahrenheit($value)
{
return $value * (9/5) + 32;
}
/**
* Calculate wind chill and return celcius temperature
*
* @param {float} temp Temperature in degrees celcius
* @param {float} speed Wind speed in m/s
* @return float
*/
function calculateMetricWindChill($temp, $speed)
{
// Convert windspeed m/s to Km/h
$speed *= 3.6;
if ($temp > 10) return null;
if ($speed <= 4.8) return $temp;
return 13.12 + (0.6215 * $temp) + ((0.3965 * $temp - 11.37) * pow($speed, 0.16));
}
/**
* Calculate wind chill and return fahrenheit temperature
*
* @param {float} temp Temperature in degrees celcius
* @param {float} speed Wind speed in m/s
* @return float
*/
function calculateImperialWindChill($temp, $speed)
{
$value = calculateMetricWindChill($temp, $speed);
if ($value)
{
$value = convertCelciusToFahrenheit($value);
}
return $value;
}
/**
* Convert hPa/mbar to mmhg
*
* @param {float} value
* @return float
*/
function convertMbarToMmhg($value)
{
return $value * 0.75006375541921;
}
/**
* Convert hPa/mbar to inches hg
*
* @param {float} value
* @return float
*/
function convertMbarToInchHg($value)
{
return $value * 0.0295301;
}
/**
* Convert a value based on its unit
*
* @param {float} value
* @param {string} unit
* @return float
*/
function universalDataUnitConvert($value, $unit)
{
if (!isImperialUnitUser()) return array('value' => $value, 'unit' => $unit);
$unit = trim($unit);
if ($unit == 'C') return array('value' => round(convertCelciusToFahrenheit($value), 2), 'unit' => 'F');
return array('value' => $value, 'unit' => $unit);
}
/**
* Returnes true if value is float
*
* @param mixed $value
* @return boolean
*/
function isFloat($value)
{
if (is_numeric($value))
{
// PHP automagically tries to coerce $value to a number
return is_float($value + 0);
}
return false;
}
/**
* Returnes true if value is int
*
* @param mixed $value
* @return boolean
*/
function isInt($value)
{
return (ctype_digit(strval($value)));
}
/**
* Replace first occurence
*
* @param string $search
* @param string $replace
* @param string $string
* @return string
*/
function str_replace_first($search, $replace, $string)
{
$pos = strpos($string, $search);
if ($pos !== false)
{
return substr_replace($string, $replace, $pos, strlen($search));
}
else
{
return $string;
}
}
/**
* Gets the APRS data source filter from an HTTP request
*
* @param array $defaultValues (Default data source values to use if none set)
* @param string $method (INPUT_GET or INPUT_POST)
* @param varname $string (Key to look for, default 'source')
* @return array (Data sources)
*/
function getAPRSFilterSourceFromRequest($defaultValues = [SOURCE_APRS,SOURCE_CWOP,SOURCE_CBAPRS,SOURCE_OGN], $method = INPUT_GET, $varname = 'source')
{
$source = array_filter(array_unique(filter_input($method, $varname, FILTER_VALIDATE_INT, ['flags' => FILTER_REQUIRE_ARRAY | FILTER_NULL_ON_FAILURE | FILTER_FORCE_ARRAY, 'options' => ['min_range'=> SOURCE_APRS, 'max_range'=> SOURCE_OGN]]) ?: $defaultValues));
if (sizeof($source) == 0) $source = $defaultValues;
return $source;
}
/*
* Returnes symbol description
*
* @param string $symbolTable
* @param string $symbol
* @param boolean $includeUndefinedOverlay
* @return string
*/
function getSymbolDescription($symbolTable, $symbol, $includeUndefinedOverlay)
{
if ($symbolTable == '/')
{
switch ($symbol)
{
case '!':
return 'Police, Sheriff';
case '"':
return 'No Symbol';
case '#':
return 'Digipeater';
case '$':
return 'Phone';
case '%':
return 'DX Cluster';
case '&':
return 'HF Gateway';
case '\'':
return 'Small Aircraft';
case '(':
return 'Mobile Satellite Station';
case ')':
return 'Wheelchair (handicapped)';
case '*':
return 'Snowmobile';
case '+':
return 'Red Cross';
case ',':
return 'Scout (Boy Scout)';
case '-':
return 'House (VHF)';
case '.':
return 'X';
case '/':
return 'Red Dot';
case '0':
return 'Circle (0)';
case '1':
return 'Circle (1)';
case '2':
return 'Circle (2)';
case '3':
return 'Circle (3)';
case '4':
return 'Circle (4)';
case '5':
return 'Circle (5)';
case '6':
return 'Circle (6)';
case '7':
return 'Circle (7)';
case '8':
return 'Circle (8)';
case '9':
return 'Circle (9)';
case ':':
return 'Fire';
case ';':
return 'Campground or Portable operation';
case '<':
return 'Motorcycle';
case '=':
return 'Railroad Engine';
case '>':
return 'Car';
case '?':
return 'File server';
case '@':
return 'Hurricane prediction';
case 'A':
return 'Aid Station';
case 'B':
return 'BBS or PBBS';
case 'C':
return 'Canoe';
case 'D':
return 'No Symbol'; // was originally undefined
case 'E':
return 'Event (Special live event)'; // Eyeball
case 'F':
return 'Farm Vehicle (tractor)';
case 'G':
return 'Grid Square (6 digit)';
case 'H':
return 'Hotel (blue bed symbol)';
case 'I':
return 'TCP/IP network station';
case 'J':
return 'No Symbol';
case 'K':
return 'School';
case 'L':
return 'Logged-ON user (or PC User)';
case 'M':
return 'MacAPRS';
case 'N':
return 'NTS Station';
case 'O':
return 'Balloon';
case 'P':
return 'Police';
case 'Q':
return 'TBD';
case 'R':
return 'Recreational Vehicle';
case 'S':
return 'Shuttle';
case 'T':
return 'SSTV';
case 'U':
return 'Bus';
case 'V':
return 'ATV';
case 'W':
return 'National Weather Service';
case 'X':
return 'Helicopter';
case 'Y':
return 'Yacht (sail)';
case 'Z':
return 'WinAPRS';
case '[':
return 'Human/Person';
case '\\':
return 'Triangle (DF station)';
case ']':
return 'Mail/PostOffice';
case '^':
return 'Large Aircraft';
case '_':
return 'Weather Station';
case '`':
return 'Dish Antenna';
case 'a':
return 'Ambulance';
case 'b':
return 'Bike';
case 'c':
return 'Incident Command Post';
case 'd':
return 'Fire Station';
case 'e':
return 'Horse (equestrian)';
case 'f':
return 'Fire Truck';
case 'g':
return 'Glider';
case 'h':
return 'Hospital';
case 'i':
return 'IOTA (islands on the air)';
case 'j':
return 'Jeep';
case 'k':
return 'Truck';
case 'l':
return 'Laptop';
case 'm':
return 'Mic-E Repeater';
case 'n':
return 'Node (black bulls-eye)';
case 'o':
return 'EOC';
case 'p':
return 'Rover (puppy, or dog)';
case 'q':
return 'Grid square';
case 'r':
return 'Antenna';
case 's':
return 'Power Boat';
case 't':
return 'Truck Stop';
case 'u':
return 'Truck (18 wheeler)';
case 'v':
return 'Van';
case 'w':
return 'Water Station';
case 'x':
return 'xAPRS (Unix)';
case 'y':
return 'Yagi @ QTH';
case 'z':
return 'Shelter';
case '{':
return 'No Symbol';
case '|':
return 'TNC Stream Switch';
case '}':
return 'No Symbol';
case '~':
return 'TNC Stream Switch';
}
}
else
{
switch ($symbol)
{
case '!':
switch ($symbolTable)
{
case "\\":
return 'Emergency!';
case 'E':
return 'ELT or EPIRB';
case 'V':
return 'Volcanic Eruption or Lava';
default:
if ($includeUndefinedOverlay)
{
return 'Emergency (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '"':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case '#':
switch ($symbolTable)
{
case '\\':
return 'Digipeater';
case 'A':
return 'Digipeater (An Alt-Freq input digi)';
case 'R':
return 'Digipeater (RELAY only)';
case 'W':
return 'Digipeater (RELAY and WIDE)';
case 'T':
return 'Digipeater (PacComm RELAY,WIDE and TRACE)';
case 'N':
return 'Digipeater (WIDEn-N and relay,wide,trace)';
case 'I':
return 'Digipeater (digipeater is also an IGate)';
case 'L':
return 'Digipeater (LIMITED New n-N Paradigm digi)';
case 'S':
return 'Digipeater (New n-N Paradigm digi)';
case 'P':
return 'Digipeater (PacComm, New n-N Paradigm)';
case 'U':
return 'Digipeater (UI-DIGI firmware)';
case 'D':
return 'Digipeater (DIGI_NED)';
case '1':
return 'Digipeater (Fill-in digi, 1-hop limit)';
case 'X':
return 'Digipeater (Experimental)';
default:
if ($includeUndefinedOverlay)
{
return 'Digipeater (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '$':
switch ($symbolTable)
{
case '\\':
return 'Bank or ATM';
case 'U':
return 'ATM (US dollars)';
case 'L':
return 'ATM (Brittish Pound)';
case 'Y':
return 'ATM (Japanese Yen)';
default:
if ($includeUndefinedOverlay)
{
return 'Bank or ATM (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '%':
switch ($symbolTable)
{
case '\\':
return 'Power/Energy';
case 'C':
return 'Power/Energy (Coal)';
case 'E':
return 'Power/Energy (Emergency)';
case 'G':
return 'Power/Energy (Geothermal)';
case 'H':
return 'Power/Energy (Hydroelectric)';
case 'N':
return 'Power/Energy (Nuclear)';
case 'P':
return 'Power/Energy (Portable)';
case 'S':
return 'Power/Energy (Solar)';
case 'T':
return 'Power/Energy (Turbine)';
case 'W':
return 'Power/Energy (Wind)';
default:
if ($includeUndefinedOverlay)
{
return 'Power/Energy';
}
else
{
return null;
}
}
case '&':
switch ($symbolTable)
{
case '\\':
return 'Gateway';
case 'I':
return 'Igate (Generic)';
case 'R':
return 'Receive only IGate';
case 'P':
return 'PSKmail node';
case 'T':
return 'TX Igate (with path set to 1 hop)';
case 'W':
return 'WIRES-X';
case '2':
return 'TX igate (with path set to 2 hops)';
case 'D':
return 'D-STAR (D-PRS IGate)';
default:
if ($includeUndefinedOverlay)
{
return 'Gateway (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '\'':
switch ($symbolTable)
{
case '\\':
return 'Incident site (Airplane Crash Site)';
case 'A':
return 'Incident site (Automobile crash site)';
case 'H':
return 'Incident site (Hazardous incident)';
case 'M':
return 'Incident site (Multi-Vehicle crash site)';
case 'P':
return 'Incident site (Pileup)';
case 'T':
return 'Incident site (Truck wreck)';
default:
if ($includeUndefinedOverlay)
{
return 'Incident site';
}
else
{
return null;
}
}
case '(':
switch ($symbolTable)
{
case "\\":
return 'Cloudy';
default:
if ($includeUndefinedOverlay)
{
return 'Cloudy';
}
else
{
return null;
}
}
case ')':
switch ($symbolTable)
{
case "\\":
return 'Firenet MEO (Modis Earth Observatory)';
default:
if ($includeUndefinedOverlay)
{
return 'Firenet MEO (Modis Earth Observatory)';
}
else
{
return null;
}
}
case '*':
switch ($symbolTable)
{
case "\\":
return 'Snow';
default:
if ($includeUndefinedOverlay)
{
return 'Snow';
}
else
{
return null;
}
}
case '+':
switch ($symbolTable)
{
case "\\":
return 'Church';
default:
if ($includeUndefinedOverlay)
{
return 'Church';
}
else
{
return null;
}
}
case ',':
switch ($symbolTable)
{
case "\\":
return 'Scout (Girl Scout)';
default:
if ($includeUndefinedOverlay)
{
return 'Scout (Girl Scout)';
}
else
{
return null;
}
}
case '-':
switch ($symbolTable)
{
case '\\':
return 'House (HF)';
case '5':
return 'House (50 Hz mains power)';
case '6':
return 'House (60 Hz mains power)';
case 'B':
return 'House (Backup Battery Power)';
case 'C':
return 'House (Ham club)';
case 'E':
return 'House (Emergency power)';
case 'G':
return 'House (Geothermal)';
case 'H':
return 'House (Hydro powered)';
case 'O':
return 'House (Operator Present)';
case 'S':
return 'House (Solar Powered)';
case 'W':
return 'House (Wind powered)';
default:
if ($includeUndefinedOverlay)
{
return 'House (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '.':
switch ($symbolTable)
{
case "\\":
return 'Unknown Position';
default:
if ($includeUndefinedOverlay)
{
return 'Unknown Position';
}
else
{
return null;
}
}
case '/':
switch ($symbolTable)
{
case "\\":
return 'Waypoint Destination';
default:
if ($includeUndefinedOverlay)
{
return 'Waypoint Destination';
}
else
{
return null;
}
}
case '0':
switch ($symbolTable)
{
case '\\':
return 'Circle';
case 'A':
return 'Allstar Node';
case 'E':
return 'Echolink Node';
case 'I':
return 'IRLP repeater';
case 'S':
return 'Staging Area';
case 'V':
return 'Echolink and IRLP (VOIP)';
case 'W':
return 'WIRES (Yaesu VOIP)';
default:
if ($includeUndefinedOverlay)
{
return 'Circle (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case '8':
switch ($symbolTable)
{
case '\\':
return 'No Symbol';
case '8':
return '802.11 network node';
case 'G':
return '802.11G';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case '9':
switch ($symbolTable) {
case "\\":
return 'Gas Station';
default:
if ($includeUndefinedOverlay)
{
return 'Gas Station';
}
else
{
return null;
}
}
case ':':
switch ($symbolTable)
{
case "\\":
return 'Hail (weather condition)';
default:
if ($includeUndefinedOverlay)
{
return 'Hail (weather condition)';
}
else
{
return null;
}
}
case ';':
switch ($symbolTable)
{
case '\\':
return 'Portable, Park or Picnic';
case 'F':
return 'Field Day';
case 'I':
return 'Islands on the air';
case 'S':
return 'Summits on the air';
case 'W':
return 'WOTA';
default:
if ($includeUndefinedOverlay)
{
return 'Portable';
}
else
{
return null;
}
}
case '<':
switch ($symbolTable)
{
case "\\":
return 'Advisory (single gale flag)';
default:
if ($includeUndefinedOverlay) {
return 'Advisory (single gale flag)';
}
else
{
return null;
}
}
case '=':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case '>':
switch ($symbolTable)
{
case '\\':
return 'Car';
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
return 'Numbered Car (' . $symbolTable . ')';
case 'E':
return 'Car (Electric)';
case 'H':
return 'Car (Hybrid)';
case 'S':
return 'Car (Solar powered)';
case 'V':
return 'Car (GM Volt)';
default:
if ($includeUndefinedOverlay)
{
return 'Car (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '?':
switch ($symbolTable)
{
case "\\":
return 'Info Kiosk';
default:
if ($includeUndefinedOverlay)
{
return 'Info Kiosk';
}
else
{
return null;
}
}
case '@':
switch ($symbolTable)
{
case "\\":
return 'Hurricane/Tropical storm';
default:
if ($includeUndefinedOverlay)
{
return 'Hurricane/Tropical storm (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'A':
switch ($symbolTable)
{
case '\\':
return 'Box';
case '9':
return 'Mobile DTMF user';
case '7':
return 'HT DTMF user';
case 'H':
return 'House DTMF user';
case 'E':
return 'Echolink DTMF report';
case 'I':
return 'IRLP DTMF report';
case 'R':
return 'RFID report';
case 'A':
return 'AllStar DTMF report';
case 'D':
return 'D-Star report';
case 'X':
return 'OLPC Laptop XO';
default:
if ($includeUndefinedOverlay)
{
return 'Box (' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'B':
switch ($symbolTable)
{
case "\\":
return 'Blowing snow';
default:
if ($includeUndefinedOverlay)
{
return 'Blowing snow';
}
else
{
return null;
}
}
case 'C':
switch ($symbolTable)
{
case "\\":
return 'Coast Guard';
default:
if ($includeUndefinedOverlay)
{
return 'Coast Guard';
}
else
{
return null;
}
}
case 'D':
switch ($symbolTable)
{
case '\\':
return 'Depot'; // drizzle rain moved to ' ovlyD
case 'A':
return 'Airport';
case 'F':
return 'Ferry Landing';
case 'H':
return 'Heloport';
case 'R':
return 'Rail Depot';
case 'B':
return 'Bus Depot';
case 'L':
return 'LIght Rail or Subway';
case 'S':
return 'Seaport Depot';
default:
if ($includeUndefinedOverlay)
{
return 'Depot (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'E':
switch ($symbolTable)
{
case '\\':
return 'Smoke';
case 'H':
return 'Haze';
case 'S':
return 'Smoke';
case 'B':
return 'Blowing Snow'; // was \B
case 'D':
return 'Blowing Dust or Sand'; // was \b
case 'F':
return 'Fog'; // was \{
default:
if ($includeUndefinedOverlay)
{
return 'Smoke (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'F':
switch ($symbolTable)
{
case "\\":
return 'Freezing rain';
default:
if ($includeUndefinedOverlay)
{
return 'Freezing rain';
}
else
{
return null;
}
}
case 'G':
switch ($symbolTable) {
case "\\":
return 'Snow Shower';
default:
if ($includeUndefinedOverlay)
{
return 'Snow Shower';
}
else
{
return null;
}
}
case 'H':
switch ($symbolTable)
{
case '\\':
return 'Haze';
case 'R':
return 'Radiation detector';
case 'W':
return 'Hazardous Waste';
case 'X':
return 'Skull&Crossbones';
default:
if ($includeUndefinedOverlay)
{
return 'Hazard (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'I':
switch ($symbolTable)
{
case "\\":
return 'Rain Shower';
default:
if ($includeUndefinedOverlay)
{
return 'Rain Shower';
}
else
{
return null;
}
}
case 'J':
switch ($symbolTable)
{
case "\\":
return 'Lightning';
default:
if ($includeUndefinedOverlay)
{
return 'Lightning';
}
else
{
return null;
}
}
case 'K':
switch ($symbolTable)
{
case "\\":
return 'Kenwood HT';
default:
if ($includeUndefinedOverlay)
{
return 'Kenwood HT';
}
else
{
return null;
}
}
case 'L':
switch ($symbolTable)
{
case "\\":
return 'Lighthouse';
default:
if ($includeUndefinedOverlay)
{
return 'Lighthouse (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'M':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case 'N':
switch ($symbolTable)
{
case "\\":
return 'Navigation Buoy';
default:
if ($includeUndefinedOverlay)
{
return 'Navigation Buoy (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'O':
switch ($symbolTable)
{
case '\\':
return 'Rocket (amateur)';
case 'B':
return 'Blimp (non-rigid airship)';
case 'M':
return 'Manned Balloon';
case 'T':
return 'Teathered Balloon';
case 'C':
return 'Constant Pressure Balloon - Long duration';
case 'R':
return 'Rocket bearing Balloon (Rockoon)';
default:
if ($includeUndefinedOverlay)
{
return 'Balloon (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'P':
switch ($symbolTable)
{
case "\\":
return 'Parking';
default:
if ($includeUndefinedOverlay)
{
return 'Parking (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'Q':
switch ($symbolTable)
{
case "\\":
return 'Quake';
default:
if ($includeUndefinedOverlay)
{
return 'Quake';
}
else
{
return null;
}
}
case 'R':
switch ($symbolTable)
{
case '\\':
return 'Restaurant (generic)';
case '7':
return 'Restaurant (7/11)';
case 'K':
return 'Restaurant (KFC)';
case 'M':
return 'Restaurant (McDonalds)';
case 'T':
return 'Restaurant (Taco Bell)';
default:
if ($includeUndefinedOverlay)
{
return 'Restaurant (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'S':
switch ($symbolTable)
{
case "\\":
return 'Satellite/Pacsat';
default:
if ($includeUndefinedOverlay)
{
return 'Satellite/Pacsat (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'T':
switch ($symbolTable)
{
case "\\":
return 'Thunderstorm';
default:
if ($includeUndefinedOverlay)
{
return 'Thunderstorm (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'U':
switch ($symbolTable)
{
case "\\":
return 'Sunny';
default:
if ($includeUndefinedOverlay)
{
return 'Sunny (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'V':
switch ($symbolTable)
{
case "\\":
return 'VORTAC Navigation Aid';
default:
if ($includeUndefinedOverlay)
{
return 'VORTAC Navigation Aid';
}
else
{
return null;
}
}
case 'W':
switch ($symbolTable)
{
case "\\":
return 'National Weather Service';
default:
if ($includeUndefinedOverlay)
{
return 'National Weather Service (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'X':
switch ($symbolTable)
{
case "\\":
return 'Pharmacy';
default:
if ($includeUndefinedOverlay)
{
return 'Pharmacy';
}
else
{
return null;
}
}
case 'Y':
switch ($symbolTable)
{
case '\\':
return 'Radio/APRS Device';
case 'A':
return 'Alinco';
case 'B':
return 'Byonics';
case 'I':
return 'Icom';
case 'K':
return 'Kenwood';
case 'Y':
return 'Yaesu/Standard';
default:
if ($includeUndefinedOverlay)
{
return 'Radio/APRS Device'; // or "No Symbol"?
}
else
{
return null;
}
}
case 'Z':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case '[':
switch ($symbolTable)
{
case '\\':
return 'Wall Cloud (or pedestal cloud)';
case 'B':
return 'Baby on board (stroller, pram etc)';
case 'S':
return 'Skier';
case 'R':
return 'Runner';
case 'H':
return 'Hiker';
default:
if ($includeUndefinedOverlay)
{
return 'Human/Person (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '\\':
switch ($symbolTable)
{
case '\\':
return 'No Symbol';
case 'A':
return 'Avmap G5';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case ']':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case '^':
switch ($symbolTable)
{
case '\\':
return 'Aircraft'; // top-view originally intended to point in direction of flight
case 'A':
return 'Aircraft (A = Autonomous)';
case 'D':
return 'Aircraft (D = Drone)';
case 'E':
return 'Aircraft (E = Electric aircraft)';
case 'G':
return 'Aircraft (G = Glider aircraft)';
case 'H':
return 'Aircraft (H = Hovercraft)';
case 'J':
return 'Aircraft (J = JET)';
case 'L':
return 'Paraglider'; // Not official definition
case 'M':
return 'Aircraft (M = Missle)';
case 'P':
return 'Aircraft (P = Propeller)';
case 'R':
return 'Aircraft (R = Remotely Piloted)';
case 'S':
return 'Aircraft (S = Solar Powered)';
case 'V':
return 'Aircraft (V = Vertical takeoff)';
case 'X':
return 'Aircraft (X = Experimental)';
default:
if ($includeUndefinedOverlay)
{
return 'Aircraft (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '_':
switch ($symbolTable)
{
case "\\":
return 'Weather Station';
default:
if ($includeUndefinedOverlay)
{
return 'Weather Station (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '`':
switch ($symbolTable)
{
case "\\":
return 'Rain';
default:
if ($includeUndefinedOverlay)
{
return 'Rain';
}
else
{
return null;
}
}
case 'a':
switch ($symbolTable)
{
case '\\':
return 'Red Diamond';
case 'A':
return 'ARES';
case 'D':
return 'D-STAR (previously Dutch ARES)';
case 'G':
return 'RSGB Radio Society of Great Brittan';
case 'R':
return 'RACES';
case 'S':
return 'SATERN Salvation Army';
case 'W':
return 'WinLink';
case 'Y':
return 'C4FM Yaesu repeaters';
default:
if ($includeUndefinedOverlay)
{
return 'Red Diamond (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'b':
switch ($symbolTable)
{
case "\\":
return 'Dust blowing';
default:
if ($includeUndefinedOverlay)
{
return 'Dust blowing';
}
else
{
return null;
}
}
case 'c':
switch ($symbolTable)
{
case '\\':
return 'Civil Defense';
case 'D':
return 'Decontamination';
case 'R':
return 'RACES';
case 'S':
return 'SATERN mobile canteen';
default:
if ($includeUndefinedOverlay)
{
return 'Civil Defense (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'd':
switch ($symbolTable)
{
case "\\":
return 'DX Spot';
default:
if ($includeUndefinedOverlay)
{
return 'DX Spot';
}
else
{
return null;
}
}
case 'e':
switch ($symbolTable)
{
case "\\":
return 'Sleet';
default:
if ($includeUndefinedOverlay)
{
return 'Sleet';
}
else
{
return null;
}
}
case 'f':
switch ($symbolTable)
{
case "\\":
return 'Funnel Cloud';
default:
if ($includeUndefinedOverlay)
{
return 'Funnel Cloud';
}
else
{
return null;
}
}
case 'g':
switch ($symbolTable)
{
case "\\":
return 'Gale warning flags';
default:
if ($includeUndefinedOverlay)
{
return 'Gale warning flags (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'h':
switch ($symbolTable)
{
case '\\':
return 'Store/Ham Store';
case 'F':
return 'Hamfest';
case 'H':
return 'Home Dept etc..';
default:
if ($includeUndefinedOverlay)
{
return 'Other store (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'i':
switch ($symbolTable)
{
case "\\":
return 'Point of interest';
default:
if ($includeUndefinedOverlay)
{
return 'Point of interest (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'j':
switch ($symbolTable)
{
case "\\":
return 'Work Zone';
default:
if ($includeUndefinedOverlay)
{
return 'Work Zone';
}
else
{
return null;
}
}
case 'k':
switch ($symbolTable)
{
case '\\':
return 'Special Vehicle (SUV)';
case '4':
return 'Special Vehicle (4x4)';
case 'A':
return 'Special Vehicle (ATV)';
default:
if ($includeUndefinedOverlay)
{
return 'Special Vehicle (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'l':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case 'm':
switch ($symbolTable)
{
case "\\":
return 'Milepost';
default:
if ($includeUndefinedOverlay)
{
return 'Milepost';
}
else
{
return null;
}
}
case 'n':
switch ($symbolTable)
{
case "\\":
return 'Red Triangle';
default:
if ($includeUndefinedOverlay)
{
return 'Red Triangle (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'o':
switch ($symbolTable)
{
case "\\":
return 'Small Circle';
default:
if ($includeUndefinedOverlay)
{
return 'Small Circle (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'p':
switch ($symbolTable)
{
case "\\":
return 'Partly Cloudy';
default:
if ($includeUndefinedOverlay)
{
return 'Partly Cloudy';
}
else
{
return null;
}
}
case 'q':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case 'r':
switch ($symbolTable)
{
case "\\":
return 'Restrooms';
default:
if ($includeUndefinedOverlay)
{
return 'Restrooms';
}
else
{
return null;
}
}
case 's':
switch ($symbolTable)
{
case '\\':
return 'Ship/Boat';
case '6':
return 'Ship/Boat (Shipwreck "deep6")';
case 'B':
return 'Ship/Boat (Pleasure Boat)';
case 'C':
return 'Ship/Boat (Cargo)';
case 'D':
return 'Ship/Boat (Diving)';
case 'E':
return 'Ship/Boat (Emergency or Medical transport)';
case 'F':
return 'Ship/Boat (Fishing)';
case 'H':
return 'Ship/Boat (High-speed Craft)';
case 'J':
return 'Ship/Boat (Jet Ski)';
case 'L':
return 'Ship/Boat (Law enforcement)';
case 'M':
return 'Ship/Boat (Miltary)';
case 'O':
return 'Ship/Boat (Oil Rig)';
case 'P':
return 'Ship/Boat (Pilot Boat)';
case 'Q':
return 'Ship/Boat (Torpedo)';
case 'S':
return 'Ship/Boat (Search and Rescue)';
case 'T':
return 'Ship/Boat (Tug)';
case 'U':
return 'Ship/Boat (Underwater ops or submarine)';
case 'W':
return 'Ship/Boat (Wing-in-Ground effect or Hovercraft)';
case 'X':
return 'Ship/Boat (Passenger, Ferry)';
case 'Y':
return 'Ship/Boat (Sailing, large ship)';
default:
if ($includeUndefinedOverlay)
{
return 'Ship/Boat (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 't':
switch ($symbolTable)
{
case "\\":
return 'Tornado';
default:
if ($includeUndefinedOverlay)
{
return 'Tornado';
}
else
{
return null;
}
}
case 'u':
switch ($symbolTable)
{
case '\\':
return 'Truck';
case 'B':
return 'Truck (Buldozer/construction/Backhoe)';
case 'G':
return 'Truck (Gas)';
case 'P':
return 'Truck (Plow or SnowPlow)';
case 'T':
return 'Truck (Tanker)';
case 'C':
return 'Truck (Chlorine Tanker)';
case 'H':
return 'Truck (Hazardous)';
default:
if ($includeUndefinedOverlay)
{
return 'Truck (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'v':
switch ($symbolTable)
{
case "\\":
return 'Van';
default:
if ($includeUndefinedOverlay)
{
return 'Van (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case 'w':
switch ($symbolTable)
{
case "\\":
return 'Flooding';
default:
if ($includeUndefinedOverlay)
{
return 'Flooding';
}
else
{
return null;
}
}
case 'x':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case 'y':
switch ($symbolTable)
{
case "\\":
return 'Skywarn';
default:
if ($includeUndefinedOverlay)
{
return 'Skywarn';
}
else
{
return null;
}
}
case 'z':
switch ($symbolTable)
{
case '\\':
return 'Shelter';
case 'C':
return 'Clinic';
case 'G':
return 'Government building';
case 'M':
return 'Morgue';
case 'T':
return 'Triage';
default:
if ($includeUndefinedOverlay)
{
return 'Building (with overlay ' . $symbolTable . ')';
}
else
{
return null;
}
}
case '{':
switch ($symbolTable)
{
case "\\":
return 'Fog';
default:
if ($includeUndefinedOverlay)
{
return 'Fog';
}
else
{
return null;
}
}
case '|':
switch ($symbolTable)
{
case "\\":
return 'TNC Stream Switch';
default:
if ($includeUndefinedOverlay)
{
return 'TNC Stream Switch';
}
else
{
return null;
}
}
case '}':
switch ($symbolTable)
{
case "\\":
return 'No Symbol';
default:
if ($includeUndefinedOverlay)
{
return 'No Symbol';
}
else
{
return null;
}
}
case '~':
switch ($symbolTable)
{
case "\\":
return 'TNC Stream Switch';
default:
if ($includeUndefinedOverlay)
{
return 'TNC Stream Switch';
}
else
{
return null;
}
}
}
}
}
/**
* Returnes true if we may show data older than 24h
*
* @return boolean
*/
function isAllowedToShowOlderData()
{
$isAllowedToShowOlderData = false;
$config = getConfig('application_server');
if (isset($config) && is_array($config))
{
if (isset($config['allow_time_travel']))
{
if ($config['allow_time_travel'] == '1')
{
$isAllowedToShowOlderData = true;
}
}
}
return $isAllowedToShowOlderData;
}
/**
* Returnes valid view path
*
* @param {string} $request
* @return string
*/
function getView($request)
{
if (is_null($request)) return null;
$parts = explode("/", trim($request, '/'));
if (count($parts) >= 2)
{
$page = array_pop($parts);
$dir = array_pop($parts);
if ($page && ($dir == 'views' || $dir == 'station' || $dir == 'account' || $dir == 'events'))
{
$path = ROOT . '/public/' . $dir . '/' . $page;
if (file_exists($path)) return $path;
}
}
return null;
}
/**
* Helper function to return an assoc array containing the bootstrap config
*
* @param {string} $key
* @return string
* */
function getBootstrapConfig()
{
global $bootstrap_config;
return $bootstrap_config['bootstrap'];
}
/**
* Helper function to return an assoc array containing website related values from config
*
* @param {string} $key
* @return string
* */
function getWebsiteConfig($key)
{
return getConfig('website', $key);
}
/**
* Helper function to return an assoc array containing backend database related values from config
*
* @param {string} $key
* @return string
* */
function getBackendDatabaseConfig($key)
{
return getConfig('backend_database', $key);
}
/**
* Helper function to return an assoc array containing database related values from config
*
* @param {string} $key
* @return string
* */
function getDatabaseConfig($key)
{
return getConfig('database', $key);
}
/**
* Helper function to return an assoc array containing websocket related values from config
*
* @param {string} $key
* @return string
* */
function getWebsocketConfig($key)
{
return getConfig('application_server', $key);
}
/**
* Helper function to return an assoc array containing SMTP related values from config
*
* @param {string} $key
* @return string
* */
function getEmailConfig($key)
{
return getConfig('email', $key);
}
/**
* Returns an associative array containing related key values from the specified section in the configuration.
*
* @param string $section The section of the configuration to retrieve values from.
* @param string|null $key The specific key to retrieve. If null, the entire section is returned.
* @return array|null Returns the value associated with the key, the entire section, or null if not found.
*/
function getConfig(string $section, ?string $key = null): mixed
{
global $config;
if (isset($config[$section]))
{
if ($key === null)
{
return $config[$section];
}
if (isset($config[$section][$key]))
{
return $config[$section][$key];
}
}
return null; // Explicitly return null if the section or key is not found
}
/**
* Echo a language phrase from $id to the browser
*
* @param {string} $id - The phrase key
* @param {int} $itemCount - Number of items the phrase refers to (for pluralization)
* @return none
*/
function _L($id, $itemCount = 1)
{
global $language;
if (isset($language['en-us']["$id"]))
{
if ($itemCount == 1)
echo $language['en-us'][$id]['s'] ?? 'literal missing';
else
echo $language['en-us'][$id]['p'] ?? 'literal missing';
}
else echo 'literal missing';
}
/**
* Returns a language phrase from $id
*
* @param {string} $id - The phrase key
* @param {int} $itemCount - Number of items the phrase refers to (for pluralization)
* @return {string} - The phrase from the language
*/
function _LANG($id, $itemCount = 1)
{
global $language;
if (isset($language['en-us']["$id"]))
{
if ($itemCount == 1)
return $language['en-us'][$id]['s'];
else
return $language['en-us'][$id]['p'];
}
else return 'literal missing';
}
/**
* Convert coordinate to pixel position in heatmap image
*
* @param {float} $lat
* @param {int} $zoom
* @param {int} $imageTileSize
* @return int
*/
function getLatPixelCoordinate($lat, $zoom, $imageTileSize)
{
$pixelGlobeSize = $imageTileSize * pow(2, $zoom);
$yPixelsToRadiansRatio = $pixelGlobeSize / (2 * M_PI);
$halfPixelGlobeSize = $pixelGlobeSize / 2;
$pixelGlobeCenterY = $halfPixelGlobeSize;
$degreesToRadiansRatio = 180 / M_PI;
$siny = sin($lat * M_PI / 180);
# Truncating to 0.9999 effectively limits latitude to 89.189. This is
# about a third of a tile past the edge of the world tile.
if ($siny < -0.9999)
{
$siny = -0.9999;
}
if ($siny > 0.9999)
{
$siny = 0.9999;
}
$latY = round($pixelGlobeCenterY + 0.5 * log((1 + $siny) / (1 - $siny)) * -$yPixelsToRadiansRatio);
return $latY;
}
/**
* Convert coordinate to pixel position in heatmap image
*
* @param {float} $lng
* @param {int} $zoom
* @param {int} $imageTileSize
* @return int
*/
function getLngPixelCoordinate($lng, $zoom, $imageTileSize)
{
$scale = 1 << $zoom;
$lngX = floor($imageTileSize * (0.5 + $lng / 360) * $scale);
return $lngX;
}
/**
* Convert pixel position in heatmap image to coordinate
*
* @param {float} $latPixelCoord
* @param {int} $zoom
* @param {int} $imageTileSize
* @return float
*/
function getLatFromLatPixelCoordinate($latPixelCoord, $zoom, $imageTileSize)
{
$pixelGlobeSize = $imageTileSize * pow(2, $zoom);
$yPixelsToRadiansRatio = $pixelGlobeSize / (2 * M_PI);
$halfPixelGlobeSize = $pixelGlobeSize / 2;
$pixelGlobeCenterY = $halfPixelGlobeSize;
$degreesToRadiansRatio = 180 / M_PI;
$lat = (2 * atan(exp(($latPixelCoord - $pixelGlobeCenterY) / -$yPixelsToRadiansRatio)) - M_PI / 2) * $degreesToRadiansRatio;
return $lat;
}
/**
* Convert pixel position in heatmap image to coordinate
*
* @param {float} $lngPixelCoord
* @param {int} $zoom
* @param {int} $imageTileSize
* @return float
*/
function getLngFromLngPixelCoordinate($lngPixelCoord, $zoom, $imageTileSize)
{
$scale = 1 << $zoom;
$lng = ((($lngPixelCoord / $scale) / $imageTileSize) - 0.5) * 360;
return $lng;
}
/**
* Get the closest timezone from coordinates
* Original credit to ben@jp
* https://stackoverflow.com/questions/3126878/get-php-timezone-name-from-latitude-and-longitude
*
* @param {float} $latitude
* @param {float} $longitude
* @param {string} $countryCode (optional)
* @return string
*/
function getNearestTimezone($latitude, $longitude, $countryCode = '')
{
if (is_null($latitude) || is_null($longitude)) return null;
$countryCode = strtoupper(trim($countryCode));
$timezone_ids = ($countryCode) ? DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $countryCode) : DateTimeZone::listIdentifiers();
if($timezone_ids && is_array($timezone_ids) && isset($timezone_ids[0]))
{
$time_zone = '';
$tz_distance = 0;
$timezone_obj = null;
//only one identifier?
if (count($timezone_ids) == 1)
{
$time_zone = $timezone_ids[0];
}
else
{
foreach($timezone_ids as $timezone_id)
{
$timezone = new DateTimeZone($timezone_id);
$location = $timezone->getLocation();
$tz_lat = $location['latitude'];
$tz_long = $location['longitude'];
$theta = $longitude - $tz_long;
$distance = (sin(deg2rad($latitude)) * sin(deg2rad($tz_lat))) + (cos(deg2rad($latitude)) * cos(deg2rad($tz_lat)) * cos(deg2rad($theta)));
$distance = acos($distance);
$distance = abs(rad2deg($distance));
if (!$time_zone || $tz_distance > $distance)
{
$time_zone = $timezone_id;
$tz_distance = $distance;
$timezone_obj = $timezone;
}
}
}
return $timezone_obj;
}
return null;
}
/**
* Get the maindenhead grid square from latitiude and longitude
*
* @param {float} $latitude
* @param {float} $longitude
* @param {int} $precision (optional, min/default = 3, max = 5)
* @return string
*/
define('ORD_A', ord('A'));
define('ORD_0', ord('0'));
function getMaidenheadFromCoordinates($latitude, $longitude, $precision = 3)
{
if ($precision < 3 || $precision > 5) $precision = 3;
$lat = $latitude + 90;
$lon = $longitude + 180;
// Pair 1
$gs = chr(ORD_A + floor($lon / 20)) . chr(ORD_A + floor($lat / 10));
$lon = fmod($lon, 20);
if ($lon < 0) $lon += 20;
$lat = fmod($lat, 10);
if ($lat < 0) $lat += 10;
// Pair 2
$gs .= chr(ORD_0 + floor($lon / 2)) . chr(ORD_0 + floor($lat / 1));
$lon = fmod($lon, 2);
if ($lon < 0) $lon += 2;
$lat = fmod($lat, 1);
if ($lat < 0) $lat += 1;
// Pair 3
$gs .= chr(ORD_A + floor($lon * 12)) . chr(ORD_A + floor($lat * 24));
$lon = fmod($lon, (1/12));
if ($lon < 0) $lon += (1/12);
$lat = fmod($lat, (1/24));
if ($lat < 0) $lat += (1/24);
// Pair 4
if ($precision > 3)
{
$gs .= chr(ORD_0 + floor($lon * 120)) . chr(ORD_0 + floor($lat * 240));
$lon = fmod($lon, (1/120));
if ($lon < 0) $lon += (1/120);
$lat = fmod($lat, (1/240));
if ($lat < 0) $lat += (1/240);
}
// Pair 5
if ($precision > 4)
{
$gs .= chr(ORD_A + floor($lon * 120 * 24)) . chr(ORD_A + floor($lat * 240 * 24));
$lon = fmod($lon, (1/120/24));
if ($lon < 0) $lon += (1/120/24);
$lat = fmod($lat, (1/240/24));
if ($lat < 0) $lat += (1/240/24);
}
return $gs;
}
// Imported from repository... Object fetch is slower, so we will not use it here
function getTelemetryValue($telemetryPacket, $valNumber, $rootTelemetryPacket)
{
$val = $telemetryPacket["val{$valNumber}"];
$eqns = $rootTelemetryPacket->getEqnsValue($valNumber);
$a = $eqns[0];
$b = $eqns[1];
$c = $eqns[2];
if ($a == null && $b == null)
{
// User has sent us a faulty eqns, just return raw value
return $val;
}
else
{
$result = 0;
if ($a != null)
{
$result += $a * $val * $val;
}
if ($b != null)
{
$result += $b * $val;
}
if ($c != null)
{
$result += $c;
}
return $result;
}
}
/**
* Converts degrees to cardinal directions
*
* @param {int} $degrees
* @return string
*/
function convertDegreesToCardinalDirection($degrees)
{
if (!isInt($degrees) || $degrees > 360) return '';
return ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'][round($degrees / 22.5)];
}
/**
* Parses a Mic-E Destination Address
*
* @param {char} $c
* @return array
* */
function getInfoForDestinationAddressChar($c)
{
//0 - 0, 1 - 1 custom, 2 - 1 std
$asciiCode = ord($c);
$ret = ['latDigit'=> 0, 'message'=> 0, 'isNorth'=> false, 'longOffset'=> 0, 'isWest'=> false];
if ($c >= '0' && $c <= '9')
{
$ret['latDigit'] = $asciiCode - ord('0');
}
else if ($c >= 'A' && $c <= 'J')
{
$ret['latDigit'] = $asciiCode - ord('A');
$ret['message'] = 1;
$ret['isNorth'] = null;
$ret['longOffset'] = null;
$ret['isWest'] = null;
}
else if ($c == 'K')
{
$ret['latDigit'] = 0;
$ret['message'] = 1;
$ret['isNorth'] = null;
$ret['longOffset'] = null;
$ret['isWest'] = null;
}
else if ($c == 'L')
{
$ret['latDigit'] = 0;
$ret['message'] = 0;
}
else if ($c >= 'P' && $c <= 'Y')
{
$ret['latDigit'] = $asciiCode - ord('P');
$ret['message'] = 2;
$ret['isNorth'] = true;
$ret['longOffset'] = 100;
$ret['isWest'] = true;
}
else if ($c == 'Z')
{
$ret['latDigit'] = 0;
$ret['message'] = 2;
$ret['isNorth'] = true;
$ret['longOffset'] = 100;
$ret['isWest'] = true;
}
return $ret;
}
const MicEStates =
[
'M0'=> 'off duty',
'M1'=> 'en route',
'M2'=> 'in service',
'M3'=> 'returning',
'M4'=> 'commited',
'M5'=> 'special',
'M6'=> 'priority',
'C0'=> 'custom-0',
'C1'=> 'custom-1',
'C2'=> 'custom-2',
'C3'=> 'custom-3',
'C4'=> 'custom-4',
'C5'=> 'custom-5',
'C6'=> 'custom-6',
'EMERGENCY'=> 'emergency',
'UNKNOWN'=> 'unknown'
];
/**
* Gets the Mic-E state (i.e. In Service) from the Mic-E data
* Note Message: array, 3 elements, values: 0 - 0, 1 - 1 custom, 2 - 1 std
* @param {string} $message
* @return {string}
*/
function getStateFromMicE($message)
{
$state = null;
if (sizeof($message) != 3) return null; // Message array should contain 3 elements
if ($message[0] == 0 && $message[1] == 0 && $message[2] == 0)
{
$state = MicEStates['EMERGENCY'];
}
else
{
$isStd = $message[0] == 2 || $message[1] == 2 || $message[2] == 2;
$isCustom = $message[0] == 1 || $message[1] == 1 || $message[2] == 1;
if ($isStd && $isCustom)
{
$state = MicEStates['UNKNOWN'];
}
else
{
$message[0] = $message[0] == 2 ? 1 : $message[0];
$message[1] = $message[1] == 2 ? 1 : $message[1];
$message[2] = $message[2] == 2 ? 1 : $message[2];
if ($message == [1, 1, 1])
$state = $isStd ? MicEStates['M0'] : MicEStates['C0'];
else if ($message == [1, 1, 0])
$state = $isStd ? MicEStates['M1'] : MicEStates['C1'];
else if ($message == [1, 0, 1])
$state = $isStd ? MicEStates['M2'] : MicEStates['C2'];
else if ($message == [1, 0, 0])
$state = $isStd ? MicEStates['M3'] : MicEStates['C3'];
else if ($message == [0, 1, 1])
$state = $isStd ? MicEStates['M4'] : MicEStates['C4'];
else if ($message == [0, 1, 0])
$state = $isStd ? MicEStates['M5'] : MicEStates['C5'];
else if ($message == [0, 0, 1])
$state = $isStd ? MicEStates['M6'] : MicEStates['C6'];
else
$state = MicEStates['UNKNOWN'];
}
}
return $state;
}
/**
* Generates a random numerical code $length digits long
*
* @param {int} $length (Length of the random code to generate, default 6)
* @return {string} (Generated code)
*/
function generateSecureCode($length = 6)
{
// Generate a {$length} digit random code
$code = [];
for ($x = 0; $x < $length; ++$x)
{
$code[] = strval(random_int(0, 9));
}
return implode('', $code);
}
/**
* Generates a random binary token $length digits long
*
* @param {int} $length (Length of the random token to generate, default 20)
* @return {string} (Generated code)
*/
function generateSecureToken($length = 20)
{
return bin2hex(random_bytes($length));
}
/**
* Generates a base URL to the site taking into account http vs https and domain name
*
* @return {string} (Full URL to site including http/https)
*/
function getWebsiteURL()
{
return (getWebsiteConfig('cookie_secure') == 1 ? "https" : "http") . "://" . getWebsiteConfig('cookie_domain');
}
/**
* Outputs to the client a fully rendered navigation menu for the station modal
*
* @param {string} $selectedIndex (Base name of the file being displayed i.e. station.php)
* @param {array} $urlParams (Array of parameters to pass in each generated URL)
* @param {string} $extraHTML (Extra menu HTML to include at the end of the menu)
* @return {string} HTML Menu
*/
function getStationMenu($selectedIndex, $urlParams = [], $extraHTML = null)
{
global $tdSession;
$pages =
[
'station.php' => ['title' => 'Station Details', 'text' => 'Station'],
'statistics.php' => ['title' => 'Station Statistics', 'text' => 'Statistics'],
'trail.php' => ['title' => 'Trail Chart', 'text' => 'Trail Chart'],
'weather.php' => ['title' => 'Weather Conditions, History, and Graphs', 'text' => 'Weather'],
'telemetry.php' => ['title' => 'Current and Historical Telemetry and Graphs', 'text' => 'Telemetry'],
'raw.php' => ['title' => 'Raw Packets', 'text' => 'Raw Packets'],
'live.php' => ['title' => 'Live Packet Feed', 'text' => 'Live Feed'],
'messages.php' => ['title' => 'Station Messages', 'text' => 'Messages'],
'bulletins.php' => ['title' => 'Station Bulletins', 'text' => 'Bulletins']
];
return renderMenu('station-menu', '/station/', $pages, $selectedIndex, $urlParams, $extraHTML);
}
/**
* Outputs to the client a fully rendered navigation menu for the account management modal
*
* @param {string} $selectedIndexL (Base name of the file being displayed i.e. station.php)
* @param {array} $urlParams (Array of parameters to pass in each generated URL)
* @param {string} $extraHTML (Extra menu HTML to include at the end of the menu)
* @return {string} HTML Menu
*/
function getAccountMenu($selectedIndex, $urlParams = [], $extraHTML = null)
{
global $tdSession;
$pages =
[
'map_settings.php' => ['title' => 'Map Settings', 'text' => 'Map Settings'],
'site_settings.php' => ['title' => 'Site Settings', 'text' => 'Site Settings'],
'my_stations.php' => ['title' => 'My Stations', 'text' => 'My Stations'],
'favorites.php' => ['title' => 'Favorite Stations', 'text' => 'Favorite Stations'],
'aprs_thursday.php' => ['title' => 'My APRSThursday Profile', 'text' => 'APRSThursday Profile'],
'mapshots.php' => ['title' => 'Map Snapshots (Mapshots)', 'text' => 'Map Snapshots'],
'my_api.php' => ['title' => 'Personal API', 'text' => 'Personal API'],
'account.php' => ['title' => 'My Account', 'text' => 'My Account']
];
return renderMenu('account-menu', '/account/', $pages, $selectedIndex, $urlParams, $extraHTML);
}
/**
* Outputs to the client a fully rendered general navigation menu for the account management modal
*
* @param {string} $selectedIndex (Base name of the file being displayed i.e. station.php)
* @param {array} $urlParams (Array of parameters to pass in each generated URL)
* @param {string} $extraHTML (Extra menu HTML to include at the end of the menu)
* @return {string} HTML Menu
*/
function getGeneralMenu($selectedIndex, $urlParams = [], $extraHTML = null)
{
global $tdSession;
$pages =
[
'about.php' => ['title' => 'More information about this APRS website', 'text' => 'About'],
'faq.php' => ['title' => 'Frequently Asked Questions about APRS', 'text' => 'FAQ'],
'site_statistics.php' => ['title' => 'Site and Database Statistics', 'text' => 'Statistics'],
'changelog.php' => ['title' => 'APRS Site News and Updates', 'text' => 'What\'s New?'],
'server_health.php' => ['title' => 'Check the Health of systems supporting this APRS map.', 'text' => 'Server Status'],
'data_availability.php' => ['title' => 'Check the availability of the data avaiable to the map.', 'text' => 'Data Availability']
];
if (getWebsiteConfig('aprs_is_status_url')) $pages['aprs_status.php'] = ['title' => 'APRS Server Status and Metrics', 'text' => 'APRS Server Status'];
if (getWebsiteConfig('cwop_is_status_url')) $pages['cwop_status.php'] = ['title' => 'CWOP Server Status and Metrics', 'text' => 'CWOP Server Status'];
if (getWebsiteConfig('ogn_is_status_url')) $pages['ogn_status.php'] = ['title' => 'OGN Server Status and Metrics', 'text' => 'OGN Server Status'];
if (getWebsiteConfig('cbaprs_is_status_url')) $pages['cbaprs_status.php'] = ['title' => 'CBAPRS Server Status and Metrics', 'text' => 'CBAPRS Server Status'];
return renderMenu('about-menu', '/views/', $pages, $selectedIndex, $urlParams, $extraHTML);
}
/**
* Outputs to the client a fully rendered search window navigation menu
*
* @param {string} $selectedIndex (Base name of the file being displayed i.e. station.php)
* @param {array} $urlParams (Array of parameters to pass in each generated URL)
* @param {string} $extraHTML (Extra menu HTML to include at the end of the menu)
* @return {string} HTML Menu
*/
function getSearchMenu($selectedIndex, $urlParams = [], $extraHTML = null)
{
global $tdSession;
$pages =
[
'search.php' => ['title' => 'Search for a station/object/airplane, etc.', 'text' => 'Station Search'],
'search_grid.php' => ['title' => 'Maidenhead Locator Grid Search', 'text' => 'Maidenhead Grid Search'],
'search_location.php' => ['title' => 'Search for any place (address, business, park) or location', 'text' => 'Location Search'],
'search_license.php' => ['title' => 'Search the FCC and Canadian License Databases', 'text' => 'License Search']
];
return renderMenu('search-menu', '/views/', $pages, $selectedIndex, $urlParams, $extraHTML);
}
/**
* Outputs to the client a fully rendered legal (ToS) window navigation menu
*
* @param {string} $selectedIndex (Base name of the file being displayed i.e. station.php)
* @param {array} $urlParams (Array of parameters to pass in each generated URL)
* @param {string} $extraHTML (Extra menu HTML to include at the end of the menu)
* @return {string} HTML Menu
*/
function getLegalMenu($selectedIndex, $urlParams = [], $extraHTML = null)
{
global $tdSession;
$pages =
[
'contact.php' => ['title' => 'Contact us with questions or to report a problem', 'text' => 'Contact Us'],
'terms_of_service.php' => ['title' => 'Terms of Service Agreement', 'text' => 'Terms of Service'],
'privacy_policy.php' => ['title' => 'Our Commitment to your Privacy', 'text' => 'Privacy Policy']
];
return renderMenu('legal-menu', '/views/', $pages, $selectedIndex, $urlParams, $extraHTML);
}
/**
* Outputs to the client a fully rendered #APRSThursday window navigation menu
*
* @param {string} $selectedIndex (Base name of the file being displayed i.e. station.php)
* @param {array} $urlParams (Array of parameters to pass in each generated URL)
* @param {string} $extraHTML (Extra menu HTML to include at the end of the menu)
* @return {string} HTML Menu
*/
function getAPRSThursdayMenu($selectedIndex, $urlParams = [], $extraHTML = null)
{
global $tdSession;
$pages =
[
'aprs_thursday.php' => ['title' => 'All about the #APRSThursday Weekly Net', 'text' => 'About #APRSThursday'],
'aprs_thursday_checkins.php' => ['title' => 'View check-ins for the most recent nets.', 'text' => 'Recent Check-Ins'],
'aprs_thursday_statistics.php' => ['title' => 'Historical statistics since the beginning of #APRSThursday.', 'text' => 'Statistics'],
'aprs_thursday_leaderboard.php' => ['title' => 'View the participation leaderboard.', 'text' => 'Leaderboard']
];
return renderMenu('APRSThursday-menu', '/events/', $pages, $selectedIndex, $urlParams, $extraHTML);
}
/**
* Outputs to the client a fully rendered navigation menu
*
* @param {string} $selectId (ID of the select tag for the menu)
* @param {string} $baseURL (Root path of the items in the menu)
* @param {array} $pages (Array of pages to use as menu items)
* @param {string} $selectedIndex (Base name of the file being displayed i.e. station.php)
* @param {array} $urlParams (Array of parameters to pass in each generated URL)
* @param {string} $extraHTML (Extra menu HTML to include at the end of the menu)
* @return {string} HTML Menu
*/
function renderMenu($selectId, $baseURL, $pages, $selectedIndex, $urlParams = [], $extraHTML = null)
{
global $tdSession;
// Mobile Menu
$menu = '<div><span class="mobile-menu">Menu: <select id="' . $selectId . '" onchange="$t.ui.loadModal($(this).val());return false;">';
foreach ($pages as $page => $meta)
{
$menu .= '<option value="' . $tdSession->getURL($baseURL . $page, $urlParams) . '" ' . ($selectedIndex == $page ? 'selected="selected"' : '') . ' title="' . $meta['title'] . '">' . $meta['text'] . '</option>';
}
$menu .= '</select></span>';
// Normal Menu
$menu .= '<div class="modal-inner-content-menu">';
foreach ($pages as $page => $meta)
{
if ($selectedIndex == $page) $menu .= '<span>' . $meta['text'] . '</span>';
else $menu .= '<a class="mdWin" title="' . $meta['title'] . '" href="' . $tdSession->getURL($baseURL . $page, $urlParams) . '">' . $meta['text'] . '</a>';
}
$menu .= '</div>' . $extraHTML . '</div>';
return $menu;
}
/**
* Outputs to the client a fully rendered navigation menu
*
* @param {string} $colorName (CSS Color Name)
* @param {string} $alpha (Alpha transparency value 0-.99)
* @return {string} Complete rgbA CSS tag
*/
function cssColorToRgbATag($colorName, $alpha)
{
$cssColors = [
'black' => '0,0,0',
'silver' => '192, 192, 192',
'gray' => '128, 128, 128',
'white' => '255, 255, 255',
'maroon' => '128, 0, 0',
'red' => '255, 0, 0',
'purple' => '128, 0, 128',
'fuchsia' => '255, 0, 255',
'green' => '0, 128, 0',
'lime' => '0, 255, 0',
'olive' => '128, 128, 0',
'yellow' => '255, 255, 0',
'navy' => '0, 0, 128',
'blue' => '0, 0, 255',
'teal' => '0, 128, 128',
'aqua' => '0, 255, 255'
];
// Return black if no color is specififed
if (is_null($colorName) || $colorName == '') return 'rgba(' . $cssColors["black"] . ", $alpha)";
return 'rgba(' . $cssColors["$colorName"] . ", $alpha)";
}
/**
* Wrapper function to return a station object from various URI critera
*
* @return {Station} Station object (uninitialized if no station found)
*/
function getStationFromURI()
{
if (isset($_GET['c']))
{
$name = filter_input(INPUT_GET, 'c', FILTER_DEFAULT);
return StationRepository::getInstance()->getObjectByName(strtoupper(trim($name)));
}
// New ID format with sourceId as the first digit
else if (isset($_GET['s']))
{
$station_id = filter_input(INPUT_GET, 's', FILTER_VALIDATE_INT, ['options' => ['flags' => FILTER_NULL_ON_FAILURE]]);
if (!is_null($station_id))
{
$sid = strval($station_id);
if (strlen($sid) >= 2)
{
$source_id = $sid[0];
$station_id = substr($sid, 1);
return StationRepository::getInstance()->getObjectById($station_id, $source_id);
}
}
return new Station(0);
}
// Legacy ID format
else
{
$station_id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, ['options' => ['flags' => FILTER_NULL_ON_FAILURE]]);
return StationRepository::getInstance()->getObjectById($station_id);
}
return new Station(0);
}