Skip to content

Instantly share code, notes, and snippets.

@x-magic
Created May 18, 2024 16:40
Show Gist options
  • Save x-magic/c13e0e6794c6b777db3efc1e6a2a9026 to your computer and use it in GitHub Desktop.
Save x-magic/c13e0e6794c6b777db3efc1e6a2a9026 to your computer and use it in GitHub Desktop.
A simple call-home alive check script based on server-side PHP and client-side curl/cron
<?php
/**
* A simple call-home alive check script based on server-side PHP and client-side curl/cron
*/
error_reporting(0);
ini_set('display_errors', 0);
date_default_timezone_set('Australia/Melbourne');
header('Content-Type: text/plain');
// Define host keys
const HOSTS = [
"00000000-0000-0000-0000-000000000000" => "My Router",
];
const FLAG_TIMESTAMP = "/tmp/alive_checkin_%s.flag";
const FLAG_DISCONNECTED = "/tmp/alive_disconnected_%s.flag";
/**
* Send PushOver notifications (without cURL extension)
*
* @param string $title Title of the notification
* @param string $message Notification body
* @param string $priority Message priority, refer to https://pushover.net/api#priority
*/
function pushover($title, $message, $priority) {
$result = @file_get_contents(
"https://api.pushover.net/1/messages.json",
false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query([
"token" => "-----PO_APP_TOKEN-----",
"user" => "-----PO_USER_KEY-----",
"title" => $title,
"message" => $message,
"priority" => $priority,
])
]
])
);
}
/**
* Create human readable time up to hours
*
* @param int $time Number of seconds to parse
* @return string Human readable time (e.g. 23 hours 15 minutes and 1 second)
*/
function time_readable($time) {
$hours = floor($time / 3600);
$readable_hours = $hours . " hour" . (($hours > 1) ? "s" : "");
$minutes = floor(($time % 3600) / 60);
$readable_minutes = $minutes . " minute" . (($minutes > 1) ? "s" : "");
$seconds = ($time % 3600) % 60;
$readable_seconds = $seconds . " second" . (($seconds > 1) ? "s" : "");
$readable = "";
if ($hours > 0) {
$readable .= $readable_hours;
if ($minutes > 0 && $seconds > 0)
$readable .= " ";
}
if ($minutes > 0) {
if ($hours > 0 && $seconds == 0)
$readable .= " and ";
$readable .= $readable_minutes;
}
if ($seconds > 0) {
if ($hours > 0 || $minutes > 0)
$readable .= " and ";
$readable .= $readable_seconds;
}
return $readable;
}
/**
* Process home call requests
*
* @param string $hostkey Host key of the monitoring target
*/
function action_ping($hostkey) {
$timestamp_file = sprintf(FLAG_TIMESTAMP, $hostkey);
$disconnected_file = sprintf(FLAG_DISCONNECTED, $hostkey);
$last_checkin = intval(@file_get_contents($timestamp_file));
// Write current timestamp as checkin time
file_put_contents($timestamp_file, time());
// Remove flag and notify on reconnection
if (file_exists($disconnected_file)) {
unlink($disconnected_file);
$offline = time() - $last_checkin;
pushover(
sprintf("%s is back online", HOSTS[$hostkey]),
sprintf(
"%s is back online. It was offline for\n%s",
HOSTS[$hostkey],
time_readable($offline)
),
0
);
}
}
/**
* Process check alive requests
*
* @param string $hostkey Host key of the monitoring target
*/
function action_check($hostkey) {
$timestamp_file = sprintf(FLAG_TIMESTAMP, $hostkey);
$disconnected_file = sprintf(FLAG_DISCONNECTED, $hostkey);
$last_checkin = intval(@file_get_contents($timestamp_file));
$last_checkin_readable = date('r', $last_checkin);
// Check if last checkin is < 60 seconds
if (time() - $last_checkin > 60) {
if (!file_exists($disconnected_file)) {
// Create flag and notify on first disconnection
file_put_contents($disconnected_file, "disconnected");
pushover(
sprintf("%s is offline!", HOSTS[$hostkey]),
sprintf(
"%s seems to be offline.\nLast check-in: %s",
HOSTS[$hostkey],
$last_checkin_readable
),
1
);
}
}
}
// Test if parameters are all present
foreach (['hostkey', 'action'] as $query) {
if (!array_key_exists($query, $_GET)) {
http_response_code(422);
die();
}
}
// Test if host key is valid
if (!array_key_exists($_GET['hostkey'], HOSTS)) {
http_response_code(403);
die();
}
// Process actions
switch($_GET['action']) {
case 'ping':
action_ping($_GET['hostkey']);
break;
case 'check':
action_check($_GET['hostkey']);
break;
default:
http_response_code(403);
die();
}
# Call server every minute
* * * * * /usr/bin/curl -m 10 "https://api.billgong.com/alive?hostkey=00000000-0000-0000-0000-000000000000&action=ping" >/dev/null 2>&1
# Server-side check client last check time - better wait a few seconds before checking in case the old timestamp exceeds the 60 seconds threshold
* * * * * sleep 15;/usr/bin/curl -m 10 "http://api.billgong.com/alive?hostkey=00000000-0000-0000-0000-000000000000&action=cron" >/dev/null 2>&1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment