<?php
/**
* @copyright 2024 Double Bastion LLC <www.doublebastion.com>
*
* @author Double Bastion LLC
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
define('ACCESSCONST', TRUE);
require('db-connect.php');
foreach (glob("version-scripts/*.php") as $scriptname) {
include $scriptname;
}
session_start();
if ($_SESSION['loggedtorspanel'] == true) {
?>
<!doctype html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>RED SCARF Suite Panel</title>
<meta name="description" content="RED SCARF Suite Panel dashboard">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" type="image/png" href="images/favicon.png" />
<link rel="stylesheet" href="assets/css/normalize.min.css">
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/font-awesome-4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="assets/css/themify-icons/themify-icons.css">
<link rel="stylesheet" href="assets/css/cs-skin-elastic.css">
<link rel="stylesheet" href="assets/css/style.css">
<script type="text/javascript" src="assets/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="assets/js/jquery.flot.min.js"></script>
<script type="text/javascript" src="assets/js/jquery.flot.pie.min.js"></script>
<script type="text/javascript" src="assets/js/jquery.flot.tooltip.min.js"></script>
<script type="text/javascript" src="assets/js/jquery.flot.time.js"></script>
<script type="text/javascript" src="assets/js/jquery.flot.symbol.js"></script>
<script type="text/javascript" src="assets/js/jquery.flot.axislabels.js"></script>
<script type="text/javascript" src="assets/js/jquery.min.js"></script>
<script type="text/javascript" src="assets/js/popper.min.js"></script>
<script type="text/javascript" src="assets/js/bootstrap.min.js"></script>
<script type="text/javascript" src="assets/js/jquery.matchHeight.min.js"></script>
<script type="text/javascript" src="assets/js/main.js"></script>
<script type="text/javascript" src="assets/js/moment.min.js"></script>
<script type="text/javascript" src="assets/js/settingsmenu.js"></script>
<script type="text/javascript" src="assets/js/index.js"></script>
<script type="text/javascript" src="assets/js/arrow-up.js"></script>
</head>
<body>
<?php include 'panels.php'; ?>
<!-- Content -->
<div class="content">
<!-- Sample Announcement that can be displayed on the Dashboard. When you want to make an announcement you can edit the text below and remove the comment signs. -->
<!--
<div class="row">
<div class="announcement">Announcement</div>
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div id="announcetext">
Please be adviced that Saturday, May 29, 2025, at 3:00 AM we will conduct periodic system maintenance. All the websites
hosted on the server will become inaccessible for 20 minutes, between 3:00 AM - 3:20 AM. Thank you for your understanding !
</div>
</div>
</div>
</div>
</div>
-->
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h4 class="cardheader">Services Status</h4>
<div class="flot-container">
<div class="hostnamerow">
<?php
$nameofhost = exec("hostname");
// Get the system uptime
$uptimeinit = exec("uptime | awk '{print $3,$4}'");
$uptimesplit = explode(" ", $uptimeinit);
if ($uptimesplit[1] == 'days,') {
$uptimefin = $uptimesplit[0] . " days";
} elseif ($uptimesplit[1] == 'min,') {
$uptimefin = $uptimesplit[0] . " min";
} elseif ($uptimesplit[1] == 'day,') {
$uptimefin = $uptimesplit[0] . " day";
} elseif (strpos($uptimeinit, ':') !== false) {
$uptimesec = explode(":", $uptimesplit[0]);
$uptimefin = $uptimesec[0] . " hours";
}
if (!file_exists('/var/run/reboot-required')) {
$needsrestart = "<font style='color:#06699b;'> No</font>";
} else { $needsrestart = "<font style='color:#cc2c52; font-weight:900;'> Security updates were automatically installed and THE SERVER NEEDS TO BE RESTARTED.</font>"; }
$hostdomain = gethostname();
$hostip = gethostbyname($hostdomain);
print_r("Host: <font color='#06699b'>" . $nameofhost . "</font> • Uptime: <font color='#06699b'>" . $uptimefin .
"</font> • Needs restart: " . $needsrestart . "<br> IP: <div id='hostIP'>" . $hostip . "</div> •
<span class='reputationcheck'>
<span class='inforeputation'>Check IP reputation</span>
<span class='checkreppopup-text'>
<input type='submit' id='checkIPmxtoolbox' name='checkipreputation' value='Check IP reputation on mxtoolbox.com'>
<input type='submit' id='checkIPabuseipdb' name='checkipreputation' value='Check IP reputation on abuseipdb.com'>
</span>
</span>");
?>
</div>
<div id="failed-processes">
<?php
// Search for failed processes and format the data
$getfailedservinit = shell_exec('systemctl --failed --all');
$getfailedservsec = str_replace("To show all installed unit files use 'systemctl list-unit-files'.", "", $getfailedservinit);
$failedservsplit = explode("\n", $getfailedservsec);
$countlines = count($failedservsplit);
$getfailedservbr = implode("<br>", $failedservsplit);
$getfailedservtert = $failedservsplit[$countlines - 3];
$getfailedlines = [];
foreach ($failedservsplit as $failedkey => $failedvalue) {
if (strpos($failedvalue, "●") !== false) {
$getfailedlines[] = str_replace("● ", "", $failedvalue);
}
}
$tablerows = [];
foreach ($getfailedlines as $tablelines) {
$valuesplit = explode(" ", $tablelines);
$getdatainit = array_filter(array_map('trim', $valuesplit));
$getwords = array_values($getdatainit);
$getremaininginit = array_slice($getwords, 4);
$getremaining = implode(" ", $getremaininginit);
$tablerows[] = "<tr><td class='unitcolumn'>".$getwords[0]."</td><td>".$getwords[1]."</td><td class='activesubcolumns'>".$getwords[2]."</td><td class='activesubcolumns'>".$getwords[3]."</td><td>".$getremaining."</td></tr>";
}
$finaltablehead = "<table id='failed-services'><tr><th>UNIT</th><th>LOAD</th><th>ACTIVE</th><th>SUB</th><th>DESCRIPTION</th></tr>";
array_unshift($tablerows, $finaltablehead);
array_push($tablerows, "</table>");
$finaltablerows = implode("", $tablerows);
// If there are failed processes, list them in a table
if ($getfailedservtert[0] != 0){
echo "<b>The following ".$getfailedservtert[0]." services are in failed state:</b>".$finaltablerows."
LOAD = Reflects whether the unit definition was properly loaded.<br>
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.<br>
SUB = The low-level unit activation state, values depend on unit type.";
} else echo "<p id='nofailedservices'>There are no services in failed state !</p><img id='ok-sign-image' src='images/ok_sign.svg' alt='' />";
?>
</div>
</div>
</div>
</div><!-- /# card -->
</div><!-- /# column -->
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h4 class="cardheader">ClamAV Detections by Periodic Scanning</h4>
<div class="flot-container">
<div class="clamavdirrow">
<?php
$detectresult = $mysqli->query("SELECT id, detdir FROM detectionsdir WHERE id = 1");
$clamavdet = $detectresult->fetch_array();
$clamavreportdir = $clamavdet[1];
echo "ClamAV detections directory: <font color='#06699b'>" . $clamavreportdir . "</font>";
?>
</div>
<div id="clamav-detections">
<?php
$maildetectrep = $clamavreportdir . "/clamav_mail_report";
$nextdetectrep = $clamavreportdir . "/clamav_nextcloud_report";
$targetstr = "Infected files: ";
$maildetlnbr = "";
$nextdetlnbr = "";
// Search for the infected files lines in the mail scan report
if (is_file($maildetectrep)) {
$mailfilecheck = true;
$readmaildetrep = file_get_contents($maildetectrep);
$infectedfl = strstr($readmaildetrep, $targetstr);
$txtbreakline = explode("\n", $infectedfl);
$nbofinfectfls = explode("Infected files: ", $txtbreakline[0]);
$nbinfctdflsmail = $nbofinfectfls[1];
if ($nbinfctdflsmail != 0) {
$getdetlines = file($maildetectrep);
$getdetmaillnarr = array();
$gosel = false;
$p = 0;
foreach ($getdetlines as $lnkey => $lnvalue) {
if (strpos($lnvalue, "SCAN SUMMARY") !== false) {
$gosel = false;
}
if (trim($lnvalue) == '') { $gosel = false; }
if ($gosel) {
$lnsplit = explode(":", $lnvalue);
$lnsplitreminit = array_slice($lnsplit, 2);
$lnsplitrem = implode(":", $lnsplitreminit);
$lndircolor = $lnsplit[0] . ":" . $lnsplit[1];
$lndirsplit = explode("/", $lndircolor);
$lndirlast = end($lndirsplit);
reset($lndirsplit);
$lndirproc = array_pop($lndirsplit);
$lndirprocfin = implode("/", $lndirsplit);
$lncolored = "<font style='color:#008e61;font-weight:600;'>" . $lndirprocfin . "/</font><font style='color:#ff0000;'>" . $lndirlast . "</font> :" . $lnsplitrem;
$getdetmaillnarr[$p] = $lncolored;
$p++;
}
if (strpos($lnvalue, "---------------------------") !== false) {
$gosel = true;
}
}
$maildetlnbr = implode("<br><br>", $getdetmaillnarr);
}
} else { $mailfilecheck = false; }
// Search for the infected files lines in the Nextcloud scan report
if (is_file($nextdetectrep)) {
$nextfilecheck = true;
$readnextdetrep = file_get_contents($nextdetectrep);
$infectedfltxt = strstr($readnextdetrep, $targetstr);
$txtbreakln = explode("\n", $infectedfltxt);
$nbofinfectedinit = explode("Infected files: ", $txtbreakln[0]);
$nbinfctdflsnext = $nbofinfectedinit[1];
if ($nbinfctdflsnext != 0) {
$getdetnextlines = file($nextdetectrep);
$getdetnextlinesarr = array();
$goselnext = false;
$b = 0;
foreach ($getdetnextlines as $lnextkey => $lnextvalue) {
if (strpos($lnextvalue, "SCAN SUMMARY") !== false) {
$goselnext = false;
}
if (trim($lnextvalue) == '') { $goselnext = false; }
if ($goselnext) {
$lnextsplit = explode(":", $lnextvalue);
$lnextreminit = array_slice($lnextsplit, 1);
$lnextsplitrem = implode(":", $lnextreminit);
$lnextdirsplit = explode("/", $lnextsplit[0]);
$lnextend = end($lnextdirsplit);
reset($lnextdirsplit);
$lnextproc = array_pop($lnextdirsplit);
$lnextprocfin = implode("/", $lnextdirsplit);
$lnextcolored = "<font style='color:#008e61;font-weight:600;'>" . $lnextprocfin . "/</font><font style='color:#ff0000;'>" . $lnextend . "</font> :" . $lnextsplitrem;
$getdetnextlinesarr[$b] = $lnextcolored;
$b++;
}
if (strpos($lnextvalue, "---------------------------") !== false) {
$goselnext = true;
}
}
$nextdetlnbr = implode("<br><br>", $getdetnextlinesarr);
}
} else { $nextfilecheck = false; }
if ($mailfilecheck == false && $nextfilecheck == false) {
$clamdetfilesmissing = "<div class='clamavnodir'>Error! The files containing the ClamAV antivirus detections weren't found ! Please verify that the detections directory
set up in 'Settings > Detections Directory' is correct and that the crontab jobs for ClamAV periodic scanning are correct.</div>";
} elseif ($mailfilecheck == false && $nextfilecheck == true) {
$clamdetfilesmissing = "<div class='clamavnodir'>Error! The file containing the detections made by ClamAV in the '/var/vmail' directory wasn't found ! Please verify ClamAV
status and the crontab jobs for ClamAV periodic scanning.</div>";
} elseif ($mailfilecheck == true && $nextfilecheck == false) {
$clamdetfilesmissing = "<div class='clamavnodir'>Error! The file containing the detections made by ClamAV in the '/var/www/cloud.example.com/data' directory wasn't
found ! Please verify ClamAV status and the crontab jobs for ClamAV periodic scanning.</div>";
} else $clamdetfilesmissing = "";
if (($maildetlnbr != "") && ($nextdetlnbr != "")) {
$clamavperiodicdetect = "<div id='clamavpozitive'><div class='clamavsectext'>ClamAV antivirus has made the following detections by periodic scanning:</div><br>
<ul><li class='virusesline'>Viruses detected in received emails directories (You should remove them manually):</li><br>" . $maildetlnbr . "</ul><br>
<ul><li class='virusesline'>Viruses detected in Nextcloud upload directories (You should remove them manually):</li><br>" . $nextdetlnbr . "</ul>
</div>";
} elseif (($maildetlnbr != "") && ($nextdetlnbr == "")) {
$clamavperiodicdetect = "<div id='clamavpozitive'><div class='clamavsectext'>ClamAV antivirus has made the following detections by periodic scanning:</div><br>
<ul><li class='virusesline'>Viruses detected in received emails directories (You should remove them manually):</li><br>" . $maildetlnbr . "</ul>
</div>" . $clamdetfilesmissing;
} elseif (($maildetlnbr == "") && ($nextdetlnbr != "")) {
$clamavperiodicdetect = "<div id='clamavpozitive'><div class='clamavsectext'>ClamAV antivirus has made the following detections by periodic scanning:</div><br>
<ul><li class='virusesline'>Viruses detected in Nextcloud upload directories (You should remove them manually):</li><br>" . $nextdetlnbr . "</ul>
</div>" . $clamdetfilesmissing;
} elseif ((($maildetlnbr == "") && ($nextdetlnbr == "")) && ($mailfilecheck == true && $nextfilecheck == true)) {
$clamavperiodicdetect = "<div class='clamavperdetect'><div id='clamavnodet'>ClamAV didn't detect any problems by periodic scanning !</div><img id='ok-sign-clamav'
src='images/ok_sign.svg' alt=''></div>";
} elseif ((($maildetlnbr == "") && ($nextdetlnbr == "")) && ($mailfilecheck == false && $nextfilecheck == false)) {
$clamavperiodicdetect = $clamdetfilesmissing;
} elseif ((($maildetlnbr == "") && ($nextdetlnbr == "")) && ($mailfilecheck == false && $nextfilecheck == true)) {
$clamavperiodicdetect = "<div class='clamavnodir'>Error! The file containing the detections made by ClamAV in the '/var/vmail' directory wasn't found ! Please verify ClamAV
status and the crontab jobs for ClamAV periodic scanning.</div>";
} elseif ((($maildetlnbr == "") && ($nextdetlnbr == "")) && ($mailfilecheck == true && $nextfilecheck == false)) {
$clamavperiodicdetect = "<div class='clamavnodir'>Error! The file containing the detections made by ClamAV in the '/var/www/cloud.example.com/data' directory wasn't
found ! Please verify ClamAV status and the crontab jobs for ClamAV periodic scanning.</div>";
}
echo $clamavperiodicdetect;
?>
</div>
</div>
</div>
</div> <!-- /# card -->
</div> <!-- /# column -->
</div> <!-- /# row -->
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h4 class="cardheader">Storage</h4>
<div class="flot-container">
<div id="useddiskspace">
<div id="pie-placeholder" class="flot"></div>
<div id="freediskspace">
<?php
// Get the total free storage space (in kibibytes) and if it is below the threashold of 3 GiB, display a warning
$diskthreshold = 3145728;
$freedisk = exec("df -x tmpfs --total | awk '{print $4}' | tail -1");
$totalspace = exec("df -x tmpfs --total | awk '{print $2}' | tail -1");
$freediskgb = round($freedisk / 1048576);
$totaldiskgb = round($totalspace / 1048576);
$totalusedspace = $totaldiskgb - $freediskgb;
if ($freedisk <= $diskthreshold){
$diskwarn = "You may consider removing unnecessary files, optimize data storage processes, upgrade your server, or your server's storage.";
} else $diskwarn = null;
// Include an info line about the free storage space
$infodisk = "The total free storage space on all partitions of this system is approximately<font style='color: #0082cd; font-weight: bold;'> ".$freediskgb." </font><a style='color: #0082cd; font-weight: bold; text-decoration: underline;' href='https://en.wikipedia.org/wiki/Gibibyte' target='_blank'>gibibytes</a> from a total of <font style='color: #00a859; font-weight: bold;'> ".$totaldiskgb." gibibytes.</font></b>";
echo $infodisk . "<br><br>" . $diskwarn;
?>
</div>
</div>
</div>
</div>
</div> <!-- /# card -->
</div> <!-- /# column -->
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h4 class="cardheader">Network Usage</h4>
<div class="flot-container">
<div class="totalnetrow">
<?php
$int = exec("ip addr | awk '/state UP/ {print $2}' | sed 's/.$//'");
$transmitted = file_get_contents("/sys/class/net/".$int."/statistics/tx_bytes");
$received = file_get_contents("/sys/class/net/".$int."/statistics/rx_bytes");
$transDropped = file_get_contents("/sys/class/net/".$int."/statistics/tx_dropped");
$recDropped = file_get_contents("/sys/class/net/".$int."/statistics/rx_dropped");
$txErrors = file_get_contents("/sys/class/net/".$int."/statistics/tx_errors");
$rxErrors = file_get_contents("/sys/class/net/".$int."/statistics/rx_errors");
$totalSent = round(intval($transmitted)/1073741824, 2);
$totalReceived = round(intval($received)/1073741824, 2);
$txDropped = round(intval($transDropped)/1048576, 2);
$rxDropped = round(intval($recDropped)/1048576, 2);
print_r("<div class='networkinfo' >Total Sent: <font color='#06699b'>" . $totalSent . " GiB</font> • Total Received: <font color='#06699b'>" . $totalReceived . " GiB</font></br>TX Dropped: <font color='#06699b'>" . $txDropped . " MiB</font> • RX Dropped: <font color='#06699b'>" . $rxDropped . " MiB</font> • TX Errors: <font color='#06699b'>" . $txErrors . "</font> • RX Errors: <font color='#06699b'>" . $rxErrors . "</font></div>");
?>
</div>
<div id="net-usage-placeholder"></div>
</div>
</div>
</div>
</div>
</div> <!-- /# row -->
<script type="text/javascript">
var usedspace = "<?php print_r($totalusedspace); ?>";
var freespace = "<?php print_r($freediskgb); ?>";
var data = [{
label: "Used Space",
data: usedspace,
color: '#cc2c52'
}, {
label: "Free Space",
data: freespace,
color: '#0895e0'
}];
function labelFormatter(label, series) {
return "<div style='font-size:13px; text-align: center; color: white; font-weight: bold;'>" + series.data[0][1] + " GiB <br>" + label + "</div>";
}
var options = {
series: {
pie: {
show: true,
radius: 1,
label: {
show: true,
radius: 0.52,
threshold: 0.1,
formatter: labelFormatter
}
}
},
grid: {
hoverable: true,
clickable: true
},
tooltip: true,
tooltipOpts: {
cssClass: "flotTip",
content: function(label, xval, yval) {
var content = yval +" GiB %s (%p.0%)";
return content;
},
shifts: {
x: 15,
y: 0
},
defaultTheme: false
}
};
$.plot($("#pie-placeholder"), data, options);
</script>
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h4 class="cardheader">CPU Usage</h4>
<div class="flot-container">
<div class="totalcpurow">
<?php
$resultcpu = shell_exec("cat /proc/cpuinfo | grep MHz | head -n 1");
$resultproc = explode(":", $resultcpu);
$resultprocfourth = str_replace(" ", "", $resultproc[1]);
$resultfin = "<font color='#06699b'>" . $resultprocfourth . "</font>";
$cpucores = exec("nproc");
$infocpu = "CPU MHz: " . $resultfin . " • CPU Cores: <font color='#06699b'>" . $cpucores . "</font>";
print_r($infocpu);
?>
</div>
<div id="cpu-usage-placeholder"></div>
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h4 class="cardheader">RAM Usage</h4>
<div class="flot-container">
<div class="totalramrow">
<?php
$stat1_init = shell_exec("free");
$stat1 = explode("\n", $stat1_init);
$ram1_init = explode(" ", $stat1[1]);
$getnonemptyram1 = array_filter(array_map('trim', $ram1_init));
$ram1 = array_values($getnonemptyram1);
$swap1_init = explode(" ", $stat1[2]);
$getnonemptyswap1 = array_filter(array_map('trim', $swap1_init));
$swap1 = array_values($getnonemptyswap1);
$ramtotal = $ram1[1];
$swaptotal = $swap1[1];
$totalRam = round($ramtotal / 1048576, 2);
$totalSwap = round($swaptotal / 1048576, 2);
print_r("Total RAM: <font color='#06699b'>" . $totalRam . " GiB</font> • Total SWAP: <font color='#06699b'>" . $totalSwap . " GiB</font>");
?>
</div>
<div id="ram-usage-placeholder"></div>
</div>
</div>
</div>
</div> <!-- /# column -->
</div> <!-- /# row -->
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<strong class="card-title">Components</strong>
</div>
<div class="card-body">
<table class="table">
<thead>
<tr>
<th scope="col">No</th>
<th scope="col">Component</th>
</tr>
</thead>
<tbody id="buttonTableTbody">
<?php
$sqlquery = $mysqli->query("SELECT id, orderno, component, componentrole, componentplace, imagename, versionscript, info
FROM components");
$getcompname = [];
while ($result_fetch = $sqlquery->fetch_row()) {
$inddbid = $result_fetch[0];
$comporderno = $result_fetch[1];
$componentname = $result_fetch[2];
$componentrole = $result_fetch[3];
$componentplace = $result_fetch[4];
$indimagename = $result_fetch[5];
$versionscript = $result_fetch[6];
$popupinfo = htmlspecialchars_decode($result_fetch[7]);
$getcompname[] = [$inddbid, $comporderno, $componentname, $componentrole, $componentplace, $indimagename,
$versionscript, $popupinfo];
}
$sqlquery->close();
$comptablerowsinit = [];
for ($r = 0; $r < count($getcompname); $r++) {
$compPlace = str_replace(" ","", $getcompname[$r][4]);
$compRole = str_replace(" ","", $getcompname[$r][3]);
if ($getcompname[$r][6] != '') {
if (strpos($getcompname[$r][6], ".php") !== false) {
$currentFunction = str_replace(".php", "", $getcompname[$r][6]);
$compVersion = $currentFunction();
} else { $compVersion = $getcompname[$r][6]; }
} else $compVersion = '';
$currentorderno = $getcompname[$r][1];
$comptablerowsinit[$currentorderno] = '<td class="componentOrder">'.$getcompname[$r][1].'</td><td><span class="'.$compPlace.' '.$compRole.'"><span class="componentLogo"><img src="images/components/'.$getcompname[$r][5].'" /></span><span class="componentName">'.$getcompname[$r][2].'</span><span class="versionData">'.$compVersion.'</span><span class="componentInfo"><img class="infopic" src="images/info-popup.svg"/><span class="popup-text">'.$getcompname[$r][7].'</span></span></span></td></tr>';
}
ksort($comptablerowsinit);
$comptablerows = array_combine(range(1, count($comptablerowsinit)), array_values($comptablerowsinit));
for ($n = 1; $n <= count($comptablerows); $n++) {
echo '<tr class="compTableRow"><td class="currentNmbr">'.$n.'</td>' . $comptablerows[$n];
}
?>
</tbody>
</table>
<table class="legendTable"><thead><tr><th class="headerBckgrnd">Color</th><th class="headerBckgrnd"></th><th class="headerBckgrnd">Indentation</th><th class="headerBckgrnd"></th></tr></thead><tbody><tr><td class="firstHalf"><img src="images/blue-square.png" class="legendColors" alt="blue square" /></td><td class="firstHalf">Kernel Component</td><td class="indentLevel secondHalf">First Level</td><td class="secondHalf">Operating system</td></tr><tr><td class="firstHalf"><img src="images/purple-square.png" class="legendColors" alt="purple square" /></td><td class="firstHalf">Shell Component</td><td class="indentLevel secondHalf">Second Level</td><td class="secondHalf">Applications installed inside the operating system</td></tr><tr><td class="firstHalf"><img src="images/green-square.png" class="legendColors" alt="green square" /></td><td class="firstHalf">Hull Component</td><td class="indentLevel secondHalf">Third Level</td><td class="secondHalf">Applications installed inside the preceding second level applications</td></tr></tbody></table>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<strong class="card-title">Launch Application</strong>
</div>
<div class="card-body">
<table id="dashboardButtons" class="table ">
<thead>
<tr>
<th scope="col">No</th>
<th scope="col">Application</th>
</tr>
</thead>
<tbody id="buttonTbody">
<?php
$buttonquery = $mysqli->query("SELECT orderno, nameonbutton, buttonurl, imgname FROM buttons");
$buttondata = [];
while ($results = $buttonquery->fetch_row()) {
$indorderno = $results[0];
$indnameonbutton = $results[1];
$indbuttonurl = $results[2];
$indimgname = $results[3];
$buttondata[] = [$indorderno, $indnameonbutton, $indbuttonurl, $indimgname];
}
$buttonquery->close();
$buttontablerowsinit = [];
for ($r = 0; $r < count($buttondata); $r++) {
$currentbuttonno = $buttondata[$r][0];
$buttontablerowsinit[$currentbuttonno] = '<td class="buttonOrder">'.$buttondata[$r][0].'</td><td><a class="appButton" href="'.$buttondata[$r][2].'" role="button" target="_blank"><img class="buttonImage" src="images/buttons/'.$buttondata[$r][3].'" />'.$buttondata[$r][1].'</a></td></tr>';
}
ksort($buttontablerowsinit);
$buttontablerows = array_combine(range(1, count($buttontablerowsinit)), array_values($buttontablerowsinit));
for ($b = 1; $b <= count($buttontablerows); $b++) {
echo '<tr class="btnTableRow"><td class="currentbtnNo">'.$b.'</td>' . $buttontablerows[$b];
}
?>
</tbody>
</table>
</div>
</div>
</div>
</div> <!-- /# row -->
<?php include 'about.php'; ?>
</div>
<!-- /.content -->
<div class="clearfix"></div>
<?php include 'footer.php'; ?>
</div>
<!-- /#right-panel -->
<button id="upBttn"></button>
</body>
</html>
<?php
} else {
header("Location: panel-login.php");
}
?>