<?php
require_once('.uptime/.config.php');
/**
* @author Gernot WALZL
*/
class Authenticator {
protected $config = null;
function __construct($config) {
$this->config = $config;
}
function authenticate() {
header('WWW-Authenticate: Basic');
header('HTTP/1.0 401 Unauthorized');
return false; // if user hits cancel
}
function verify($username, $password) {
$result = false;
if (isset($this->config->pass_hashes[$username])) {
$pass_hash = $this->config->pass_hashes[$username];
$result = password_verify($password, $pass_hash);
}
return $result;
}
}
/**
* @author Gernot WALZL
*/
class UptimeDAO {
function order_by(&$table, $field, $sort_type=SORT_ASC) {
$keys = array_column($table, $field);
array_multisort($keys, $sort_type, $table);
}
function get_local_uptime() {
$filepath = '/proc/uptime';
$result = array();
$result['hostname'] = 'localhost';
$result['last_update'] = time();
$result['uptime'] = strtok(file_get_contents($filepath), ' ');
return $result;
}
function get_uptime($hostname) {
if (false !== strpos($hostname, '..')) {
return null;
}
$filepath = dirname(__FILE__).'/.uptime/'.$hostname.'.uptime';
$result = null;
if (is_file($filepath)) {
$result = array();
$result['hostname'] = $hostname;
$result['last_update'] = filemtime($filepath);
$result['uptime'] = trim(file_get_contents($filepath));
}
return $result;
}
function get_uptimes() {
$result = null;
$path = dirname(__FILE__).'/.uptime';
if ($handle = opendir($path)) {
$result = array();
while (false !== ($entry = readdir($handle))) {
$filepath = $path.'/'.$entry;
if (is_file($filepath)) {
$path_parts = pathinfo($filepath);
if ($path_parts['extension'] === 'uptime') {
$record = $this->get_uptime($path_parts['filename']);
array_push($result, $record);
}
}
}
closedir($handle);
$this->order_by($result, 'hostname');
$record = $this->get_local_uptime();
array_unshift($result, $record);
}
return $result;
}
function update_uptime($hostname, $uptime) {
if (false !== strpos($hostname, '..')) {
return false;
}
$filename = dirname(__FILE__).'/.uptime/'.$hostname.'.uptime';
$result = false;
$fp = fopen($filename, 'w');
if ($fp) {
if (fwrite($fp, sprintf("%0.2f", $uptime)."\n") > 0) {
$result = true;
}
fclose($fp);
}
return $result;
}
}
/**
* @author Gernot WALZL
*/
class UptimeHTML {
function println($msg) {
print($msg."\n");
}
function print_head($title='Uptime') {
$this->println('<!DOCTYPE html>');
$this->println('<html lang="en">');
$this->println('<head>');
$this->println('<meta charset="utf-8" />');
$this->println('<title>'.$title.'</title>');
$this->println('<meta name="viewport" '.
'content="width=device-width, initial-scale=1.0" />');
$stylesheet = '.uptime/style.css';
$href = $stylesheet.'?mtime='.filemtime($stylesheet);
$this->println('<link rel="stylesheet" href="'.$href.'" />');
$this->println('</head>');
$this->println('<body>');
$this->println('<h1>'.$title.'</h1>');
}
function print_foot() {
$this->println('</body>');
$this->println('</html>');
}
function print_unauthorized() {
$this->println('<p>This server could not verify that you are '.
'authorized to access the document requested.</p>');
}
function print_usage() {
$this->println('<h2>Usage</h2>');
$this->println('<pre><code class="language-bash">');
?>
UPTIME=$(cut -d' ' -f1 /proc/uptime)
wget -q -O - --user="$USERNAME" --password="$PASSWORD" \
"https://gernot-walzl.at/uptime.php?update&hostname=$HOSTNAME&uptime=$UPTIME"
<?php
$this->println('</code></pre>');
}
function determine_state($last_update) {
$result = 'unknown';
$age = time() - intval($last_update);
if ($age <= 43200) {
$result = 'ok';
} else if ($age <= 86400) {
$result = 'warning';
} else {
$result = 'critical';
}
return $result;
}
function format_duration($seconds) {
$days = intval($seconds / 86400);
$seconds -= $days * 86400;
$hours = intval($seconds / 3600);
$seconds -= $hours * 3600;
$minutes = intval($seconds / 60);
$seconds -= $minutes * 60;
$seconds = intval($seconds);
return $days.'d '.$hours.'h '.$minutes.'m '.$seconds.'s';
}
function print_table_uptimes($table) {
$this->println('<table class="cellborders">');
$this->println('<tr>');
$this->println('<th>Hostname</th>');
$this->println('<th>Last Update ('.date('e').')</th>');
$this->println('<th>Duration</th>');
$this->println('</tr>');
foreach ($table as $row) {
$this->println('<tr>');
$this->println('<td>'.$row['hostname'].'</td>');
$state = $this->determine_state($row['last_update']);
$this->println('<td class="'.$state.'">'.
date('Y-m-d H:i:s', $row['last_update']).'</td>');
$this->println('<td>'.
$this->format_duration($row['uptime']).'</td>');
$this->println('</tr>');
}
$this->println('</table>');
}
}
if (!isset($_SERVER['HTTPS'])) {
header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
exit();
}
$config = new UptimeConfig();
$html = new UptimeHTML();
$auth = new Authenticator($config);
$user = '';
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
if ($auth->verify($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
$user = $_SERVER['PHP_AUTH_USER'];
}
}
if (empty($user)) {
if (!$auth->authenticate()) {
$html->print_head('401 Unauthorized');
$html->print_unauthorized();
$html->print_foot();
}
} else {
$html->print_head();
if (isset($_GET['update'])) {
$hostname = '';
if (isset($_GET['hostname'])) {
$hostname = $_GET['hostname'];
} else if (isset($_POST['hostname'])) {
$hostname = $_POST['hostname'];
}
if (empty($hostname)) {
$html->print_usage();
} else {
if (in_array($hostname, $config->hostnames[$user])) {
$uptime = 0.0;
if (isset($_GET['uptime'])) {
$uptime = floatval($_GET['uptime']);
} else if (isset($_POST['uptime'])) {
$uptime = floatval($_POST['uptime']);
}
$dao = new UptimeDAO();
$dao->update_uptime($hostname, $uptime);
$table[] = $dao->get_uptime($hostname);
$html->print_table_uptimes($table);
} else {
$html->println('<p>ERROR: Hostname not accepted.</p>');
}
}
} else {
$dao = new UptimeDAO();
$table = $dao->get_uptimes();
$html->print_table_uptimes($table);
}
$html->print_foot();
}
?>