mirror of https://github.com/LX3JL/xlxd.git
parent
7176e44386
commit
37a79a95a0
@ -0,0 +1,190 @@
|
||||
body {
|
||||
margin : 0px;
|
||||
padding : 0px;
|
||||
background-color : #D3D3D3;
|
||||
font-family : calibri, verdana, arial, comic sans;
|
||||
min-width : 760px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size : 25pt;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
a.tip {
|
||||
text-decoration : none;
|
||||
}
|
||||
|
||||
a.tip:hover {
|
||||
position : relative;
|
||||
}
|
||||
|
||||
a.tip span {
|
||||
display : none
|
||||
}
|
||||
|
||||
a.tip:hover span {
|
||||
background : #000000;
|
||||
opacity : 0.8;
|
||||
border : none;
|
||||
border-radius : 5px 5px 5px 5px;
|
||||
font-family : calibri, verdana, arial, comic sans;
|
||||
font-size : 12pt;
|
||||
text-decoration : none;
|
||||
white-space : nowrap;
|
||||
color : #FFFFFF;
|
||||
padding : 6px 6px 6px 6px;
|
||||
margin : 10px;
|
||||
display : block;
|
||||
z-index : 50;
|
||||
position : absolute;
|
||||
top : 10px;
|
||||
}
|
||||
|
||||
#top {
|
||||
height : 115px;
|
||||
background-color : #FFFFFF;
|
||||
width : 100%;
|
||||
background-image : url('../img/dvc.jpg');
|
||||
background-repeat : no-repeat;
|
||||
background-position : 98.5%;
|
||||
position : absolute;
|
||||
left : 0px;
|
||||
top : 0px;
|
||||
min-width : 760px;
|
||||
}
|
||||
|
||||
#menu {
|
||||
margin-top : 5px;
|
||||
height : 34px;
|
||||
float : left;
|
||||
}
|
||||
|
||||
#menubar {
|
||||
height : 40px;
|
||||
width : 100%;
|
||||
background-color : #FEC456;
|
||||
position : absolute;
|
||||
left : 0px;
|
||||
top : 115px;
|
||||
min-width : 760px;
|
||||
}
|
||||
|
||||
#content {
|
||||
width : 100%;
|
||||
position : absolute;
|
||||
left : 0px;
|
||||
top : 175px;
|
||||
}
|
||||
|
||||
.menulink {
|
||||
font-size : 14pt;
|
||||
text-decoration : none;
|
||||
white-space : nowrap;
|
||||
border : 1px #000000 solid;
|
||||
padding-left : 10px;
|
||||
padding-top : 3px;
|
||||
padding-bottom : 3px;
|
||||
padding-right : 10px;
|
||||
margin-left : 10px;
|
||||
background-color : #FFFFC6;
|
||||
color : #000000;
|
||||
}
|
||||
|
||||
.menulinkactive {
|
||||
font-size : 14pt;
|
||||
text-decoration : none;
|
||||
white-space : nowrap;
|
||||
border : 1px #000000 solid;
|
||||
padding-left : 10px;
|
||||
padding-top : 3px;
|
||||
padding-bottom : 3px;
|
||||
padding-right : 10px;
|
||||
margin-left : 10px;
|
||||
background-color : #87dcfc;
|
||||
color : #000000;
|
||||
}
|
||||
|
||||
.pl {
|
||||
font-size : 12pt;
|
||||
text-decoration : none;
|
||||
color : #000000;
|
||||
}
|
||||
|
||||
.listingtable {
|
||||
margin-top : 10px;
|
||||
border : 1px #C1DAD7 solid;
|
||||
font-size : 12pt;
|
||||
}
|
||||
|
||||
.listingtable th {
|
||||
height : 35px;
|
||||
text-align : center;
|
||||
background-color : #D5EBF0;
|
||||
background-image : -webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
left bottom,
|
||||
color-stop(0, rgb(201, 231, 233)),
|
||||
color-stop(0.8, rgb(220, 237, 244))
|
||||
);
|
||||
background-image: -o-linear-gradient(bottom, rgb(201, 231, 233) 0%, rgb(220, 237, 244) 80%);
|
||||
background-image: -moz-linear-gradient(bottom, rgb(201, 231, 233) 0%, rgb(220, 237, 244) 80%);
|
||||
background-image: -webkit-linear-gradient(bottom, rgb(201, 231, 233) 0%, rgb(220, 237, 244) 80%);
|
||||
background-image: -ms-linear-gradient(bottom, rgb(201, 231, 233) 0%, rgb(220, 237, 244) 80%);
|
||||
background-image: linear-gradient(to bottom, rgb(201, 231, 233) 0%, rgb(220, 237, 244) 80%);
|
||||
}
|
||||
|
||||
.listingtable td {
|
||||
padding-left : 5px;
|
||||
}
|
||||
|
||||
.listinglink {
|
||||
font-size : 12pt;
|
||||
text-decoration : underline;
|
||||
color : #60A1DE;
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size : 12pt;
|
||||
text-decoration : none,
|
||||
font-weight : bold;
|
||||
color : #FF0000;
|
||||
background-color : #FFFFFF;
|
||||
width : 90%;
|
||||
padding : 15px;
|
||||
margin : 5px;
|
||||
}
|
||||
|
||||
.FilterField {
|
||||
font-size : 10pt;
|
||||
text-decoration : none,
|
||||
color : #000000;
|
||||
background-color : #FFFFFF;
|
||||
width : 150px;
|
||||
height : 20px;
|
||||
padding-left : 5px;
|
||||
padding-top : 3px;
|
||||
border : 1px #60A1DE solid;
|
||||
}
|
||||
|
||||
.FilterSubmit {
|
||||
font-size : 10pt;
|
||||
text-decoration : none,
|
||||
color : #000000;
|
||||
background-color : #FFFFFF;
|
||||
height : 26px;
|
||||
width : 60px;
|
||||
padding-left : 5px;
|
||||
padding-top : 3px;
|
||||
border : 1px #60A1DE solid;
|
||||
}
|
||||
|
||||
.smalllink {
|
||||
font-size : 12pt;
|
||||
text-decoration : none;
|
||||
color : #0E0789;
|
||||
}
|
||||
|
After Width: | Height: | Size: 21 KiB |
@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
// Secure session configuration
|
||||
ini_set('session.cookie_httponly', 1);
|
||||
ini_set('session.cookie_samesite', 'Strict');
|
||||
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
|
||||
ini_set('session.cookie_secure', 1);
|
||||
}
|
||||
|
||||
session_start();
|
||||
|
||||
// Security headers
|
||||
header("X-Content-Type-Options: nosniff");
|
||||
header("X-Frame-Options: SAMEORIGIN");
|
||||
header("X-XSS-Protection: 1; mode=block");
|
||||
header("Referrer-Policy: strict-origin-when-cross-origin");
|
||||
|
||||
if (file_exists("./pgs/functions.php")) { require_once("./pgs/functions.php"); } else { die("functions.php does not exist."); }
|
||||
if (file_exists("./pgs/config.inc.php")) { require_once("./pgs/config.inc.php"); } else { die("config.inc.php does not exist."); }
|
||||
|
||||
if (!class_exists('ParseXML')) require_once("./pgs/class.parsexml.php");
|
||||
if (!class_exists('Node')) require_once("./pgs/class.node.php");
|
||||
if (!class_exists('xReflector')) require_once("./pgs/class.reflector.php");
|
||||
if (!class_exists('Station')) require_once("./pgs/class.station.php");
|
||||
if (!class_exists('Peer')) require_once("./pgs/class.peer.php");
|
||||
if (!class_exists('Interlink')) require_once("./pgs/class.interlink.php");
|
||||
|
||||
// Validate 'show' parameter
|
||||
$allowed_pages = ['users', 'repeaters', 'liveircddb', 'peers', 'modules', 'reflectors', 'traffic'];
|
||||
if (!isset($_GET['show'])) {
|
||||
$_GET['show'] = '';
|
||||
} elseif (!in_array($_GET['show'], $allowed_pages, true)) {
|
||||
$_GET['show'] = '';
|
||||
}
|
||||
|
||||
// Validate 'do' parameter for filter resets
|
||||
if (isset($_GET['do']) && $_GET['do'] !== 'resetfilter') {
|
||||
unset($_GET['do']);
|
||||
}
|
||||
|
||||
// Validate 'callhome' parameter
|
||||
if (isset($_GET['callhome'])) {
|
||||
$_GET['callhome'] = filter_var($_GET['callhome'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||
if ($_GET['callhome'] === null) {
|
||||
unset($_GET['callhome']);
|
||||
}
|
||||
}
|
||||
|
||||
$Reflector = new xReflector();
|
||||
$Reflector->SetFlagFile("./pgs/country.csv");
|
||||
$Reflector->SetPIDFile($Service['PIDFile']);
|
||||
$Reflector->SetXMLFile($Service['XMLFile']);
|
||||
|
||||
$Reflector->LoadXML();
|
||||
|
||||
if ($CallingHome['Active']) {
|
||||
|
||||
$CallHomeNow = false;
|
||||
$LastSync = 0;
|
||||
$Hash = "";
|
||||
|
||||
if (!file_exists($CallingHome['HashFile'])) {
|
||||
$Ressource = fopen($CallingHome['HashFile'], "w+");
|
||||
if ($Ressource) {
|
||||
$Hash = CreateCode(16);
|
||||
@fwrite($Ressource, "<?php\n");
|
||||
@fwrite($Ressource, "\n".'$Hash = "'.$Hash.'";');
|
||||
@fwrite($Ressource, "\n\n".'?>');
|
||||
@fflush($Ressource);
|
||||
@fclose($Ressource);
|
||||
@chmod($HashFile, 0777);
|
||||
}
|
||||
}
|
||||
else {
|
||||
require_once($CallingHome['HashFile']);
|
||||
}
|
||||
|
||||
if (@file_exists($CallingHome['LastCallHomefile'])) {
|
||||
if (@is_readable($CallingHome['LastCallHomefile'])) {
|
||||
$tmp = @file($CallingHome['LastCallHomefile']);
|
||||
if (isset($tmp[0])) {
|
||||
$LastSync = $tmp[0];
|
||||
}
|
||||
unset($tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if ($LastSync < (time() - $CallingHome['PushDelay'])) {
|
||||
$CallHomeNow = true;
|
||||
$Ressource = @fopen($CallingHome['LastCallHomefile'], "w+");
|
||||
if ($Ressource) {
|
||||
@fwrite($Ressource, time());
|
||||
@fflush($Ressource);
|
||||
@fclose($Ressource);
|
||||
@chmod($HashFile, 0777);
|
||||
}
|
||||
}
|
||||
|
||||
if ($CallHomeNow || isset($_GET['callhome'])) {
|
||||
$Reflector->SetCallingHome($CallingHome, $Hash);
|
||||
$Reflector->ReadInterlinkFile();
|
||||
$Reflector->PrepareInterlinkXML();
|
||||
$Reflector->PrepareReflectorXML();
|
||||
$Reflector->CallHome();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
$Hash = "";
|
||||
}
|
||||
|
||||
|
||||
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta name="description" content="<?php echo sanitize_attribute($PageOptions['MetaDescription']); ?>" />
|
||||
<meta name="keywords" content="<?php echo sanitize_attribute($PageOptions['MetaKeywords']); ?>" />
|
||||
<meta name="author" content="<?php echo sanitize_attribute($PageOptions['MetaAuthor']); ?>" />
|
||||
<meta name="revisit" content="<?php echo sanitize_attribute($PageOptions['MetaRevisit']); ?>" />
|
||||
<meta name="robots" content="<?php echo sanitize_attribute($PageOptions['MetaRobots']); ?>" />
|
||||
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title><?php echo sanitize_output($Reflector->GetReflectorName()); ?> Reflector Dashboard</title>
|
||||
<link rel="stylesheet" type="text/css" href="./css/layout.css">
|
||||
<link rel="icon" href="./favicon.ico" type="image/vnd.microsoft.icon"><?php
|
||||
|
||||
if ($PageOptions['PageRefreshActive']) {
|
||||
echo '
|
||||
<script src="./js/jquery-1.12.4.min.js"></script>
|
||||
<script>
|
||||
var PageRefresh;
|
||||
|
||||
function ReloadPage() {
|
||||
$.get("./index.php'.((!empty($_GET['show'])) ? '?show='.urlencode($_GET['show']) : '').'", function(data) {
|
||||
var BodyStart = data.indexOf("<bo"+"dy");
|
||||
var BodyEnd = data.indexOf("</bo"+"dy>");
|
||||
if ((BodyStart >= 0) && (BodyEnd > BodyStart)) {
|
||||
BodyStart = data.indexOf(">", BodyStart)+1;
|
||||
$("body").html(data.substring(BodyStart, BodyEnd));
|
||||
}
|
||||
})
|
||||
.always(function() {
|
||||
PageRefresh = setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');
|
||||
});
|
||||
}';
|
||||
|
||||
if (!isset($_GET['show']) || (($_GET['show'] != 'liveircddb') && ($_GET['show'] != 'reflectors') && ($_GET['show'] != 'interlinks'))) {
|
||||
echo '
|
||||
PageRefresh = setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');';
|
||||
}
|
||||
echo '
|
||||
|
||||
function SuspendPageRefresh() {
|
||||
clearTimeout(PageRefresh);
|
||||
}
|
||||
</script>';
|
||||
}
|
||||
|
||||
if (!isset($_GET['show'])) $_GET['show'] = "";
|
||||
?>
|
||||
</head>
|
||||
<body>
|
||||
<?php if (file_exists("./tracking.php")) { include_once("tracking.php"); }?>
|
||||
<div id="top"><img src="./img/header.jpg" alt="XLX Multiprotocol Gateway Reflector" style="margin-top:15px;" />
|
||||
<br /> <?php echo sanitize_output($Reflector->GetReflectorName()); ?> v<?php echo sanitize_output($Reflector->GetVersion()); ?> - Dashboard v<?php echo sanitize_output($PageOptions['DashboardVersion']); ?> <?php echo sanitize_output($PageOptions['CustomTXT']); ?> / Service uptime: <span id="suptime"><?php echo FormatSeconds($Reflector->GetServiceUptime()); ?></span></div>
|
||||
<div id="menubar">
|
||||
<div id="menu">
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td><a href="./index.php" class="menulink<?php if ($_GET['show'] == '') { echo 'active'; } ?>">Users / Modules</a></td>
|
||||
<td><a href="./index.php?show=repeaters" class="menulink<?php if ($_GET['show'] == 'repeaters') { echo 'active'; } ?>">Repeaters / Nodes (<?php echo intval($Reflector->NodeCount()); ?>)</a></td>
|
||||
<td><a href="./index.php?show=peers" class="menulink<?php if ($_GET['show'] == 'peers') { echo 'active'; } ?>">Peers (<?php echo intval($Reflector->PeerCount()); ?>)</a></td>
|
||||
<td><a href="./index.php?show=modules" class="menulink<?php if ($_GET['show'] == 'modules') { echo 'active'; } ?>">Modules list</a></td>
|
||||
<td><a href="./index.php?show=reflectors" class="menulink<?php if ($_GET['show'] == 'reflectors') { echo 'active'; } ?>">Reflectors list</a></td>
|
||||
<?php
|
||||
|
||||
if ($PageOptions['Traffic']['Show']) {
|
||||
echo '
|
||||
<td><a href="./index.php?show=traffic" class="menulink';
|
||||
if ($_GET['show'] == 'traffic') { echo 'active'; }
|
||||
echo '">Traffic statistics</a></td>';
|
||||
}
|
||||
if ($PageOptions['IRCDDB']['Show']) {
|
||||
echo '
|
||||
<td><a href="./index.php?show=liveircddb" class="menulink';
|
||||
if ($_GET['show'] == 'liveircddb') { echo 'active'; }
|
||||
echo '">D-Star live</a></td>';
|
||||
}
|
||||
|
||||
?>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content" align="center">
|
||||
|
||||
<?php
|
||||
if ($CallingHome['Active']) {
|
||||
if (!is_readable($CallingHome['HashFile']) && (!is_writeable($CallingHome['HashFile']))) {
|
||||
echo '
|
||||
<div class="error">
|
||||
your private hash in '.sanitize_output($CallingHome['HashFile']).' could not be created, please check your config file and the permissions for the defined folder.
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
|
||||
switch ($_GET['show']) {
|
||||
case 'users' : require_once("./pgs/users.php"); break;
|
||||
case 'repeaters' : require_once("./pgs/repeaters.php"); break;
|
||||
case 'liveircddb' : require_once("./pgs/liveircddb.php"); break;
|
||||
case 'peers' : require_once("./pgs/peers.php"); break;
|
||||
case 'modules' : require_once("./pgs/modules.php"); break;
|
||||
case 'reflectors' : require_once("./pgs/reflectors.php"); break;
|
||||
case 'traffic' : require_once("./pgs/traffic.php"); break;
|
||||
default : require_once("./pgs/users.php");
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div style="width:100%;text-align:center;margin-top:50px;"><a href="mailto:<?php echo sanitize_attribute($PageOptions['ContactEmail']); ?>" style="font-family:verdana;color:#000000;font-size:12pt;text-decoration:none;"><?php echo sanitize_output($PageOptions['ContactEmail']); ?></a></div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
if (isset($_POST['password'])) {
|
||||
$_SESSION['password'] = $_POST['password'];
|
||||
}
|
||||
|
||||
if (isset($_SESSION['password'])) {
|
||||
|
||||
if ($_SESSION['password'] != "-D-Star+") {
|
||||
echo '
|
||||
<form name="frmpass" action="./xlxlog.php" method="post">
|
||||
|
||||
<input type="password" name="password" />
|
||||
<input type="submit" />
|
||||
|
||||
</form>';
|
||||
|
||||
die();
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo '
|
||||
<form name="frmpass" action="./xlxlog.php" method="post">
|
||||
|
||||
<input type="password" name="password" />
|
||||
<input type="submit" />
|
||||
|
||||
</form>';
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>XLX Live Log</title>
|
||||
<script>
|
||||
|
||||
function ReloadPage() {
|
||||
document.location.href = "./xlxlog.php";
|
||||
}
|
||||
|
||||
setTimeout(ReloadPage, 1000);
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre>
|
||||
|
||||
<?php
|
||||
$a = array();
|
||||
$handle = fopen("/var/log/messages","r");
|
||||
if ($handle) {
|
||||
while(!feof($handle)) {
|
||||
$a[] = fgets($handle, 1024);
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
$a = array_reverse($a);
|
||||
|
||||
$max = 65;
|
||||
if (count($a) < 65) $max = count($a);
|
||||
|
||||
for ($i=0;$i<$max;$i++) {
|
||||
echo $a[$i];
|
||||
}
|
||||
|
||||
?>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
class Interlink {
|
||||
|
||||
private $ReflectorName;
|
||||
private $ReflectorAddress;
|
||||
private $Modules;
|
||||
|
||||
public function __construct() {
|
||||
$this->ReflectorName = null;
|
||||
$this->ReflectorAddress = null;
|
||||
$this->Modules = null;
|
||||
}
|
||||
|
||||
public function SetName($RefName) {
|
||||
$RefName = trim($RefName);
|
||||
// Validate reflector name format (XLX + 3 alphanumeric)
|
||||
if (preg_match('/^[A-Z0-9]{3,10}$/i', $RefName)) {
|
||||
$this->ReflectorName = strtoupper($RefName);
|
||||
}
|
||||
}
|
||||
public function SetAddress($RefAdd) {
|
||||
$RefAdd = trim($RefAdd);
|
||||
// Validate it's a valid hostname or IP
|
||||
if (filter_var($RefAdd, FILTER_VALIDATE_IP) ||
|
||||
filter_var($RefAdd, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
|
||||
$this->ReflectorAddress = $RefAdd;
|
||||
}
|
||||
}
|
||||
public function GetName() { return $this->ReflectorName; }
|
||||
public function GetAddress() { return $this->ReflectorAddress; }
|
||||
public function GetModules() { return $this->Modules; }
|
||||
|
||||
|
||||
public function AddModule($Module) {
|
||||
$Module = trim(strtoupper($Module));
|
||||
if (strlen($Module) != 1) return false;
|
||||
if (!preg_match('/^[A-Z]$/', $Module)) return false; // Only A-Z
|
||||
if (strpos($this->Modules, $Module) === false) {
|
||||
$this->Modules .= $Module;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function RemoveModule($Module) {
|
||||
$Module = trim(strtoupper($Module));
|
||||
if (strlen($Module) != 1) return false;
|
||||
if (!preg_match('/^[A-Z]$/', $Module)) return false; // Only A-Z
|
||||
if (strpos($this->Modules, $Module) !== false) {
|
||||
$this->Modules = str_replace($Module, '', $this->Modules);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function HasModuleEnabled($Module) {
|
||||
$Module = trim(strtoupper($Module));
|
||||
if (strlen($Module) != 1 || !preg_match('/^[A-Z]$/', $Module)) {
|
||||
return false;
|
||||
}
|
||||
return (strpos($this->Modules, $Module) !== false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
class Node {
|
||||
|
||||
private $Callsign;
|
||||
private $IP;
|
||||
private $LinkedModule;
|
||||
private $Protocol;
|
||||
private $ConnectTime;
|
||||
private $LastHeardTime;
|
||||
private $Suffix;
|
||||
private $Prefix;
|
||||
private $RandomID;
|
||||
|
||||
public function __construct($Callsign, $IP, $LinkedModule, $Protocol, $ConnectTime, $LastHeardTime, $RandomID) {
|
||||
|
||||
// Validate and sanitize IP
|
||||
$IP = trim($IP);
|
||||
$this->IP = filter_var($IP, FILTER_VALIDATE_IP) ? $IP : '0.0.0.0';
|
||||
|
||||
// Validate protocol
|
||||
$Protocol = trim($Protocol);
|
||||
$allowed_protocols = ['DPlus', 'DExtra', 'DCS', 'DMR', 'YSF', 'DEXTRA', 'DPLUS', 'DMRMmdvm'];
|
||||
$this->Protocol = in_array($Protocol, $allowed_protocols, true) ? $Protocol : 'Unknown';
|
||||
|
||||
$this->ConnectTime = ParseTime($ConnectTime);
|
||||
$this->LastHeardTime = ParseTime($LastHeardTime);
|
||||
|
||||
// Sanitize callsign (remove excessive spaces, validate format)
|
||||
$Callsign = trim(preg_replace('/\s+/', ' ', $Callsign));
|
||||
|
||||
$this->FullCallsign = str_replace(" ", "-", $Callsign);
|
||||
|
||||
if (strpos($Callsign, " ") !== false) {
|
||||
$this->Callsign = trim(substr($Callsign, 0, strpos($Callsign, " ")));
|
||||
$this->Suffix = trim(substr($Callsign, strpos($Callsign, " ")));
|
||||
$this->Prefix = strtoupper(trim(substr($Callsign, 0, 3)));
|
||||
}
|
||||
else {
|
||||
$this->Callsign = trim($Callsign);
|
||||
$this->Suffix = "";
|
||||
$this->Prefix = "";
|
||||
}
|
||||
|
||||
// Validate callsign format (basic check)
|
||||
if (!preg_match('/^[A-Z0-9]{1,10}$/i', $this->Callsign)) {
|
||||
$this->Callsign = 'INVALID';
|
||||
}
|
||||
|
||||
// Validate LinkedModule (single letter A-Z)
|
||||
$LinkedModule = trim(strtoupper($LinkedModule));
|
||||
$this->LinkedModule = preg_match('/^[A-Z]$/', $LinkedModule) ? $LinkedModule : '';
|
||||
|
||||
$this->RandomID = $RandomID;
|
||||
}
|
||||
|
||||
public function GetFullCallsign() { return $this->FullCallsign; }
|
||||
public function GetCallsign() { return $this->Callsign; }
|
||||
public function GetIP() { return $this->IP; }
|
||||
public function GetLinkedModule() { return $this->LinkedModule; }
|
||||
public function GetProtocol() { return $this->Protocol; }
|
||||
public function GetConnectTime() { return $this->ConnectTime; }
|
||||
public function GetLastHeardTime() { return $this->LastHeardTime; }
|
||||
public function GetSuffix() { return $this->Suffix; }
|
||||
public function GetPrefix() { return $this->Prefix; }
|
||||
public function GetRandomID() { return $this->RandomID; }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
class ParseXML {
|
||||
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetElement($InputString, $ElementName) {
|
||||
// Sanitize element name to prevent XML injection
|
||||
$ElementName = preg_replace('/[^a-zA-Z0-9_\-\s]/', '', $ElementName);
|
||||
|
||||
if (strpos($InputString, "<".$ElementName.">") === false) return false;
|
||||
if (strpos($InputString, "</".$ElementName.">") === false) return false;
|
||||
|
||||
$Element = substr($InputString, strpos($InputString, "<".$ElementName.">")+strlen($ElementName)+2, strpos($InputString, "</".$ElementName.">")-strpos($InputString, "<".$ElementName.">")-strlen($ElementName)-2);
|
||||
|
||||
// Return raw content - sanitization happens at output time
|
||||
return $Element;
|
||||
}
|
||||
|
||||
public function GetAllElements($InputString, $ElementName) {
|
||||
// Sanitize element name to prevent XML injection
|
||||
$ElementName = preg_replace('/[^a-zA-Z0-9_\-\s]/', '', $ElementName);
|
||||
|
||||
$Elements = array();
|
||||
while (strpos($InputString, $ElementName) !== false) {
|
||||
$element = $this->GetElement($InputString, $ElementName);
|
||||
if ($element !== false) {
|
||||
$Elements[] = $element;
|
||||
}
|
||||
$InputString = substr($InputString, strpos($InputString, "</".$ElementName.">")+strlen($ElementName)+3, strlen($InputString));
|
||||
}
|
||||
return $Elements;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
class Peer {
|
||||
|
||||
private $Callsign;
|
||||
private $IP;
|
||||
private $LinkedModule;
|
||||
private $Protocol;
|
||||
private $ConnectTime;
|
||||
private $LastHeardTime;
|
||||
|
||||
public function __construct($Callsign, $IP, $LinkedModule, $Protocol, $ConnectTime, $LastHeardTime) {
|
||||
|
||||
// Validate and sanitize IP
|
||||
$IP = trim($IP);
|
||||
$this->IP = filter_var($IP, FILTER_VALIDATE_IP) ? $IP : '0.0.0.0';
|
||||
|
||||
// Validate protocol
|
||||
$Protocol = trim($Protocol);
|
||||
$allowed_protocols = ['DPlus', 'DExtra', 'DCS', 'DMR', 'YSF', 'DEXTRA', 'DPLUS', 'XLX'];
|
||||
$this->Protocol = in_array($Protocol, $allowed_protocols, true) ? $Protocol : 'Unknown';
|
||||
|
||||
$this->ConnectTime = ParseTime($ConnectTime);
|
||||
$this->LastHeardTime = ParseTime($LastHeardTime);
|
||||
|
||||
// Sanitize and validate callsign
|
||||
$Callsign = trim($Callsign);
|
||||
if (preg_match('/^[A-Z0-9]{3,10}$/i', $Callsign)) {
|
||||
$this->Callsign = strtoupper($Callsign);
|
||||
} else {
|
||||
$this->Callsign = 'INVALID';
|
||||
}
|
||||
|
||||
// Validate LinkedModule (single letter A-Z)
|
||||
$LinkedModule = trim(strtoupper($LinkedModule));
|
||||
$this->LinkedModule = preg_match('/^[A-Z]$/', $LinkedModule) ? $LinkedModule : '';
|
||||
}
|
||||
|
||||
|
||||
public function GetCallsign() { return $this->Callsign; }
|
||||
public function GetIP() { return $this->IP; }
|
||||
public function GetLinkedModule() { return $this->LinkedModule; }
|
||||
public function GetProtocol() { return $this->Protocol; }
|
||||
public function GetConnectTime() { return $this->ConnectTime; }
|
||||
public function GetLastHeardTime() { return $this->LastHeardTime; }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,556 @@
|
||||
<?php
|
||||
|
||||
class xReflector {
|
||||
|
||||
public $Nodes = null;
|
||||
public $Stations = null;
|
||||
public $Peers = null;
|
||||
private $Flagarray = null;
|
||||
private $Flagarray_DXCC = null;
|
||||
private $Flagfile = null;
|
||||
private $CallingHomeActive = null;
|
||||
private $CallingHomeHash = null;
|
||||
private $CallingHomeDashboardURL = null;
|
||||
private $CallingHomeServerURL = null;
|
||||
private $ReflectorName = null;
|
||||
private $ServiceUptime = null;
|
||||
private $ProcessIDFile = null;
|
||||
private $XMLContent = null;
|
||||
private $XMLFile = null;
|
||||
private $ServiceName = null;
|
||||
private $Version = null;
|
||||
private $CallingHomeCountry = null;
|
||||
private $CallingHomeComment = null;
|
||||
private $CallingHomeOverrideIP = null;
|
||||
private $Transferinterlink = null;
|
||||
private $Interlinkfile = null;
|
||||
public $Interlinks = null;
|
||||
private $InterlinkXML = null;
|
||||
private $ReflectorXML = null;
|
||||
|
||||
public function __construct() {
|
||||
$this->Nodes = array();
|
||||
$this->Stations = array();
|
||||
$this->Peers = array();
|
||||
$this->Interlinks = array();
|
||||
$this->Transferinterlink = false;
|
||||
}
|
||||
|
||||
public function LoadXML() {
|
||||
if ($this->XMLFile != null) {
|
||||
$handle = fopen($this->XMLFile, 'r');
|
||||
$this->XMLContent = fread($handle, filesize($this->XMLFile));
|
||||
fclose($handle);
|
||||
|
||||
# XLX alphanumeric naming...
|
||||
$this->ServiceName = substr($this->XMLContent, strpos($this->XMLContent, "<XLX")+4, 3);
|
||||
|
||||
// Validate service name
|
||||
if (!preg_match('/^[a-zA-Z0-9]{3}$/', $this->ServiceName)) {
|
||||
$this->ServiceName = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->ReflectorName = "XLX".$this->ServiceName;
|
||||
|
||||
$LinkedPeersName = "XLX".$this->ServiceName." linked peers";
|
||||
$LinkedNodesName = "XLX".$this->ServiceName." linked nodes";
|
||||
$LinkedUsersName = "XLX".$this->ServiceName." heard users";
|
||||
|
||||
$XML = new ParseXML();
|
||||
|
||||
$AllNodesString = $XML->GetElement($this->XMLContent, $LinkedNodesName);
|
||||
$tmpNodes = $XML->GetAllElements($AllNodesString, "NODE");
|
||||
|
||||
for ($i=0;$i<count($tmpNodes);$i++) {
|
||||
$Node = new Node(
|
||||
$XML->GetElement($tmpNodes[$i], 'Callsign'),
|
||||
$XML->GetElement($tmpNodes[$i], 'IP'),
|
||||
$XML->GetElement($tmpNodes[$i], 'LinkedModule'),
|
||||
$XML->GetElement($tmpNodes[$i], 'Protocol'),
|
||||
$XML->GetElement($tmpNodes[$i], 'ConnectTime'),
|
||||
$XML->GetElement($tmpNodes[$i], 'LastHeardTime'),
|
||||
CreateCode(16)
|
||||
);
|
||||
$this->AddNode($Node);
|
||||
}
|
||||
|
||||
$AllStationsString = $XML->GetElement($this->XMLContent, $LinkedUsersName);
|
||||
$tmpStations = $XML->GetAllElements($AllStationsString, "STATION");
|
||||
for ($i=0;$i<count($tmpStations);$i++) {
|
||||
$Station = new Station(
|
||||
$XML->GetElement($tmpStations[$i], 'Callsign'),
|
||||
$XML->GetElement($tmpStations[$i], 'Via node'),
|
||||
$XML->GetElement($tmpStations[$i], 'Via peer'),
|
||||
$XML->GetElement($tmpStations[$i], 'LastHeardTime'),
|
||||
$XML->GetElement($tmpStations[$i], 'On module')
|
||||
);
|
||||
$this->AddStation($Station, false);
|
||||
}
|
||||
|
||||
$AllPeersString = $XML->GetElement($this->XMLContent, $LinkedPeersName);
|
||||
$tmpPeers = $XML->GetAllElements($AllPeersString, "PEER");
|
||||
for ($i=0;$i<count($tmpPeers);$i++) {
|
||||
$Peer = new Peer(
|
||||
$XML->GetElement($tmpPeers[$i], 'Callsign'),
|
||||
$XML->GetElement($tmpPeers[$i], 'IP'),
|
||||
$XML->GetElement($tmpPeers[$i], 'LinkedModule'),
|
||||
$XML->GetElement($tmpPeers[$i], 'Protocol'),
|
||||
$XML->GetElement($tmpPeers[$i], 'ConnectTime'),
|
||||
$XML->GetElement($tmpPeers[$i], 'LastHeardTime')
|
||||
);
|
||||
$this->AddPeer($Peer, false);
|
||||
}
|
||||
|
||||
$this->Version = strip_tags($XML->GetElement($this->XMLContent, "Version"));
|
||||
}
|
||||
}
|
||||
|
||||
public function GetVersion() {
|
||||
return $this->Version;
|
||||
}
|
||||
|
||||
public function GetReflectorName() {
|
||||
return $this->ReflectorName;
|
||||
}
|
||||
|
||||
public function SetXMLFile($XMLFile) {
|
||||
// Prevent path traversal
|
||||
$XMLFile = basename($XMLFile);
|
||||
$XMLFile = '/var/log/' . $XMLFile; // Force it to expected directory
|
||||
|
||||
if (file_exists($XMLFile) && is_readable($XMLFile)) {
|
||||
$this->XMLFile = $XMLFile;
|
||||
}
|
||||
else {
|
||||
error_log("XML File ".$XMLFile." does not exist or is not readable");
|
||||
$this->XMLFile = null;
|
||||
$this->XMLContent = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetPIDFile($ProcessIDFile) {
|
||||
// Prevent path traversal
|
||||
$ProcessIDFile = basename($ProcessIDFile);
|
||||
$ProcessIDFile = '/var/log/' . $ProcessIDFile;
|
||||
|
||||
if (file_exists($ProcessIDFile)) {
|
||||
$this->ProcessIDFile = $ProcessIDFile;
|
||||
$this->ServiceUptime = time() - filectime($ProcessIDFile);
|
||||
}
|
||||
else {
|
||||
$this->ProcessIDFile = null;
|
||||
$this->ServiceUptime = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetServiceUptime() {
|
||||
return $this->ServiceUptime;
|
||||
}
|
||||
|
||||
public function SetFlagFile($Flagfile) {
|
||||
// Security: Only allow country.csv from the pgs directory
|
||||
$expectedFile = dirname(__FILE__) . '/country.csv';
|
||||
$realPath = realpath($Flagfile);
|
||||
|
||||
// Must resolve to the exact expected file
|
||||
if ($realPath !== $expectedFile) {
|
||||
error_log("Flag file must be country.csv in pgs directory. Expected: " . $expectedFile . ", Got: " . $realPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_exists($realPath) && is_readable($realPath)) {
|
||||
$this->Flagfile = $realPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
error_log("Flag file not readable: " . $realPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
public function LoadFlags() {
|
||||
if ($this->Flagfile != null) {
|
||||
$this->Flagarray = array();
|
||||
$this->Flagarray_DXCC = array();
|
||||
$handle = fopen($this->Flagfile,"r");
|
||||
if ($handle) {
|
||||
$i = 0;
|
||||
while(!feof($handle)) {
|
||||
$row = fgets($handle,1024);
|
||||
$tmp = explode(";", $row);
|
||||
|
||||
if (isset($tmp[0])) { $this->Flagarray[$i]['Country'] = $tmp[0]; } else { $this->Flagarray[$i]['Country'] = 'Undefined'; }
|
||||
if (isset($tmp[1])) { $this->Flagarray[$i]['ISO'] = $tmp[1]; } else { $this->Flagarray[$i]['ISO'] = "Undefined"; }
|
||||
//$this->Flagarray[$i]['DXCC'] = array();
|
||||
if (isset($tmp[2])) {
|
||||
$tmp2 = explode("-", $tmp[2]);
|
||||
for ($j=0;$j<count($tmp2);$j++) {
|
||||
//$this->Flagarray[$i]['DXCC'][] = $tmp2[$j];
|
||||
$this->Flagarray_DXCC[ trim($tmp2[$j]) ] = $i;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function AddNode($NodeObject) {
|
||||
if (is_object($NodeObject)) {
|
||||
$this->Nodes[] = $NodeObject;
|
||||
}
|
||||
}
|
||||
|
||||
public function NodeCount() {
|
||||
return count($this->Nodes);
|
||||
}
|
||||
|
||||
public function GetNode($ArrayIndex) {
|
||||
if (isset($this->Nodes[$ArrayIndex])) {
|
||||
return $this->Nodes[$ArrayIndex];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function AddPeer($PeerObject) {
|
||||
if (is_object($PeerObject)) {
|
||||
$this->Peers[] = $PeerObject;
|
||||
}
|
||||
}
|
||||
|
||||
public function PeerCount() {
|
||||
return count($this->Peers);
|
||||
}
|
||||
|
||||
public function GetPeer($ArrayIndex) {
|
||||
if (isset($this->Peer[$ArrayIndex])) {
|
||||
return $this->Peer[$ArrayIndex];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function AddStation($StationObject, $AllowDouble = false) {
|
||||
if (is_object($StationObject)) {
|
||||
|
||||
if ($AllowDouble) {
|
||||
$this->Stations[] = $StationObject;
|
||||
}
|
||||
else {
|
||||
$FoundStationInList = false;
|
||||
$i = 0;
|
||||
|
||||
$tmp = explode(" ", $StationObject->GetCallsign());
|
||||
$RealCallsign = trim($tmp[0]);
|
||||
|
||||
while (!$FoundStationInList && $i<$this->StationCount()) {
|
||||
if ($this->Stations[$i]->GetCallsignOnly() == $RealCallsign) {
|
||||
$FoundStationInList = true;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if (!$FoundStationInList) {
|
||||
if (strlen(trim($RealCallsign)) > 3) {
|
||||
$this->Stations[] = $StationObject;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetSuffixOfRepeater($Repeater, $LinkedModul, $StartWithIndex = 0) {
|
||||
$suffix = "";
|
||||
$found = false;
|
||||
$i = $StartWithIndex;
|
||||
while (!$found && $i < $this->NodeCount()) {
|
||||
if ($this->Nodes[$i]->GetLinkedModule() == $LinkedModul) {
|
||||
if (strpos($this->Nodes[$i]->GetCallSign(), $Repeater) !== false) {
|
||||
$suffix = $this->Nodes[$i]->GetSuffix();
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return $suffix;
|
||||
}
|
||||
|
||||
public function GetCallsignAndSuffixByID($RandomId) {
|
||||
$suffix = "";
|
||||
$callsign = "";
|
||||
$i = 0;
|
||||
while ($i < $this->NodeCount()) {
|
||||
if ($this->Nodes[$i]->GetRandomID() == $RandomId) {
|
||||
if (trim($this->Nodes[$i]->GetSuffix()) == "") {
|
||||
return $this->Nodes[$i]->GetCallSign();
|
||||
}
|
||||
else {
|
||||
return $this->Nodes[$i]->GetCallSign().'-'.$this->Nodes[$i]->GetSuffix();
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return 'N/A';
|
||||
}
|
||||
|
||||
public function StationCount() {
|
||||
return count($this->Stations);
|
||||
}
|
||||
|
||||
public function GetStation($ArrayIndex) {
|
||||
if (isset($this->Stations[$ArrayIndex])) {
|
||||
return $this->Stations[$ArrayIndex];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetFlag($Callsign) {
|
||||
$Image = "";
|
||||
$Letters = 4;
|
||||
$Name = "";
|
||||
while ($Letters >= 2) {
|
||||
$Prefix = substr(trim($Callsign), 0, $Letters);
|
||||
if (isset($this->Flagarray_DXCC[$Prefix])) {
|
||||
$Image = $this->Flagarray[ $this->Flagarray_DXCC[$Prefix] ]['ISO'];
|
||||
$Name = $this->Flagarray[ $this->Flagarray_DXCC[$Prefix] ]['Country'];
|
||||
break;
|
||||
}
|
||||
$Letters--;
|
||||
}
|
||||
return array(strtolower($Image), $Name);
|
||||
}
|
||||
|
||||
public function GetModules() {
|
||||
$out = array();
|
||||
for ($i=0;$i<$this->NodeCount();$i++) {
|
||||
$Found = false;
|
||||
$b = 0;
|
||||
while ($b < count($out) && !$Found) {
|
||||
if ($out[$b] == $this->Nodes[$i]->GetLinkedModule()) {
|
||||
$Found = true;
|
||||
}
|
||||
$b++;
|
||||
}
|
||||
if (!$Found && (trim($this->Nodes[$i]->GetLinkedModule()) != "")) {
|
||||
$out[] = $this->Nodes[$i]->GetLinkedModule();
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function GetModuleOfNode($Node) {
|
||||
die("FUNCTION DEPRECATED...");
|
||||
$Node = trim(str_replace(" ", "-", $Node));
|
||||
$Node = trim(str_replace(" ", "-", $Node));
|
||||
$Node = trim(str_replace(" ", "-", $Node));
|
||||
$found = false;
|
||||
$i = 0;
|
||||
$Module = "";
|
||||
while (!$found && $i<$this->NodeCount()) {
|
||||
if (strpos($Node, $this->Nodes[$i]->GetFullCallsign()) !== false) {
|
||||
$Module = $this->Nodes[$i]->GetLinkedModule();
|
||||
$found = true;
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
return $Module;
|
||||
}
|
||||
|
||||
public function GetCallSignsInModules($Module) {
|
||||
$out = array();
|
||||
for ($i=0;$i<$this->NodeCount();$i++) {
|
||||
if ($this->Nodes[$i]->GetLinkedModule() == $Module) {
|
||||
$out[] = $this->Nodes[$i]->GetCallsign();
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function GetNodesInModulesById($Module) {
|
||||
$out = array();
|
||||
for ($i=0;$i<$this->NodeCount();$i++) {
|
||||
if ($this->Nodes[$i]->GetLinkedModule() == $Module) {
|
||||
$out[] = $this->Nodes[$i]->GetRandomID();
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function SetCallingHome($CallingHomeVariables, $Hash) {
|
||||
|
||||
if (!isset($CallingHomeVariables['Active'])) { $CallingHomeVariables['Active'] = false; }
|
||||
if (!isset($CallingHomeVariables['MyDashBoardURL'])) { $CallingHomeVariables['MyDashBoardURL'] = ''; }
|
||||
if (!isset($CallingHomeVariables['ServerURL'])) { $CallingHomeVariables['ServerURL'] = ''; }
|
||||
if (!isset($CallingHomeVariables['Country'])) { $CallingHomeVariables['Country'] = ''; }
|
||||
if (!isset($CallingHomeVariables['Comment'])) { $CallingHomeVariables['Comment'] = ''; }
|
||||
if (!isset($CallingHomeVariables['OverrideIPAddress'])) { $CallingHomeVariables['OverrideIPAddress'] = false; }
|
||||
if (!isset($CallingHomeVariables['InterlinkFile'])) { $CallingHomeVariables['InterlinkFile'] = ''; }
|
||||
|
||||
// Validate URLs
|
||||
if (!empty($CallingHomeVariables['MyDashBoardURL'])) {
|
||||
if (filter_var($CallingHomeVariables['MyDashBoardURL'], FILTER_VALIDATE_URL) === false) {
|
||||
$CallingHomeVariables['MyDashBoardURL'] = '';
|
||||
}
|
||||
}
|
||||
if (!empty($CallingHomeVariables['ServerURL'])) {
|
||||
if (filter_var($CallingHomeVariables['ServerURL'], FILTER_VALIDATE_URL) === false) {
|
||||
$CallingHomeVariables['ServerURL'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_exists($CallingHomeVariables['InterlinkFile'])) {
|
||||
$this->Interlinkfile = '';
|
||||
$this->Transferinterlink = false;
|
||||
}
|
||||
else {
|
||||
$this->Transferinterlink = true;
|
||||
$this->Interlinkfile = $CallingHomeVariables['InterlinkFile'];
|
||||
}
|
||||
|
||||
$this->CallingHomeActive = ($CallingHomeVariables['Active'] === true);
|
||||
$this->CallingHomeHash = $Hash;
|
||||
$this->CallingHomeDashboardURL = $CallingHomeVariables['MyDashBoardURL'];
|
||||
$this->CallingHomeServerURL = $CallingHomeVariables['ServerURL'];
|
||||
$this->CallingHomeCountry = $CallingHomeVariables['Country'];
|
||||
$this->CallingHomeComment = $CallingHomeVariables['Comment'];
|
||||
$this->CallingHomeOverrideIP = $CallingHomeVariables['OverrideIPAddress'];
|
||||
|
||||
}
|
||||
|
||||
public function PushCallingHome() {
|
||||
$CallingHome = @fopen($this->CallingHomeServerURL."?ReflectorName=".$this->ReflectorName."&ReflectorUptime=".$this->ServiceUptime."&ReflectorHash=".$this->CallingHomeHash."&DashboardURL=".$this->CallingHomeDashboardURL."&Country=".urlencode($this->CallingHomeCountry)."&Comment=".urlencode($this->CallingHomeComment)."&OverrideIP=".$this->CallingHomeOverrideIP, "r");
|
||||
}
|
||||
|
||||
public function ReadInterlinkFile() {
|
||||
if (empty($this->Interlinkfile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent path traversal
|
||||
$realPath = realpath($this->Interlinkfile);
|
||||
if ($realPath === false || strpos($realPath, '/xlxd/') === false) {
|
||||
error_log("ReadInterlinkFile blocked - invalid path");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_exists($realPath) && is_readable($realPath)) {
|
||||
$this->Interlinks = array();
|
||||
$this->InterlinkXML = "";
|
||||
$Interlinkfilecontent = file($realPath);
|
||||
for ($i=0;$i<count($Interlinkfilecontent);$i++) {
|
||||
if (substr($Interlinkfilecontent[$i], 0, 1) != '#') {
|
||||
$Interlink = explode(" ", $Interlinkfilecontent[$i]);
|
||||
$this->Interlinks[] = new Interlink();
|
||||
if (isset($Interlink[0])) {
|
||||
$this->Interlinks[count($this->Interlinks)-1]->SetName(trim($Interlink[0]));
|
||||
}
|
||||
if (isset($Interlink[1])) {
|
||||
$this->Interlinks[count($this->Interlinks)-1]->SetAddress(trim($Interlink[1]));
|
||||
}
|
||||
if (isset($Interlink[2])) {
|
||||
$Modules = str_split(trim($Interlink[2]), 1);
|
||||
for ($j=0;$j<count($Modules);$j++) {
|
||||
$this->Interlinks[count($this->Interlinks)-1]->AddModule($Modules[$j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function PrepareInterlinkXML() {
|
||||
$xml = '
|
||||
<interlinks>';
|
||||
for ($i=0;$i<count($this->Interlinks);$i++) {
|
||||
$xml .= '
|
||||
<interlink>
|
||||
<name>'.htmlspecialchars($this->Interlinks[$i]->GetName(), ENT_XML1, 'UTF-8').'</name>
|
||||
<address>'.htmlspecialchars($this->Interlinks[$i]->GetAddress(), ENT_XML1, 'UTF-8').'</address>
|
||||
<modules>'.htmlspecialchars($this->Interlinks[$i]->GetModules(), ENT_XML1, 'UTF-8').'</modules>
|
||||
</interlink>';
|
||||
}
|
||||
$xml .= '
|
||||
</interlinks>';
|
||||
$this->InterlinkXML = $xml;
|
||||
}
|
||||
|
||||
public function PrepareReflectorXML() {
|
||||
$this->ReflectorXML = '
|
||||
<reflector>
|
||||
<name>'.htmlspecialchars($this->ReflectorName, ENT_XML1, 'UTF-8').'</name>
|
||||
<uptime>'.intval($this->ServiceUptime).'</uptime>
|
||||
<hash>'.htmlspecialchars($this->CallingHomeHash, ENT_XML1, 'UTF-8').'</hash>
|
||||
<url>'.htmlspecialchars($this->CallingHomeDashboardURL, ENT_XML1, 'UTF-8').'</url>
|
||||
<country>'.htmlspecialchars($this->CallingHomeCountry, ENT_XML1, 'UTF-8').'</country>
|
||||
<comment>'.htmlspecialchars($this->CallingHomeComment, ENT_XML1, 'UTF-8').'</comment>
|
||||
<ip>'.htmlspecialchars($this->CallingHomeOverrideIP, ENT_XML1, 'UTF-8').'</ip>
|
||||
<reflectorversion>'.htmlspecialchars($this->Version, ENT_XML1, 'UTF-8').'</reflectorversion>
|
||||
</reflector>';
|
||||
}
|
||||
|
||||
public function CallHome() {
|
||||
// Validate ServerURL is not localhost/internal IP
|
||||
$parsed = parse_url($this->CallingHomeServerURL);
|
||||
if (!isset($parsed['host'])) {
|
||||
error_log("CallHome failed - invalid URL");
|
||||
return false;
|
||||
}
|
||||
|
||||
$ip = gethostbyname($parsed['host']);
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
|
||||
error_log("CallHome blocked - internal/private IP detected");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sanitize all data being sent
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<query>CallingHome</query>'.$this->ReflectorXML.$this->InterlinkXML;
|
||||
|
||||
$p = @stream_context_create(array('http' => array(
|
||||
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
|
||||
'method' => 'POST',
|
||||
'content' => http_build_query(array('xml' => $xml)),
|
||||
'timeout' => 10
|
||||
)));
|
||||
|
||||
$result = @file_get_contents($this->CallingHomeServerURL, false, $p);
|
||||
if ($result === false) {
|
||||
error_log("CallHome connection failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function InterlinkCount() {
|
||||
return count($this->Interlinks);
|
||||
}
|
||||
|
||||
public function GetInterlink($Index) {
|
||||
if (isset($this->Interlinks[$Index])) {
|
||||
return $this->Interlinks[$Index];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function IsInterlinked($Reflectorname) {
|
||||
$i = -1;
|
||||
$f = false;
|
||||
while (!$f && $i < $this->InterlinkCount()) {
|
||||
$i++;
|
||||
if (isset($this->Interlinks[$i])) {
|
||||
if ($this->Interlinks[$i]->GetName() == $Reflectorname) {
|
||||
$f = true;
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
class Station {
|
||||
|
||||
private $Callsign;
|
||||
private $Via;
|
||||
private $LastHeardTime;
|
||||
private $Suffix;
|
||||
private $CallsignOnly;
|
||||
private $Peer;
|
||||
private $OnModule;
|
||||
|
||||
public function __construct($Callsign, $Via, $Peer, $LastHeardTime, $OnModule) {
|
||||
// Sanitize and validate callsign
|
||||
$Callsign = trim($Callsign);
|
||||
$this->Callsign = $Callsign;
|
||||
|
||||
// Sanitize Via and Peer
|
||||
$this->Via = trim($Via);
|
||||
$this->Peer = trim($Peer);
|
||||
|
||||
$this->LastHeardTime = ParseTime($LastHeardTime);
|
||||
|
||||
if (strpos($Callsign, " / ") !== false) {
|
||||
$this->Suffix = trim(substr($Callsign, strpos($Callsign, " / ")+3));
|
||||
}
|
||||
else {
|
||||
$this->Suffix = "";
|
||||
}
|
||||
|
||||
$tmp = explode(" ", $Callsign);
|
||||
$this->CallsignOnly = isset($tmp[0]) ? trim($tmp[0]) : '';
|
||||
|
||||
// Validate callsign format
|
||||
if (!empty($this->CallsignOnly) && !preg_match('/^[A-Z0-9]{1,10}$/i', $this->CallsignOnly)) {
|
||||
$this->CallsignOnly = 'INVALID';
|
||||
}
|
||||
|
||||
// Validate OnModule (single letter A-Z)
|
||||
$OnModule = trim(strtoupper($OnModule));
|
||||
$this->OnModule = preg_match('/^[A-Z]$/', $OnModule) ? $OnModule : '';
|
||||
}
|
||||
|
||||
public function GetCallsign() { return $this->Callsign; }
|
||||
public function GetVIA() { return $this->Via; }
|
||||
public function GetPeer() { return $this->Peer; }
|
||||
public function GetLastHeardTime() { return $this->LastHeardTime; }
|
||||
public function GetSuffix() { return $this->Suffix; }
|
||||
public function GetCallsignOnly() { return $this->CallsignOnly; }
|
||||
public function GetModule() { return $this->OnModule; }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/*
|
||||
Possible values for IPModus
|
||||
|
||||
HideIP
|
||||
ShowFullIP
|
||||
ShowLast1ByteOfIP
|
||||
ShowLast2ByteOfIP
|
||||
ShowLast3ByteOfIP
|
||||
|
||||
*/
|
||||
|
||||
$Service = array();
|
||||
$CallingHome = array();
|
||||
$PageOptions = array();
|
||||
$VNStat = array();
|
||||
|
||||
$PageOptions['ContactEmail'] = 'your_email'; // Support E-Mail address
|
||||
|
||||
$PageOptions['DashboardVersion'] = '2.4.3'; // Dashboard Version
|
||||
|
||||
$PageOptions['PageRefreshActive'] = true; // Activate automatic refresh
|
||||
$PageOptions['PageRefreshDelay'] = '10000'; // Page refresh time in miliseconds
|
||||
|
||||
$PageOptions['NumberOfModules'] = 10; // Number of Modules enabled on reflector
|
||||
|
||||
$PageOptions['RepeatersPage'] = array();
|
||||
$PageOptions['RepeatersPage']['LimitTo'] = 99; // Number of Repeaters to show
|
||||
$PageOptions['RepeatersPage']['IPModus'] = 'ShowFullIP'; // See possible options above
|
||||
$PageOptions['RepeatersPage']['MasqueradeCharacter'] = '*'; // Character used for masquerade
|
||||
|
||||
$PageOptions['PeerPage'] = array();
|
||||
$PageOptions['PeerPage']['LimitTo'] = 99; // Number of peers to show
|
||||
$PageOptions['PeerPage']['IPModus'] = 'ShowFullIP'; // See possible options above
|
||||
$PageOptions['PeerPage']['MasqueradeCharacter'] = '*'; // Character used for masquerade
|
||||
|
||||
$PageOptions['LastHeardPage']['LimitTo'] = 39; // Number of stations to show
|
||||
|
||||
$PageOptions['ModuleNames'] = array(); // Module nomination
|
||||
$PageOptions['ModuleNames']['A'] = 'Int.';
|
||||
$PageOptions['ModuleNames']['B'] = 'Regional';
|
||||
$PageOptions['ModuleNames']['C'] = 'National';
|
||||
$PageOptions['ModuleNames']['D'] = '';
|
||||
|
||||
$PageOptions['MetaDescription'] = 'XLX is a D-Star Reflector System for Ham Radio Operators.'; // Meta Tag Values, usefull for Search Engine
|
||||
$PageOptions['MetaKeywords'] = 'Ham Radio, D-Star, XReflector, XLX, XRF, DCS, REF, '; // Meta Tag Values, usefull forSearch Engine
|
||||
$PageOptions['MetaAuthor'] = 'LX1IQ'; // Meta Tag Values, usefull for Search Engine
|
||||
$PageOptions['MetaRevisit'] = 'After 30 Days'; // Meta Tag Values, usefull for Search Engine
|
||||
$PageOptions['MetaRobots'] = 'index,follow'; // Meta Tag Values, usefull for Search Engine
|
||||
|
||||
$PageOptions['UserPage']['ShowFilter'] = true; // Show Filter on Users page
|
||||
$PageOptions['Traffic']['Show'] = false; // Enable vnstat traffic statistics
|
||||
$PageOptions['IRCDDB']['Show'] = true; // Show liveircddb, set it to false if you are running your db in https
|
||||
|
||||
$PageOptions['CustomTXT'] = ''; // custom text in your header
|
||||
|
||||
$Service['PIDFile'] = '/var/log/xlxd.pid';
|
||||
$Service['XMLFile'] = '/var/log/xlxd.xml';
|
||||
|
||||
$CallingHome['Active'] = false; // xlx phone home, true or false
|
||||
$CallingHome['MyDashBoardURL'] = 'http://your_dashboard'; // dashboard url
|
||||
$CallingHome['ServerURL'] = 'http://xlxapi.rlx.lu/api.php'; // database server, do not change !!!!
|
||||
$CallingHome['PushDelay'] = 600; // push delay in seconds
|
||||
$CallingHome['Country'] = "your_country"; // Country
|
||||
$CallingHome['Comment'] = "your_comment"; // Comment. Max 100 character
|
||||
$CallingHome['HashFile'] = "/tmp/callinghome.php"; // Make sure the apache user has read and write permissions in this folder.
|
||||
$CallingHome['LastCallHomefile'] = "/tmp/lastcallhome.php"; // lastcallhome.php can remain in the tmp folder
|
||||
$CallingHome['OverrideIPAddress'] = ""; // Insert your IP address here. Leave blank for autodetection. No need to enter a fake address.
|
||||
$CallingHome['InterlinkFile'] = "/xlxd/xlxd.interlink"; // Path to interlink file
|
||||
|
||||
$VNStat['Interfaces'] = array();
|
||||
$VNStat['Interfaces'][0]['Name'] = 'eth0';
|
||||
$VNStat['Interfaces'][0]['Address'] = 'eth0';
|
||||
$VNStat['Binary'] = '/usr/bin/vnstat';
|
||||
|
||||
/*
|
||||
include an extra config file for people who dont like to mess with shipped config.ing.php
|
||||
this makes updating dashboard from git a little bit easier
|
||||
*/
|
||||
if (file_exists("../config.inc.php")) {
|
||||
include ("../config.inc.php");
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -0,0 +1,228 @@
|
||||
<?php
|
||||
function sanitize_output($string) {
|
||||
if ($string === null) return '';
|
||||
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
}
|
||||
|
||||
function sanitize_attribute($string) {
|
||||
if ($string === null) return '';
|
||||
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
}
|
||||
|
||||
function validate_callsign($callsign) {
|
||||
$callsign = trim($callsign);
|
||||
if (preg_match('/^[A-Z0-9\-\/\s]{3,20}$/i', $callsign)) {
|
||||
return strtoupper($callsign);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function validate_module($module) {
|
||||
$module = trim(strtoupper($module));
|
||||
if (preg_match('/^[A-Z]$/', $module)) {
|
||||
return $module;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function validate_protocol($protocol) {
|
||||
$allowed = ['DPlus', 'DExtra', 'DCS', 'DMR', 'YSF', 'DEXTRA', 'DPLUS', 'DMRMmdvm', 'XLX'];
|
||||
return in_array(trim($protocol), $allowed, true) ? trim($protocol) : '';
|
||||
}
|
||||
|
||||
function GetSystemUptime() {
|
||||
if (file_exists('/proc/uptime')) {
|
||||
$uptime = @file_get_contents('/proc/uptime');
|
||||
if ($uptime !== false) {
|
||||
$parts = explode(' ', $uptime);
|
||||
return isset($parts[0]) ? (int)$parts[0] : 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function Debug($message) {
|
||||
if (defined('DEBUG_MODE') && DEBUG_MODE === true) {
|
||||
echo '<br><hr><pre>';
|
||||
print_r($message); // Don't sanitize here as it's debug only
|
||||
echo '</pre><hr><br>';
|
||||
}
|
||||
}
|
||||
|
||||
function ParseTime($Input) {
|
||||
if (empty($Input) || !is_string($Input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$Input = strip_tags($Input); // Remove any HTML tags
|
||||
|
||||
if (strpos($Input, "<") !== false) {
|
||||
$Input = substr($Input, 0, strpos($Input, "<"));
|
||||
}
|
||||
|
||||
// Tuesday Tue Nov 17 14:23:22 2015
|
||||
$tmp = explode(" ", $Input);
|
||||
|
||||
// Add bounds checking
|
||||
if (count($tmp) < 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen(trim($tmp[3])) == 0) {
|
||||
unset($tmp[3]);
|
||||
$tmp = array_values($tmp);
|
||||
}
|
||||
|
||||
// Check array indices exist after potential unset
|
||||
if (!isset($tmp[4]) || !isset($tmp[2]) || !isset($tmp[3]) || !isset($tmp[5])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tmp1 = explode(":", $tmp[4]);
|
||||
|
||||
// Check time parts exist
|
||||
if (count($tmp1) < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$month = "";
|
||||
switch (strtolower($tmp[2])) {
|
||||
case 'jan' : $month = 1; break;
|
||||
case 'feb' : $month = 2; break;
|
||||
case 'mar' : $month = 3; break;
|
||||
case 'apr' : $month = 4; break;
|
||||
case 'may' : $month = 5; break;
|
||||
case 'jun' : $month = 6; break;
|
||||
case 'jul' : $month = 7; break;
|
||||
case 'aug' : $month = 8; break;
|
||||
case 'sep' : $month = 9; break;
|
||||
case 'oct' : $month = 10; break;
|
||||
case 'nov' : $month = 11; break;
|
||||
case 'dec' : $month = 12; break;
|
||||
default : $month = 1;
|
||||
}
|
||||
return @mktime($tmp1[0], $tmp1[1], $tmp1[2], $month, $tmp[3], $tmp[5]);
|
||||
}
|
||||
|
||||
function FormatSeconds($seconds) {
|
||||
$seconds = abs($seconds);
|
||||
return sprintf("%d days %02d:%02d:%02d", $seconds/60/60/24,($seconds/60/60)%24,($seconds/60)%60,$seconds%60);
|
||||
}
|
||||
|
||||
function CreateCode ($laenge) {
|
||||
$zeichen = "1234567890abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNAOPQRSTUVWYXZ";
|
||||
$out = "";
|
||||
for ($i=1;$i<=$laenge;$i++){
|
||||
$out .= $zeichen[mt_rand(0,(strlen($zeichen)-1))];
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
function VNStatLocalize($str) {
|
||||
global $L;
|
||||
if (isset($L[$str])) {
|
||||
return $L[$str];
|
||||
}
|
||||
else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
function VNStatGetData($iface, $vnstat_bin) {
|
||||
// Validate interface name (only allow alphanumeric, dash, underscore)
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $iface)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validate vnstat binary path
|
||||
if (!file_exists($vnstat_bin) || !is_executable($vnstat_bin)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Escape shell arguments
|
||||
$iface_escaped = escapeshellarg($iface);
|
||||
$vnstat_bin_escaped = escapeshellarg($vnstat_bin);
|
||||
|
||||
$vnstat_data = array();
|
||||
|
||||
$fd = @popen("$vnstat_bin_escaped --dumpdb -i $iface_escaped", "r");
|
||||
if (is_resource($fd)) {
|
||||
$buffer = '';
|
||||
while (!feof($fd)) {
|
||||
$buffer .= fgets($fd);
|
||||
}
|
||||
$vnstat_data = explode("\n", $buffer);
|
||||
pclose($fd);
|
||||
}
|
||||
|
||||
$day = array();
|
||||
$hour = array();
|
||||
$month = array();
|
||||
$top = array();
|
||||
|
||||
if (isset($vnstat_data[0]) && strpos($vnstat_data[0], 'Error') !== false) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($vnstat_data as $line) {
|
||||
$d = explode(';', trim($line));
|
||||
if ($d[0] == 'd') {
|
||||
$day[$d[1]]['time'] = $d[2];
|
||||
$day[$d[1]]['rx'] = $d[3] * 1024 + $d[5];
|
||||
$day[$d[1]]['tx'] = $d[4] * 1024 + $d[6];
|
||||
$day[$d[1]]['act'] = $d[7];
|
||||
$day[$d[1]]['rx2'] = $d[5];
|
||||
$day[$d[1]]['tx2'] = $d[6];
|
||||
}
|
||||
else if ($d[0] == 'm') {
|
||||
$month[$d[1]]['time'] = $d[2];
|
||||
$month[$d[1]]['rx'] = $d[3] * 1024 + $d[5];
|
||||
$month[$d[1]]['tx'] = $d[4] * 1024 + $d[6];
|
||||
$month[$d[1]]['act'] = $d[7];
|
||||
$month[$d[1]]['rx2'] = $d[5];
|
||||
$month[$d[1]]['tx2'] = $d[6];
|
||||
}
|
||||
else if ($d[0] == 'h') {
|
||||
$hour[$d[1]]['time'] = $d[2];
|
||||
$hour[$d[1]]['rx'] = $d[3];
|
||||
$hour[$d[1]]['tx'] = $d[4];
|
||||
$hour[$d[1]]['act'] = 1;
|
||||
}
|
||||
else if ($d[0] == 't') {
|
||||
$top[$d[1]]['time'] = $d[2];
|
||||
$top[$d[1]]['rx'] = $d[3] * 1024 + $d[5];
|
||||
$top[$d[1]]['tx'] = $d[4] * 1024 + $d[6];
|
||||
$top[$d[1]]['act'] = $d[7];
|
||||
}
|
||||
else {
|
||||
$summary[$d[0]] = isset($d[1]) ? $d[1] : '';
|
||||
}
|
||||
}
|
||||
|
||||
rsort($day);
|
||||
rsort($month);
|
||||
rsort($hour);
|
||||
|
||||
return array($day, $month, $hour, $day, $month, $top, $summary);
|
||||
}
|
||||
|
||||
|
||||
function kbytes_to_string($kb) {
|
||||
$byte_notation = null;
|
||||
$units = array('TB','GB','MB','KB');
|
||||
$scale = 1024*1024*1024;
|
||||
$ui = 0;
|
||||
$custom_size = isset($byte_notation) && in_array($byte_notation, $units);
|
||||
|
||||
while ((($kb < $scale) && ($scale > 1)) || $custom_size) {
|
||||
$ui++;
|
||||
$scale = $scale / 1024;
|
||||
if ($custom_size && $units[$ui] == $byte_notation) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sprintf("%0.2f %s", ($kb/$scale),$units[$ui]);
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@ -0,0 +1,4 @@
|
||||
<div width="100%" style="text-align:center;">
|
||||
<iframe width="1050" height="800" src="http://ccs001.xreflector.net/live_seite/bndex.html" style="border:0px #000000 solid; margin-top:30px;" align="center"></iframe>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
<div width="100%" style="text-align:center;">
|
||||
<iframe width="1250" height="800" src="http://live.ircddb.net:8080/ircddblive5.html" style="border:0px #000000 solid; margin-top:30px;" align="center"></iframe>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
<table class="listingtable">
|
||||
<tr>
|
||||
<th width="80" rowspan="2">Module</th>
|
||||
<th width="130" rowspan="2">Name</th>
|
||||
<th width="65" rowspan="2">Users</th>
|
||||
<th colspan="2">DPlus</th>
|
||||
<th colspan="2">DExtra</th>
|
||||
<th colspan="2">DCS</th>
|
||||
<th width="65" rowspan="2">DMR</th>
|
||||
<th width="65" rowspan="2">YSF<br />DG-ID</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th width="100">URCALL</th>
|
||||
<th width="100">DTMF</th>
|
||||
<th width="100">URCALL</th>
|
||||
<th width="100">DTMF</th>
|
||||
<th width="100">URCALL</th>
|
||||
<th width="100">DTMF</th>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
$ReflectorNumber = substr($Reflector->GetReflectorName(), 3, 3);
|
||||
$NumberOfModules = isset($PageOptions['NumberOfModules']) ? min(max($PageOptions['NumberOfModules'],0),26) : 26;
|
||||
|
||||
$odd = "";
|
||||
|
||||
for ($i = 1; $i <= $NumberOfModules; $i++) {
|
||||
|
||||
$module = chr(ord('A')+($i-1));
|
||||
|
||||
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
|
||||
|
||||
echo '
|
||||
<tr height="30" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
|
||||
<td align="center">'. sanitize_output($module) .'</td>
|
||||
<td align="center">'. sanitize_output(empty($PageOptions['ModuleNames'][$module]) ? '-' : $PageOptions['ModuleNames'][$module]) .'</td>
|
||||
<td align="center">'. count($Reflector->GetNodesInModulesByID($module)) .'</td>
|
||||
<td align="center">'. sanitize_output('REF' . $ReflectorNumber . $module . 'L') .'</td>
|
||||
<td align="center">'. sanitize_output(is_numeric($ReflectorNumber) ? '*' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. sanitize_output('XRF' . $ReflectorNumber . $module . 'L') .'</td>
|
||||
<td align="center">'. sanitize_output(is_numeric($ReflectorNumber) ? 'B' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. sanitize_output('DCS' . $ReflectorNumber . $module . 'L') .'</td>
|
||||
<td align="center">'. sanitize_output(is_numeric($ReflectorNumber) ? 'D' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
|
||||
<td align="center">'. sanitize_output(4000+$i) .'</td>
|
||||
<td align="center">'. sanitize_output(9+$i) .'</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</table>
|
||||
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
$Result = @fopen($CallingHome['ServerURL']."?do=GetReflectorList", "r");
|
||||
|
||||
$INPUT = "";
|
||||
|
||||
if ($Result) {
|
||||
|
||||
while (!feof ($Result)) {
|
||||
$INPUT .= fgets ($Result, 1024);
|
||||
}
|
||||
|
||||
$XML = new ParseXML();
|
||||
$Reflectorlist = $XML->GetElement($INPUT, "reflectorlist");
|
||||
$Reflectors = $XML->GetAllElements($Reflectorlist, "reflector");
|
||||
}
|
||||
|
||||
fclose($Result);
|
||||
?>
|
||||
<table class="listingtable">
|
||||
<tr>
|
||||
<th width="25">#</th>
|
||||
<th width="100">XLX Peer</th>
|
||||
<th width="154">Last Heard</th>
|
||||
<th width="156">Linked for</th>
|
||||
<th width="90">Protocol</th>
|
||||
<th width="67">Module</th><?php
|
||||
|
||||
if ($PageOptions['PeerPage']['IPModus'] != 'HideIP') {
|
||||
echo '
|
||||
<th width="125">IP</th>';
|
||||
}
|
||||
|
||||
?>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
$odd = "";
|
||||
$Reflector->LoadFlags();
|
||||
|
||||
for ($i=0;$i<$Reflector->PeerCount();$i++) {
|
||||
|
||||
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
|
||||
|
||||
echo '
|
||||
<tr height="30" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
|
||||
<td align="center">'.($i+1).'</td>';
|
||||
$Name = $Reflector->Peers[$i]->GetCallSign();
|
||||
$URL = '';
|
||||
for ($j=1;$j<count($Reflectors);$j++) {
|
||||
if ($Name === $XML->GetElement($Reflectors[$j], "name")) {
|
||||
$URL = $XML->GetElement($Reflectors[$j], "dashboardurl");
|
||||
}
|
||||
}
|
||||
if ($Result && (trim($URL) != "")) {
|
||||
echo '
|
||||
<td><a href="'.sanitize_attribute($URL).'" target="_blank" class="listinglink" title="Visit the Dashboard of '.sanitize_attribute($Name).'" style="text-decoration:none;color:#000000;">'.sanitize_output($Name).'</a></td>';
|
||||
} else {
|
||||
echo '
|
||||
<td>'.sanitize_output($Name).'</td>';
|
||||
}
|
||||
echo '
|
||||
<td>'.sanitize_output(date("d.m.Y H:i", $Reflector->Peers[$i]->GetLastHeardTime())).'</td>
|
||||
<td>'.sanitize_output(FormatSeconds(time()-$Reflector->Peers[$i]->GetConnectTime())).' s</td>
|
||||
<td align="center">'.sanitize_output($Reflector->Peers[$i]->GetProtocol()).'</td>
|
||||
<td align="center">'.sanitize_output($Reflector->Peers[$i]->GetLinkedModule()).'</td>';
|
||||
if ($PageOptions['PeerPage']['IPModus'] != 'HideIP') {
|
||||
echo '
|
||||
<td>';
|
||||
$Bytes = explode(".", $Reflector->Peers[$i]->GetIP());
|
||||
if ($Bytes !== false && count($Bytes) == 4) {
|
||||
switch ($PageOptions['PeerPage']['IPModus']) {
|
||||
case 'ShowLast1ByteOfIP' : echo sanitize_output($PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[3]); break;
|
||||
case 'ShowLast2ByteOfIP' : echo sanitize_output($PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[2].'.'.$Bytes[3]); break;
|
||||
case 'ShowLast3ByteOfIP' : echo sanitize_output($PageOptions['PeerPage']['MasqueradeCharacter'].'.'.$Bytes[1].'.'.$Bytes[2].'.'.$Bytes[3]); break;
|
||||
default : echo sanitize_output($Reflector->Peers[$i]->GetIP());
|
||||
}
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
echo '
|
||||
</tr>';
|
||||
if ($i == $PageOptions['PeerPage']['LimitTo']) { $i = $Reflector->PeerCount()+1; }
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</table>
|
||||
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
$Result = @fopen($CallingHome['ServerURL']."?do=GetReflectorList", "r");
|
||||
|
||||
if (!$Result) die("HEUTE GIBTS KEIN BROT");
|
||||
|
||||
$INPUT = "";
|
||||
while (!feof ($Result)) {
|
||||
$INPUT .= fgets ($Result, 1024);
|
||||
}
|
||||
fclose($Result);
|
||||
|
||||
$XML = new ParseXML();
|
||||
$Reflectorlist = $XML->GetElement($INPUT, "reflectorlist");
|
||||
$Reflectors = $XML->GetAllElements($Reflectorlist, "reflector");
|
||||
|
||||
?>
|
||||
|
||||
<table class="listingtable">
|
||||
<tr>
|
||||
<th width="40">#</th>
|
||||
<th width="75">Reflector</th>
|
||||
<th width="120">Country</th>
|
||||
<th width="90">Service</th>
|
||||
<th width="400">Comment</th>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
$odd = "";
|
||||
|
||||
for ($i=0;$i<count($Reflectors);$i++) {
|
||||
|
||||
$NAME = sanitize_output($XML->GetElement($Reflectors[$i], "name"));
|
||||
$COUNTRY = sanitize_output($XML->GetElement($Reflectors[$i], "country"));
|
||||
$LASTCONTACT = intval($XML->GetElement($Reflectors[$i], "lastcontact"));
|
||||
$COMMENT = sanitize_output($XML->GetElement($Reflectors[$i], "comment"));
|
||||
$DASHBOARDURL = sanitize_attribute($XML->GetElement($Reflectors[$i], "dashboardurl"));
|
||||
|
||||
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
|
||||
|
||||
echo '
|
||||
<tr height="30" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
|
||||
<td align="center">'.($i+1).'</td>
|
||||
<td><a href="'.$DASHBOARDURL.'" target="_blank" class="listinglink" title="Visit the Dashboard of '.$NAME.'">'.$NAME.'</a></td>
|
||||
<td>'.$COUNTRY.'</td>
|
||||
<td align="center" valign="middle"><img src="./img/'; if ($LASTCONTACT<(time()-1800)) { echo 'down'; } ELSE { echo 'up'; } echo '.png" height="25" /></td>
|
||||
<td>'.$COMMENT.'</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
?>
|
||||
</table>
|
||||
@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
// Initialize filter session variables
|
||||
if (!isset($_SESSION['FilterCallSign'])) {
|
||||
$_SESSION['FilterCallSign'] = null;
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['FilterProtocol'])) {
|
||||
$_SESSION['FilterProtocol'] = null;
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['FilterModule'])) {
|
||||
$_SESSION['FilterModule'] = null;
|
||||
}
|
||||
|
||||
// Validate filter inputs
|
||||
if (isset($_SESSION['FilterCallSign']) && $_SESSION['FilterCallSign'] !== null) {
|
||||
$_SESSION['FilterCallSign'] = preg_replace('/[^A-Z0-9\*\-\/\s]/i', '', $_SESSION['FilterCallSign']);
|
||||
}
|
||||
if (isset($_SESSION['FilterProtocol']) && $_SESSION['FilterProtocol'] !== null) {
|
||||
$_SESSION['FilterProtocol'] = validate_protocol($_SESSION['FilterProtocol']);
|
||||
}
|
||||
if (isset($_SESSION['FilterModule']) && $_SESSION['FilterModule'] !== null) {
|
||||
$_SESSION['FilterModule'] = validate_module($_SESSION['FilterModule']);
|
||||
}
|
||||
|
||||
if (isset($_POST['do'])) {
|
||||
if ($_POST['do'] == 'SetFilter') {
|
||||
|
||||
if (isset($_POST['txtSetCallsignFilter'])) {
|
||||
$_POST['txtSetCallsignFilter'] = trim($_POST['txtSetCallsignFilter']);
|
||||
if ($_POST['txtSetCallsignFilter'] == "") {
|
||||
$_SESSION['FilterCallSign'] = null;
|
||||
}
|
||||
else {
|
||||
$_SESSION['FilterCallSign'] = $_POST['txtSetCallsignFilter'];
|
||||
if (strpos($_SESSION['FilterCallSign'], "*") === false) {
|
||||
$_SESSION['FilterCallSign'] = "*".$_SESSION['FilterCallSign']."*";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['txtSetProtocolFilter'])) {
|
||||
$_POST['txtSetProtocolFilter'] = trim($_POST['txtSetProtocolFilter']);
|
||||
if ($_POST['txtSetProtocolFilter'] == "") {
|
||||
$_SESSION['FilterProtocol'] = null;
|
||||
}
|
||||
else {
|
||||
$_SESSION['FilterProtocol'] = $_POST['txtSetProtocolFilter'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['txtSetModuleFilter'])) {
|
||||
$_POST['txtSetModuleFilter'] = trim($_POST['txtSetModuleFilter']);
|
||||
if ($_POST['txtSetModuleFilter'] == "") {
|
||||
$_SESSION['FilterModule'] = null;
|
||||
}
|
||||
else {
|
||||
$_SESSION['FilterModule'] = $_POST['txtSetModuleFilter'];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['do'])) {
|
||||
if ($_GET['do'] == "resetfilter") {
|
||||
$_SESSION['FilterModule'] = null;
|
||||
$_SESSION['FilterProtocol'] = null;
|
||||
$_SESSION['FilterCallSign'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
<table class="listingtable"><?php
|
||||
|
||||
if ($PageOptions['UserPage']['ShowFilter']) {
|
||||
echo '
|
||||
<tr>
|
||||
<th colspan="9">
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td align="left">
|
||||
<form name="frmFilterCallSign" method="post" action="./index.php?show=repeaters">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterCallSign']).'" name="txtSetCallsignFilter" placeholder="Callsign" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>';
|
||||
if (($_SESSION['FilterModule'] != null) || ($_SESSION['FilterCallSign'] != null) || ($_SESSION['FilterProtocol'] != null)) {
|
||||
echo '
|
||||
<td><a href="./index.php?show=repeaters&do=resetfilter" class="smalllink">Disable filters</a></td>';
|
||||
}
|
||||
echo '
|
||||
<td align="right" style="padding-right:3px;">
|
||||
<form name="frmFilterProtocol" method="post" action="./index.php?show=repeaters">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterProtocol']).'" name="txtSetProtocolFilter" placeholder="Protocol" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>
|
||||
<td align="right" style="padding-right:3px;">
|
||||
<form name="frmFilterModule" method="post" action="./index.php?show=repeaters">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterModule']).'" name="txtSetModuleFilter" placeholder="Module" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>
|
||||
</table>
|
||||
</th>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<th width="25">#</th>
|
||||
<th width="60">Flag</th>
|
||||
<th width="100">DV Station</th>
|
||||
<th width="75">Band</th>
|
||||
<th width="150">Last Heard</th>
|
||||
<th width="150">Linked for</th>
|
||||
<th width="90">Protocol</th>
|
||||
<th width="65">Module</th><?php
|
||||
|
||||
if ($PageOptions['RepeatersPage']['IPModus'] != 'HideIP') {
|
||||
echo '
|
||||
<th width="125">IP</th>';
|
||||
}
|
||||
|
||||
?>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
$odd = "";
|
||||
$Reflector->LoadFlags();
|
||||
|
||||
for ($i=0;$i<$Reflector->NodeCount();$i++) {
|
||||
$ShowThisStation = true;
|
||||
if ($PageOptions['UserPage']['ShowFilter']) {
|
||||
$CS = true;
|
||||
if ($_SESSION['FilterCallSign'] != null) {
|
||||
if (!fnmatch($_SESSION['FilterCallSign'], $Reflector->Nodes[$i]->GetCallSign(), FNM_CASEFOLD)) {
|
||||
$CS = false;
|
||||
}
|
||||
}
|
||||
$MO = true;
|
||||
if ($_SESSION['FilterModule'] != null) {
|
||||
if (trim(strtolower($_SESSION['FilterModule'])) != strtolower($Reflector->Nodes[$i]->GetLinkedModule())) {
|
||||
$MO = false;
|
||||
}
|
||||
}
|
||||
$PR = true;
|
||||
if ($_SESSION['FilterProtocol'] != null) {
|
||||
if (trim(strtolower($_SESSION['FilterProtocol'])) != strtolower($Reflector->Nodes[$i]->GetProtocol())) {
|
||||
$PR = false;
|
||||
}
|
||||
}
|
||||
|
||||
$ShowThisStation = ($CS && $MO && $PR);
|
||||
}
|
||||
|
||||
if ($ShowThisStation) {
|
||||
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
|
||||
|
||||
echo '
|
||||
<tr height="30" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
|
||||
<td align="center">'.($i+1).'</td>
|
||||
<td align="center">';
|
||||
list ($Flag, $Name) = $Reflector->GetFlag($Reflector->Nodes[$i]->GetCallSign());
|
||||
if (file_exists("./img/flags/".$Flag.".png")) {
|
||||
echo '<a href="#" class="tip"><img src="./img/flags/'.sanitize_attribute($Flag).'.png" height="15" alt="'.sanitize_attribute($Name).'" /><span>'.sanitize_output($Name).'</span></a>';
|
||||
}
|
||||
echo '</td>
|
||||
<td><a href="http://www.aprs.fi/'.sanitize_attribute($Reflector->Nodes[$i]->GetCallSign());
|
||||
if ($Reflector->Nodes[$i]->GetSuffix() != "") echo '-'.sanitize_attribute($Reflector->Nodes[$i]->GetSuffix());
|
||||
echo '" class="pl" target="_blank">'.sanitize_output($Reflector->Nodes[$i]->GetCallSign());
|
||||
if ($Reflector->Nodes[$i]->GetSuffix() != "") { echo '-'.sanitize_output($Reflector->Nodes[$i]->GetSuffix()); }
|
||||
echo '</a></td>
|
||||
<td>';
|
||||
if (($Reflector->Nodes[$i]->GetPrefix() == 'REF') || ($Reflector->Nodes[$i]->GetPrefix() == 'XRF')) {
|
||||
switch ($Reflector->Nodes[$i]->GetPrefix()) {
|
||||
case 'REF' : echo 'REF-Link'; break;
|
||||
case 'XRF' : echo 'XRF-Link'; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch ($Reflector->Nodes[$i]->GetSuffix()) {
|
||||
case 'A' : echo '23cm'; break;
|
||||
case 'B' : echo '70cm'; break;
|
||||
case 'C' : echo '2m'; break;
|
||||
case 'D' : echo 'Dongle'; break;
|
||||
case 'G' : echo 'Internet-Gateway'; break;
|
||||
default : echo '';
|
||||
}
|
||||
}
|
||||
echo '</td>
|
||||
<td>'.sanitize_output(date("d.m.Y H:i", $Reflector->Nodes[$i]->GetLastHeardTime())).'</td>
|
||||
<td>'.sanitize_output(FormatSeconds(time()-$Reflector->Nodes[$i]->GetConnectTime())).' s</td>
|
||||
<td>'.sanitize_output($Reflector->Nodes[$i]->GetProtocol()).'</td>
|
||||
<td align="center">'.sanitize_output($Reflector->Nodes[$i]->GetLinkedModule()).'</td>';
|
||||
if ($PageOptions['RepeatersPage']['IPModus'] != 'HideIP') {
|
||||
echo '
|
||||
<td>';
|
||||
$Bytes = explode(".", $Reflector->Nodes[$i]->GetIP());
|
||||
if ($Bytes !== false && count($Bytes) == 4) {
|
||||
switch ($PageOptions['RepeatersPage']['IPModus']) {
|
||||
case 'ShowLast1ByteOfIP' : echo sanitize_output($PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[3]); break;
|
||||
case 'ShowLast2ByteOfIP' : echo sanitize_output($PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[2].'.'.$Bytes[3]); break;
|
||||
case 'ShowLast3ByteOfIP' : echo sanitize_output($PageOptions['RepeatersPage']['MasqueradeCharacter'].'.'.$Bytes[1].'.'.$Bytes[2].'.'.$Bytes[3]); break;
|
||||
default : echo sanitize_output($Reflector->Nodes[$i]->GetIP());
|
||||
}
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
echo '
|
||||
</tr>';
|
||||
}
|
||||
if ($i == $PageOptions['RepeatersPage']['LimitTo']) { $i = $Reflector->NodeCount()+1; }
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</table>
|
||||
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
if (!isset($_GET['iface'])) {
|
||||
if (isset($VNStat['Interfaces'][0]['Address'])) {
|
||||
$_GET['iface'] = $VNStat['Interfaces'][0]['Address'];
|
||||
}
|
||||
else {
|
||||
$_GET['iface'] = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Validate interface name against whitelist
|
||||
if (!empty($_GET['iface'])) {
|
||||
$valid = false;
|
||||
for ($i = 0; $i < count($VNStat['Interfaces']); $i++) {
|
||||
if ($_GET['iface'] === $VNStat['Interfaces'][$i]['Address']) {
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$valid) {
|
||||
$_GET['iface'] = "";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<table class="listingtable">
|
||||
<tr>
|
||||
<th>Network interfaces</th>
|
||||
<th>Statistics</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor="#F1FAFA" align="left" valign="top" style="padding-left:5px;"><?php
|
||||
|
||||
for ($i=0;$i<count($VNStat['Interfaces']);$i++) {
|
||||
echo '<a href="./index.php?show=traffic&iface='.sanitize_attribute($VNStat['Interfaces'][$i]['Address']).'" class="listinglink">'.sanitize_output($VNStat['Interfaces'][$i]['Name']).'</a>';
|
||||
if ($i < count($VNStat['Interfaces'])-1) {
|
||||
echo '<br />';
|
||||
}
|
||||
}
|
||||
|
||||
?></td>
|
||||
<td bgcolor="#FFFFFF"><?php
|
||||
|
||||
$Data = VNStatGetData($_GET['iface'], $VNStat['Binary']);
|
||||
|
||||
echo '
|
||||
<table style="margin:10px;">
|
||||
<tr>
|
||||
<td>Day</td>
|
||||
<td>RX</td>
|
||||
<td>TX</td>
|
||||
<td>Avg Rx</td>
|
||||
<td>Avg TX</td>
|
||||
</tr>';
|
||||
|
||||
for ($i=0;$i<count($Data[0]);$i++) {
|
||||
if ($Data[0][$i]['time'] > 0) {
|
||||
echo '
|
||||
<tr>
|
||||
<td width="100">'.date("d.m.Y", $Data[0][$i]['time']).'</td>
|
||||
<td width="100">'.kbytes_to_string($Data[0][$i]['rx']).'</td>
|
||||
<td width="100">'.kbytes_to_string($Data[0][$i]['tx']).'</td>
|
||||
<td width="100">'.kbytes_to_string($Data[0][$i]['rx2']).'</td>
|
||||
<td width="100">'.kbytes_to_string($Data[0][$i]['tx2']).'</td>
|
||||
</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
|
||||
|
||||
|
||||
|
||||
echo '
|
||||
<table style="margin:10px;">
|
||||
<tr>
|
||||
<td>Month</td>
|
||||
<td>RX</td>
|
||||
<td>TX</td>
|
||||
<td>Avg Rx</td>
|
||||
<td>Avg TX</td>
|
||||
</tr>';
|
||||
|
||||
for ($i=0;$i<count($Data[1]);$i++) {
|
||||
if ($Data[1][$i]['time'] > 0) {
|
||||
echo '
|
||||
<tr>
|
||||
<td width="100">'.date("F", $Data[1][$i]['time']).'</td>
|
||||
<td width="100">'.kbytes_to_string($Data[1][$i]['rx']).'</td>
|
||||
<td width="100">'.kbytes_to_string($Data[1][$i]['tx']).'</td>
|
||||
<td width="100">'.kbytes_to_string($Data[1][$i]['rx2']).'</td>
|
||||
<td width="100">'.kbytes_to_string($Data[1][$i]['tx2']).'</td>
|
||||
</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
if (!isset($_SESSION['FilterCallSign'])) {
|
||||
$_SESSION['FilterCallSign'] = null;
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['FilterModule'])) {
|
||||
$_SESSION['FilterModule'] = null;
|
||||
}
|
||||
|
||||
if (isset($_POST['do'])) {
|
||||
if ($_POST['do'] == 'SetFilter') {
|
||||
|
||||
if (isset($_POST['txtSetCallsignFilter'])) {
|
||||
$_POST['txtSetCallsignFilter'] = trim($_POST['txtSetCallsignFilter']);
|
||||
if ($_POST['txtSetCallsignFilter'] == "") {
|
||||
$_SESSION['FilterCallSign'] = null;
|
||||
}
|
||||
else {
|
||||
$_SESSION['FilterCallSign'] = $_POST['txtSetCallsignFilter'];
|
||||
if (strpos($_SESSION['FilterCallSign'], "*") === false) {
|
||||
$_SESSION['FilterCallSign'] = "*".$_SESSION['FilterCallSign']."*";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['txtSetModuleFilter'])) {
|
||||
$_POST['txtSetModuleFilter'] = trim($_POST['txtSetModuleFilter']);
|
||||
if ($_POST['txtSetModuleFilter'] == "") {
|
||||
$_SESSION['FilterModule'] = null;
|
||||
}
|
||||
else {
|
||||
$_SESSION['FilterModule'] = $_POST['txtSetModuleFilter'];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['do'])) {
|
||||
if ($_GET['do'] == "resetfilter") {
|
||||
$_SESSION['FilterModule'] = null;
|
||||
$_SESSION['FilterCallSign'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate filter inputs
|
||||
if (isset($_SESSION['FilterCallSign']) && $_SESSION['FilterCallSign'] !== null) {
|
||||
$_SESSION['FilterCallSign'] = preg_replace('/[^A-Z0-9\*\-\/\s]/i', '', $_SESSION['FilterCallSign']);
|
||||
}
|
||||
if (isset($_SESSION['FilterModule']) && $_SESSION['FilterModule'] !== null) {
|
||||
$_SESSION['FilterModule'] = validate_module($_SESSION['FilterModule']);
|
||||
}
|
||||
|
||||
?>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td valign="top">
|
||||
|
||||
|
||||
<table class="listingtable"><?php
|
||||
|
||||
if ($PageOptions['UserPage']['ShowFilter']) {
|
||||
echo '
|
||||
<tr>
|
||||
<th colspan="8">
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td align="left">
|
||||
<form name="frmFilterCallSign" method="post" action="./index.php">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterCallSign']).'" name="txtSetCallsignFilter" placeholder="Callsign" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>';
|
||||
if (($_SESSION['FilterModule'] != null) || ($_SESSION['FilterCallSign'] != null)) {
|
||||
echo '
|
||||
<td><a href="./index.php?do=resetfilter" class="smalllink">Disable filters</a></td>';
|
||||
}
|
||||
echo '
|
||||
<td align="right" style="padding-right:3px;">
|
||||
<form name="frmFilterModule" method="post" action="./index.php">
|
||||
<input type="hidden" name="do" value="SetFilter" />
|
||||
<input type="text" class="FilterField" value="'.sanitize_attribute($_SESSION['FilterModule']).'" name="txtSetModuleFilter" placeholder="Module" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
|
||||
<input type="submit" value="Apply" class="FilterSubmit" />
|
||||
</form>
|
||||
</td>
|
||||
</table>
|
||||
</th>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Flag</th>
|
||||
<th>Callsign</th>
|
||||
<th>Suffix</th>
|
||||
<th>DPRS</th>
|
||||
<th>Via / Peer</th>
|
||||
<th>Last heard</th>
|
||||
<th align="center" valign="middle"><img src="./img/ear.png" alt="Listening on" /></th>
|
||||
</tr><?php
|
||||
|
||||
$Reflector->LoadFlags();
|
||||
$odd = "";
|
||||
for ($i=0;$i<$Reflector->StationCount();$i++) {
|
||||
$ShowThisStation = true;
|
||||
if ($PageOptions['UserPage']['ShowFilter']) {
|
||||
$CS = true;
|
||||
if ($_SESSION['FilterCallSign'] != null) {
|
||||
if (!fnmatch($_SESSION['FilterCallSign'], $Reflector->Stations[$i]->GetCallSign(), FNM_CASEFOLD)) {
|
||||
$CS = false;
|
||||
}
|
||||
}
|
||||
$MO = true;
|
||||
if ($_SESSION['FilterModule'] != null) {
|
||||
if (trim(strtolower($_SESSION['FilterModule'])) != strtolower($Reflector->Stations[$i]->GetModule())) {
|
||||
$MO = false;
|
||||
}
|
||||
}
|
||||
|
||||
$ShowThisStation = ($CS && $MO);
|
||||
}
|
||||
|
||||
|
||||
if ($ShowThisStation) {
|
||||
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
|
||||
echo '
|
||||
<tr height="30" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
|
||||
<td align="center" valign="middle" width="35">';
|
||||
if ($i==0 && $Reflector->Stations[$i]->GetLastHeardTime() > (time() - 60)) {
|
||||
echo '<img src="./img/tx.gif" style="margin-top:3px;" height="20"/>';
|
||||
}
|
||||
else {
|
||||
echo ($i+1);
|
||||
}
|
||||
|
||||
echo '</td>
|
||||
<td align="center" width="60">';
|
||||
|
||||
list ($Flag, $Name) = $Reflector->GetFlag($Reflector->Stations[$i]->GetCallSign());
|
||||
if (file_exists("./img/flags/".$Flag.".png")) {
|
||||
echo '<a href="#" class="tip"><img src="./img/flags/'.sanitize_attribute($Flag).'.png" height="15" alt="'.sanitize_attribute($Name).'" /><span>'.sanitize_output($Name).'</span></a>';
|
||||
}
|
||||
echo '</td>
|
||||
<td width="75"><a href="https://www.qrz.com/db/'.sanitize_attribute($Reflector->Stations[$i]->GetCallsignOnly()).'" class="pl" target="_blank">'.sanitize_output($Reflector->Stations[$i]->GetCallsignOnly()).'</a></td>
|
||||
<td width="60">'.sanitize_output($Reflector->Stations[$i]->GetSuffix()).'</td>
|
||||
<td width="50" align="center"><a href="http://www.aprs.fi/'.sanitize_attribute($Reflector->Stations[$i]->GetCallsignOnly()).'" class="pl" target="_blank"><img src="./img/sat.png" /></a></td>
|
||||
<td width="150">'.sanitize_output($Reflector->Stations[$i]->GetVia());
|
||||
if ($Reflector->Stations[$i]->GetPeer() != $Reflector->GetReflectorName()) {
|
||||
echo ' / '.sanitize_output($Reflector->Stations[$i]->GetPeer());
|
||||
}
|
||||
echo '</td>
|
||||
<td width="150">'.sanitize_output(@date("d.m.Y H:i", $Reflector->Stations[$i]->GetLastHeardTime())).'</td>
|
||||
<td align="center" width="30">'.sanitize_output($Reflector->Stations[$i]->GetModule()).'</td>
|
||||
</tr>';
|
||||
}
|
||||
if ($i == $PageOptions['LastHeardPage']['LimitTo']) { $i = $Reflector->StationCount()+1; }
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
<td style="padding-left:50px;" align="center" valign="top">
|
||||
|
||||
|
||||
|
||||
|
||||
<table class="listingtable">
|
||||
<?php
|
||||
|
||||
$Modules = $Reflector->GetModules();
|
||||
sort($Modules, SORT_STRING);
|
||||
echo '
|
||||
<tr>';
|
||||
for ($i=0;$i<count($Modules);$i++) {
|
||||
|
||||
if (isset($PageOptions['ModuleNames'][$Modules[$i]])) {
|
||||
echo '
|
||||
<th>'.sanitize_output($PageOptions['ModuleNames'][$Modules[$i]]);
|
||||
if (trim($PageOptions['ModuleNames'][$Modules[$i]]) != "") {
|
||||
echo '<br />';
|
||||
}
|
||||
echo sanitize_output($Modules[$i]).'</th>';
|
||||
}
|
||||
else {
|
||||
echo '
|
||||
<th>'.sanitize_output($Modules[$i]).'</th>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '
|
||||
</tr>
|
||||
<tr bgcolor="#FFFFFF" style="padding:0px;">';
|
||||
|
||||
$GlobalPositions = array();
|
||||
|
||||
for ($i=0;$i<count($Modules);$i++) {
|
||||
|
||||
$Users = $Reflector->GetNodesInModulesByID($Modules[$i]);
|
||||
echo '
|
||||
<td valign="top" style="border:0px;padding:0px;">
|
||||
|
||||
<table width="100" border="0" style="padding:0px;margin:0px;">';
|
||||
$odd = "";
|
||||
|
||||
$UserCheckedArray = array();
|
||||
|
||||
for ($j=0;$j<count($Users);$j++) {
|
||||
|
||||
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
|
||||
$Displayname = $Reflector->GetCallsignAndSuffixByID($Users[$j]);
|
||||
echo '
|
||||
<tr height="25" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
|
||||
<td valign="top" style="border-bottom:1px #C1DAD7 solid;"><a href="http://www.aprs.fi/'.sanitize_attribute($Displayname).'" class="pl" target="_blank">'.sanitize_output($Displayname).'</a> </td>
|
||||
</tr>';
|
||||
$UserCheckedArray[] = $Users[$j];
|
||||
}
|
||||
echo '
|
||||
</table>
|
||||
|
||||
</td>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</tr>';
|
||||
|
||||
?>
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
Loading…
Reference in new issue