Created
May 18, 2024 16:40
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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