2025-03-18 21:43:21 +01:00

955 lines
32 KiB
PHP

<?php
$config = require '../config.php';
function get_mysqli(): MySQLi
{
global $config;
static $handle;
if (!isset($handle)) {
$handle = new MySQLi(
hostname: $config['db_host'],
username: $config['db_user'],
password: $config['db_pass'],
database: $config['db_database'],
);
// make sure that the timezone is set to UTC!!!
$handle->query("SET time_zone = '+00:00'");
}
return $handle;
}
function flash_message(string $msg, string $type = 'info', bool $unsafe = false): void
{
if (session_status() === PHP_SESSION_NONE)
session_start();
$types = [
"info",
"success",
"danger",
"warning"
];
if (!in_array($type, $types)) {
throw new InvalidArgumentException("Flash type: \"$type\" does not exist");
}
$key = 'flash_messages';
if (!isset($_SESSION[$key]))
{
$_SESSION[$key] = [];
}
if (count($_SESSION[$key]) >= 100)
{
$_SESSION[$key] = [];
throw new Exception('Too many flashed messages!');
}
$_SESSION[$key][] = [
"message" => ($unsafe) ? $msg : htmlspecialchars($msg),
"type" => $type
];
}
function get_flash_messages(): ?array
{
if (session_status() === PHP_SESSION_NONE)
session_start();
$key = 'flash_messages';
if (empty($_SESSION[$key])) {
return null;
}
$msgs = $_SESSION[$key];
$_SESSION[$key] = [];
return $msgs;
}
function page_header(string $title, array $toolbar_links = [])
{
$ref_uuid = filter_input(INPUT_GET, 'ref_uuid');
$prefer_ref_uuid = !empty($ref_uuid);
if ($prefer_ref_uuid) $ref_uuid = htmlspecialchars($ref_uuid);
$host = strtolower(filter_input(INPUT_GET, 'host'));
if (!empty($host) && !is_valid_host($host)) {
$host = NULL;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?=$title?></title>
<link rel="stylesheet" href="static/css/style.css">
<link rel="icon" type="image/svg+xml" href="static/img/logo.svg">
</head>
<body>
<header>
<nav>
<a href="?p=default<?=($prefer_ref_uuid ? '&ref_uuid=' . $ref_uuid : '') . (!empty($host) ? '&host=' . $host : '')?>">Pinglerr</a>
</nav>
</header>
<?php if (!empty($toolbar_links)): ?>
<div class="toolbar">
<nav>
Handling:
<?php foreach ($toolbar_links as $link): ?>
<span>[&nbsp;<a
<?php if(isset($link['type']) && $link['type'] === 'danger'): ?>
class="link-btn-danger"
<?php else: ?>
class="link-btn-normal"
<?php endif; ?>
href="<?=$link['href']?>"><?=$link['name']?></a>&nbsp;]</span>
<?php endforeach; ?>
</nav>
</div>
<?php endif; ?>
<main>
<?php
$flash_messages = get_flash_messages();
?>
<?php if(!empty($flash_messages)): ?>
<?php foreach ($flash_messages as $message): ?>
<?php if($message['type'] === 'info'): ?>
<div class="alert alert-info"><?=$message['message']?></div>
<?php endif; ?>
<?php if($message['type'] === 'success'): ?>
<div class="alert alert-success"><?=$message['message']?></div>
<?php endif; ?>
<?php if($message['type'] === 'danger'): ?>
<div class="alert alert-danger"><?=$message['message']?></div>
<?php endif; ?>
<?php if($message['type'] === 'warning'): ?>
<div class="alert alert-warning"><?=$message['message']?></div>
<?php endif; ?>
<?php endforeach ?>
<hr>
<?php endif; ?>
<?php
}
function page_footer()
{
?>
</main>
<script src="static/js/apexcharts.min.js"></script>
<script src="static/js/global.js"></script>
<footer>
<small>Laget av William for Altidata AS</small>
</footer>
</body>
</html>
<?php
}
function get_referer(): string
{
if (isset($_SERVER['HTTP_REFERER'])) {
return htmlspecialchars($_SERVER['HTTP_REFERER']);
}
return '?p=default';
}
function is_valid_host(string $host): bool
{
if (empty($host)) {
return false;
}
if (!filter_var(
$host, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)
) {
return false;
}
return true;
}
function suicide_user_bad_request(string $errormsg)
{
http_response_code(400);
page_header('Oops, dette var en feil');
?>
<h1>Kunne ikke fortsette</h1>
<p>Feilmelding: <?=htmlspecialchars($errormsg)?></p>
<a href="<?=get_referer()?>">Klikk her for å gå tilbake</a>
<?php
page_footer();
die();
}
function pinglerr_get_scan(?string $host = null, ?string $ref_uuid = null, ?string $scan_id = null, bool $must_be_active_or_waiting = true): ?array
{
if ($host !== null) {
$sql = "SELECT * FROM pinglerr_scans WHERE host = ? AND ref_uuid IS NULL";
$param = $host;
}
if ($ref_uuid !== null) {
$sql = "SELECT * FROM pinglerr_scans WHERE ref_uuid = ?";
$param = $ref_uuid;
}
if ($scan_id !== null) {
$sql = "SELECT * FROM pinglerr_scans WHERE id = ?";
$param = $scan_id;
}
if ($must_be_active_or_waiting) {
$sql = $sql . " AND status_code IN ('ACTIVE', 'WAITING')";
}
$stmt = get_mysqli()->prepare($sql);
$stmt->bind_param("s", $param);
$stmt->execute();
$result = $stmt->get_result();
$assoc = $result->fetch_assoc();
return $assoc;
}
function pinglerr_get_scan_history(?string $host = null, ?string $ref_uuid = null, ?int $max_rows = null): ?array
{
if ($host !== null) {
$sql = "SELECT * FROM pinglerr_scans WHERE host = ? AND ref_uuid IS NULL ORDER BY start_date DESC";
$param = $host;
}
if ($ref_uuid !== null) {
$sql = "SELECT * FROM pinglerr_scans WHERE ref_uuid= ? ORDER BY start_date DESC";
$param = $ref_uuid;
}
if ($max_rows !== null) {
$sql = $sql . ' LIMIT ' . $max_rows;
}
$scans = (function() use ($sql, $param): ?array
{
$stmt = get_mysqli()->prepare($sql);
$stmt->bind_param("s", $param);
$stmt->execute();
$result = $stmt->get_result();
$assoc_array = [];
while ($row = $result->fetch_assoc()) {
$assoc_array[] = $row;
}
if (empty($assoc_array)) {
return null;
}
return $assoc_array;
})();
return $scans;
}
$route['default'] = function()
{
$ref_uuid = filter_input(INPUT_GET, 'ref_uuid');
$prefer_ref_uuid = !empty($ref_uuid);
if ($prefer_ref_uuid) $ref_uuid = htmlspecialchars($ref_uuid);
$host = strtolower(filter_input(INPUT_GET, 'host'));
if (!empty($host) && !is_valid_host($host)) {
suicide_user_bad_request('Ugyldig vert adresse');
}
if ($prefer_ref_uuid) {
$scan = pinglerr_get_scan(ref_uuid: $ref_uuid);
} else {
$scan = pinglerr_get_scan(host: $host);
}
$function['show_form'] = function() use($ref_uuid, $prefer_ref_uuid, $host) {
?>
<h1>Pinglerr</h1>
<p>Sjekk tilkobling status til IP-adresse eller annen tjeneste</p>
<form method="POST" action="?p=start_scan">
<input style="width: 100%; box-sizing: border-box; padding: .5rem;" value="<?=$host?>" autocomplete="off" placeholder="Vertsnavn eller adresse som f.eks nrk.no, 192.168.1.1" type="text" name="host">
<?php if($prefer_ref_uuid): ?>
<br>
<br>
<label for="ref_uuid">Referanse</label>
<input style="width: 100%; box-sizing: border-box; padding: .5rem;" value="<?=$ref_uuid?>" autocomplete="off" placeholder="Referanse" type="text" name="ref_uuid">
<?php endif; ?>
<br>
<br>
<label for="time_limit">Hvor lenge skal denne kjøre?</label>
<select name="time_limit" id="time_limit">
<option value="600">10 minutter</option>
<option value="3600">1 time</option>
<option value="14400">4 timer</option>
<option value="28800">8 timer</option>
<option value="43200">12 timer</option>
<option value="86400">24 timer</option>
<option value="172800">2 døgn</option>
<option value="345600">4 døgn</option>
<option value="604800">1 uke</option>
</select>
<br>
<br>
<input style="width: 5rem; padding: .5rem;" type="submit" value="Sjekk" class="btn btn-primary btn-lg">
</form>
<?php
};
$function['show_scan_history'] = function() use($prefer_ref_uuid, $ref_uuid, $host) {
$show_full_history = boolval(filter_input(INPUT_GET, 'show_full_history'));
$max_rows = 10;
if ($show_full_history) {
$max_rows = 10000;
}
if ($prefer_ref_uuid) {
$scans = pinglerr_get_scan_history(ref_uuid: $ref_uuid, max_rows: $max_rows);
$current_scan = pinglerr_get_scan(ref_uuid: $ref_uuid);
} else {
$scans = pinglerr_get_scan_history($host, max_rows: $max_rows);
$current_scan = pinglerr_get_scan($host);
}
if (empty($scans)) {
return;
}
?>
<h1>Historikk</h1>
<p>Tidligere skanninger som er gjort på denne verten eller referanse.</p>
<table>
<tr>
<th>Start Dato</th>
<th>Handling</th>
</tr>
<?php foreach($scans as $scan): ?>
<tr>
<td class="dateConverter"><?=$scan['start_date']?></td>
<td>[&nbsp;<a class="link-btn-normal" href="?p=scan_details&scan_id=<?=$scan['id']?><?=($prefer_ref_uuid ? '&ref_uuid=' . $ref_uuid : '&host=' . $host)?>">Detaljer</a>&nbsp;]</td>
</tr>
<?php endforeach; ?>
</table>
<?php
};
$function['show_live_stats'] = function() use($scan, $ref_uuid, $prefer_ref_uuid)
{
?>
<form>
<label for="timeRangeSelector">Hent statistikk fra siste:</label>
<select name="timeRangeSelector" id="timeRangeSelector">
<option value="900">15 minutter</option>
<option value="1800">30 minutter</option>
<option value="3600">1 time</option>
<option value="14400">4 timer</option>
<option value="28800">8 timer</option>
<option value="43200">12 timer</option>
<option value="86400">24 timer</option>
<option value="Details">Fullstendig</option>
</select>
</form>
<hr>
<h1>Sanntid statistikk</h1>
<div class="sign-container">
<div class="sign">
<span class="sign-label" style="">Tilkobling</span><span class="sign-text" id="connection_status">Ukjent</span>
</div>
<div class="sign">
<span class="sign-label">Vert</span><span class="sign-text"><?=$scan['host']?></span>
</div>
<?php if($prefer_ref_uuid): ?>
<div class="sign">
<span class="sign-label">Referanse</span><span class="sign-text"><?=$scan['ref_uuid']?></span>
</div>
<?php endif; ?>
</div>
<br>
<div style="
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: .5rem;
">
<div style="padding: 0.5rem; background: #eee; border: 1px solid #ccc; text-align: center; border-radius: 0.25rem;">
<div>Ping (siste)</div>
<div style="font-size: 2rem;"><span id="ping">Vent</span></div>
</div>
<div style="padding: 0.5rem; background: #eee; border: 1px solid #ccc; text-align: center; border-radius: 0.25rem;">
<div style="">Pakke tap</div>
<div style="font-size: 2rem;"><span id="packet_loss">Vent</span></div>
</div>
<div style="padding: 0.5rem; background: #eee; border: 1px solid #ccc; text-align: center; border-radius: 0.25rem;">
<div style="">Suksess-rate</div>
<div style="font-size: 2rem;"><span id="uptime">Vent</span></div>
</div>
</div>
<br>
<div style="height: 15rem">
<div id="liveChart"></div>
</div>
<script src="static/js/live_stats.js"></script>
<?php
};
if (!empty($scan)) {
page_header('Pinglerr', toolbar_links: [
[
'href' => '?p=stop_scanning&scan_id=' . $scan['id'] . ($prefer_ref_uuid ? '&ref_uuid=' . $ref_uuid : '') . (!empty($host) ? '&host=' . $host : ''),
'name' => 'Stop skanning',
'type' => 'danger'
]
]);
} else {
page_header('Pinglerr');
}
?>
<?php if(!empty($scan)): ?>
<?=$function['show_live_stats']()?>
<?php endif;?>
<?php if(empty($scan)): ?>
<?=$function['show_form']()?>
<?php endif;?>
<?php if(!empty($host) || $prefer_ref_uuid): ?>
<?=$function['show_scan_history']();?>
<?php endif; ?>
<?php
page_footer();
};
$route['scan_details'] = function()
{
$ref_uuid = filter_input(INPUT_GET, 'ref_uuid');
$prefer_ref_uuid = !empty($ref_uuid);
if ($prefer_ref_uuid) $ref_uuid = htmlspecialchars($ref_uuid);
$scan_id = filter_input(INPUT_GET, 'scan_id');
if (empty($scan_id)) {
suicide_user_bad_request('scan_id kan ikke være tom!');
}
$scan = pinglerr_get_scan(
scan_id: $scan_id,
must_be_active_or_waiting: false
);
if (!$scan) {
suicide_user_bad_request('Fant ikke scan i databasen!');
}
if ($scan['status_code'] === 'WAITING') {
suicide_user_bad_request('Venter på at denne skanningen skal starte');
}
page_header('Detaljer - Pinglerr', toolbar_links: [
[
'href' => get_referer(),
'name' => 'Gå tilbake'
]
]);
?>
<h1>Fullstendig statistikk</h1>
<div class="sign-container">
<?php if($scan['status_code'] === 'ACTIVE'): ?>
<span class="sign"><span class="sign-label">Status</span><span class="sign-text alert-success">Aktiv</span></span>
<?php elseif($scan['status_code'] === 'DONE'): ?>
<span class="sign"><span class="sign-label">Status</span><span class="sign-text alert-info">Ferdig</span></span>
<?php endif; ?>
<span class="sign"><span class="sign-label">Vert</span><span class="sign-text"><?=$scan['host']?></span></span>
<span class="sign"><span class="sign-label">ID</span><span class="sign-text"><?=$scan_id?></span></span>
</div>
<div id="chartElement"></div>
<div id="brushChartElement"></div>
<script src="static/js/scan_history_details.js"></script>
<?php
page_footer();
};
$route['start_scan'] = function()
{
$ref_uuid = filter_input(INPUT_POST, 'ref_uuid');
$prefer_ref_uuid = !empty($ref_uuid);
if ($prefer_ref_uuid) $ref_uuid = htmlspecialchars($ref_uuid);
$host = strtolower(filter_input(INPUT_POST, 'host'));
if (!is_valid_host($host)) {
if ($prefer_ref_uuid) {
header('Location: ?p=default&host=' . $host . '&ref_uuid=' . $ref_uuid);
} else {
header('Location: ?p=default&host=' . $host);
}
flash_message('Kunne ikke starte ny skanning: ugyldig vert adresse!', 'danger');
die();
}
if ($prefer_ref_uuid) {
$scan = pinglerr_get_scan(ref_uuid: $ref_uuid);
} else {
$scan = pinglerr_get_scan($host);
}
// if scan is not active or waiting
if ($scan === null) {
$stmt = get_mysqli()->prepare(
"INSERT INTO pinglerr_scans (host, ref_uuid, status_code, end_date) VALUES (?, ?, ?, NOW() + INTERVAL ? SECOND)"
);
$status_code = 'WAITING';
$time_limit_in_seconds = filter_input(INPUT_POST, 'time_limit');
if (!is_numeric($time_limit_in_seconds))
suicide_user_bad_request('time_limit is not numeric');
if ($time_limit_in_seconds > 31536000)
suicide_user_bad_request('time_limit should not be above 1 year');
if ($time_limit_in_seconds < 0)
suicide_user_bad_request('time_limit should not be a negative value');
// run forever
if ($time_limit_in_seconds == 0)
$time_limit_in_seconds = 315569260;
$stmt->bind_param("sssi", $host, $ref_uuid, $status_code, $time_limit_in_seconds);
$stmt->execute();
} else {
flash_message('Det eksisterer allerede en aktiv skanning på denne verten eller referansen');
if ($prefer_ref_uuid) {
header('Location: ?p=default&ref_uuid=' . $ref_uuid);
} else {
header('Location: ?p=default&host=' . $host);
}
die();
}
if ($prefer_ref_uuid) {
header('Location: ?p=default&ref_uuid=' . $ref_uuid);
} else {
header('Location: ?p=default&host=' . $host);
}
};
$route['stop_scanning'] = function()
{
$confirm = filter_input(INPUT_GET, 'confirm');
$scan_id = filter_input(INPUT_GET, 'scan_id');
$ref_uuid = filter_input(INPUT_GET, 'ref_uuid');
$prefer_ref_uuid = !empty($ref_uuid);
if ($prefer_ref_uuid) $ref_uuid = htmlspecialchars($ref_uuid);
$host = strtolower(filter_input(INPUT_GET, 'host'));
if (!$prefer_ref_uuid && !empty($host) && !is_valid_host($host)) {
suicide_user_bad_request('Ugyldig vertsnavn');
}
if (boolval($confirm)) {
$scan = pinglerr_get_scan(scan_id: $scan_id);
if (empty($scan)) {
suicide_user_bad_request('Fant ikke noen aktiv skanning');
}
$stmt = get_mysqli()->prepare(
"UPDATE pinglerr_scans SET status_code = ?, end_date = NOW(), error_message = ? WHERE status_code IN ('ACTIVE', 'WAITING') AND id = ?"
);
$status_code = 'DONE';
$error_message = 'Manually stopped by user';
$stmt->bind_param("sss",
$status_code,
$error_message,
$scan['id']
);
$stmt->execute();
if ($prefer_ref_uuid) {
header('Location: ?p=default&host=' . $host . '&ref_uuid=' . $ref_uuid);
} else {
header('Location: ?p=default&host=' . $host);
}
flash_message('Du har nå stanset skanningen', 'success');
die();
} else {
page_header('Er du sikker? - Pingler');
?>
<h1>Er du sikker?</h1>
<p>Vil du virkelig stanse denne skanningen?</p>
<span>[&nbsp;<a class="link-btn-success" href="?p=stop_scanning&confirm=true&scan_id=<?=htmlspecialchars($scan_id)?><?=($prefer_ref_uuid ? '&ref_uuid=' . $ref_uuid : '') . (!empty($host) ? '&host=' . $host : '')?>">Ja det vil jeg!</a>&nbsp;]</span>
<span>[&nbsp;<a class="link-btn-danger" href="<?=get_referer()?>">Nei ta meg tilbake igjen</a>&nbsp;]</span>
<?php
page_footer();
}
};
$route['daemon_poll'] = function()
{
$scans = (function(): ?array {
$stmt = get_mysqli()->prepare(
"SELECT * FROM pinglerr_scans WHERE status_code IN ('ACTIVE', 'WAITING')"
);
$stmt->execute();
$result = $stmt->get_result();
$assoc_array = [];
while ($row = $result->fetch_assoc()) {
$assoc_array[] = $row;
}
return $assoc_array;
})();
header('Content-type: application/json');
echo json_encode($scans);
};
// not in use anymore, replaced with daemon_bulk_update
$route['daemon_update'] = function()
{
$scan_id = filter_input(INPUT_GET, 'scan_id');
if (empty($scan_id)) {
suicide_user_bad_request('Mangler scan_id query parameter');
}
$scan = pinglerr_get_scan(scan_id: $scan_id);
if ($scan === null) {
suicide_user_bad_request('Kunne ikke finne scan fra scan_id');
}
// if time is up change the status to DONE and also exit the script
// TODO: this would probably be more suitable in the route daemon_jobs or some other
// endpoint that the daemon would periodically call
(function() use($scan)
{
$current_epoch = time();
$end_epoch = strtotime($scan['end_date']);
if ($current_epoch > $end_epoch) {
$stmt = get_mysqli()->prepare(
"UPDATE pinglerr_scans SET status_code = ?, error_message = ? WHERE status_code IN ('ACTIVE', 'WAITING') AND id = ?"
);
$status_code = 'DONE';
$error_message = 'Stopped because end_date was reached';
$stmt->bind_param("sss",
$status_code,
$error_message,
$scan['id']
);
$stmt->execute();
die();
}
})();
// set scan status from WAITING to ACTIVE
(function() use($scan)
{
$stmt = get_mysqli()->prepare(
"UPDATE pinglerr_scans SET status_code = ? WHERE id = ?"
);
$status_code = 'ACTIVE';
$stmt->bind_param("si",
$status_code,
$scan['id'],
);
$stmt->execute();
})();
(function() use($scan)
{
$pkt_transmitted = filter_input(INPUT_GET, 'pkt_transmitted');
$pkt_received = filter_input(INPUT_GET, 'pkt_received');
$ping_avg = filter_input(INPUT_GET, 'ping_avg');
$stmt = get_mysqli()->prepare(
"INSERT INTO pinglerr_pings (scan_id, ping_avg, pkt_transmitted, pkt_received) VALUES (?,?,?,?)"
);
$stmt->bind_param("idii",
$scan['id'],
$ping_avg,
$pkt_transmitted,
$pkt_received,
);
$stmt->execute();
})();
};
$route['daemon_bulk_update'] = function()
{
$bulk_pings = json_decode(file_get_contents('php://input'), true);
foreach ($bulk_pings as $ping) {
$scan_id = $ping['scan_id'];
$pkt_transmitted = $ping['pkt_transmitted'];
$pkt_received = $ping['pkt_received'];
if (!isset($ping['ping_avg'])) {
$ping_avg = null;
} else {
$ping_avg = $ping['ping_avg'];
}
$scan = pinglerr_get_scan(scan_id: $scan_id);
if ($scan === null) {
suicide_user_bad_request('Kunne ikke finne scan for scan_id');
}
$time_is_up = (function() use($scan)
{
$current_epoch = time();
$end_epoch = strtotime($scan['end_date']);
if ($current_epoch > $end_epoch) {
$stmt = get_mysqli()->prepare(
"UPDATE pinglerr_scans SET status_code = ?, error_message = ? WHERE status_code IN ('ACTIVE', 'WAITING') AND id = ?"
);
$status_code = 'DONE';
$error_message = 'Stopped because end_date was reached';
$stmt->bind_param("sss",
$status_code,
$error_message,
$scan['id']
);
$stmt->execute();
return true;
}
return false;
})();
if ($time_is_up) {
continue;
}
// set scan status from WAITING to ACTIVE
(function() use($scan)
{
$stmt = get_mysqli()->prepare(
"UPDATE pinglerr_scans SET status_code = ? WHERE id = ?"
);
$status_code = 'ACTIVE';
$stmt->bind_param("si",
$status_code,
$scan['id'],
);
$stmt->execute();
})();
(function() use($scan, $pkt_transmitted, $pkt_received, $ping_avg)
{
$stmt = get_mysqli()->prepare(
"INSERT INTO pinglerr_pings (scan_id, ping_avg, pkt_transmitted, pkt_received) VALUES (?,?,?,?)"
);
$stmt->bind_param("idii",
$scan['id'],
$ping_avg,
$pkt_transmitted,
$pkt_received,
);
$stmt->execute();
})();
}
};
$route['api_chart'] = function()
{
$scan_id = filter_input(INPUT_GET, 'scan_id');
$since = intval(filter_input(INPUT_GET, 'since'));
$limit_length = intval(filter_input(INPUT_GET, 'limit_length'));
$pings = (function() use($scan_id, $since): array
{
$stmt = get_mysqli()->prepare(
"SELECT ping_avg, pkt_transmitted, pkt_received, date_added FROM pinglerr_pings WHERE scan_id = ? AND date_added > FROM_UNIXTIME(?) ORDER BY date_added ASC"
);
$stmt->bind_param("ii", $scan_id, $since);
$stmt->execute();
$result = $stmt->get_result();
$assoc_array = [];
while ($row = $result->fetch_assoc()) {
$assoc_array[] = $row;
}
return $assoc_array;
})();
if (empty($pings)) {
http_response_code(204);
die();
}
if ($limit_length > 0 && $limit_length < count($pings)) {
$merged_pings = [];
$merge_gap = count($pings) / $limit_length;
$merge_iteration = 0;
$merge_remainder = 0;
$ping_avg_sum_storage = [];
$ping_pkt_transmitted_storage = [];
$ping_pkt_received_storage = [];
foreach ($pings as $ping) {
if ($merge_iteration >= $merge_gap - $merge_remainder) {
$merge_remainder+= $merge_iteration - $merge_gap;
$how_many_nulls = 0;
for ($i=0; $i < count($ping_avg_sum_storage); $i++) {
if ($ping_avg_sum_storage[$i] === null) {
$how_many_nulls++;
}
}
if ($how_many_nulls > count($ping_avg_sum_storage) / 2) {
$ping_avg = null;
} else {
for ($i=0; $i < count($ping_avg_sum_storage); $i++) {
if ($ping_avg_sum_storage[$i] === null) {
unset($ping_avg_sum_storage[$i]);
}
}
$ping_avg = round(array_sum($ping_avg_sum_storage) / count($ping_avg_sum_storage), 3);
}
$merged_pings[] = [
'ping_avg' => $ping_avg,
'date_added' => $ping['date_added'],
'pkt_transmitted' => round(array_sum($ping_pkt_transmitted_storage) / count($ping_pkt_transmitted_storage), 3),
'pkt_received' => round(array_sum($ping_pkt_received_storage) / count($ping_pkt_received_storage), 3),
];
$ping_pkt_transmitted_storage = [];
$ping_pkt_received_storage = [];
$ping_avg_sum_storage = [];
$merge_iteration = 0;
}
$ping_pkt_transmitted_storage[] = $ping['pkt_transmitted'];
$ping_pkt_received_storage[] = $ping['pkt_received'];
$ping_avg_sum_storage[] = $ping['ping_avg'];
$merge_iteration++;
}
$pings = $merged_pings;
}
//echo 'Gap: ' . htmlspecialchars($merge_gap) . ' Antall: ' . count($pings) . ' Remains: ' . $merge_remainder;
//die();
header('Content-type: application/json');
echo json_encode([
'latest' => strtotime($pings[count($pings) - 1]['date_added']),
'pings' => $pings,
]);
};
$route['api_stats'] = function()
{
$ref_uuid = filter_input(INPUT_GET, 'ref_uuid');
$prefer_ref_uuid = !empty($ref_uuid);
if ($prefer_ref_uuid) $ref_uuid = htmlspecialchars($ref_uuid);
$host = strtolower(filter_input(INPUT_GET, 'host'));
if (!$prefer_ref_uuid && !empty($host) && !is_valid_host($host)) {
suicide_user_bad_request('Ugyldig vertsnavn');
}
$scan_id = filter_input(INPUT_GET, 'scan_id');
if ($prefer_ref_uuid) {
$scan = pinglerr_get_scan(ref_uuid: $ref_uuid);
} elseif(!empty($host)) {
$scan = pinglerr_get_scan($host);
} elseif(!empty($scan_id)) {
$scan = pinglerr_get_scan(
scan_id: $scan_id,
must_be_active_or_waiting: false
);
} else {
suicide_user_bad_request('Mangler ref_uuid, host eller scan_id parameter');
}
if ($scan === null) {
suicide_user_bad_request('Kunne ikke finne noen aktive skanninger for denne verten eller referanse');
}
$since = intval(filter_input(INPUT_GET, 'since'));
$pings = (function() use($scan, $since): array
{
$stmt = get_mysqli()->prepare(
"SELECT * FROM pinglerr_pings WHERE scan_id = ? AND date_added > FROM_UNIXTIME(?) ORDER BY date_added DESC"
);
$stmt->bind_param("is", $scan['id'], $since);
$stmt->execute();
$result = $stmt->get_result();
$assoc_array = [];
while ($row = $result->fetch_assoc()) {
$assoc_array[] = $row;
}
return $assoc_array;
})();
if (empty($pings)) {
http_response_code(204);
die();
}
$pkt_transmitted = (function() use($pings): int {
$pkts = 0;
foreach ($pings as $ping_row) {
if ($ping_row['pkt_transmitted'] === null) {
continue;
}
$pkts = $pkts + $ping_row['pkt_transmitted'];
}
return $pkts;
})();
$pkt_received = (function() use($pings): int {
$pkts = 0;
foreach ($pings as $ping_row) {
if ($ping_row['pkt_received'] === null) {
continue;
}
$pkts = $pkts + $ping_row['pkt_received'];
}
return $pkts;
})();
$packet_loss_percentage = (function() use($pkt_transmitted, $pkt_received): float {
try {
$packet_loss_percentage = $pkt_received / $pkt_transmitted * 100;
} catch (\DivisionByZeroError $th) {
return 100;
}
if ($packet_loss_percentage > 100) {
$packet_loss_percentage = 100;
} else {
$packet_loss_percentage = 100 - $packet_loss_percentage;
}
return $packet_loss_percentage;
})();
// TODO: this is just packet_loss_percentage reversed! make a more proper uptime calculation
$uptime_percentage = (function() use($packet_loss_percentage): float {
return 100 - $packet_loss_percentage;
})();
// TODO: this is too simple, but it works for now. make a more proper calculation using jitter
$connection_status = (function() use($pings, $packet_loss_percentage) {
if ($pings[0]['ping_avg'] === null) {
return 'OFFLINE';
}
if ($packet_loss_percentage >= 2) {
return 'UNSTABLE';
}
return 'ONLINE';
})();
header('Content-type: application/json');
return json_encode([
'latest' => strtotime($pings[0]['date_added']),
'scan_id' => $scan['id'],
'host' => $scan['host'],
'ref_uuid' => $scan['ref_uuid'],
'status_code' => $scan['status_code'],
'connection_status' => $connection_status,
'pkt_transmitted' => $pkt_transmitted,
'pkt_received' => $pkt_received,
'ping_latest' => round($pings[0]['ping_avg'], 0, PHP_ROUND_HALF_EVEN),
'packet_loss_percentage' => round($packet_loss_percentage, 0, PHP_ROUND_HALF_UP),
'uptime_percentage' => round($uptime_percentage, 0, PHP_ROUND_HALF_DOWN),
]);
};
$page = filter_input(INPUT_GET, 'p');
if (empty($page)) {
$page = 'default';
}
if (isset($route[$page])) {
die($route[$page]());
}
http_response_code(404);
page_header('Kunne ikke finne siden')
?>
<h1>Siden ble ikke funnet</h1>
<a href="<?=get_referer()?>">Klikk her for å gå tilbake</a>
<?php
page_footer()
?>