Files
ISP-Billing/system/router_monitor.php
2026-01-16 12:25:08 +01:00

312 lines
10 KiB
PHP

<?php
/**
* Enhanced Router Monitoring Service
* Runs every 2 minutes to collect comprehensive router data
* Usage: */2 * * * * cd /var/www/html/newdesign1/system && php -f router_monitor.php
*/
include "../init.php";
$isCli = php_sapi_name() === 'cli';
if (!$isCli) {
echo "<pre>";
}
echo "Router Monitor Started: " . date('Y-m-d H:i:s') . "\n";
use PEAR2\Net\RouterOS;
use RouterOS\Exceptions\Socket\TimeoutException;
use RouterOS\Exceptions\Socket\ConnectionException;
class RouterMonitor {
private $config;
private $db;
public function __construct() {
global $config;
$this->config = $config;
}
/**
* Monitor all enabled routers
*/
public function monitorAllRouters() {
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
echo "Monitoring " . count($routers) . " routers...\n";
foreach ($routers as $router) {
$this->monitorRouter($router);
}
echo "Router monitoring completed: " . date('Y-m-d H:i:s') . "\n";
}
/**
* Monitor individual router
*/
private function monitorRouter($router) {
$routerId = $router['id'];
$routerName = $router['name'];
$ipAddress = $router['ip_address'];
echo "Checking router: $routerName ($ipAddress)...\n";
// Check if router is in circuit breaker state
if ($this->isCircuitBreakerActive($routerId)) {
echo " - Circuit breaker active, skipping\n";
$this->updateRouterStatus($router, 'Offline', 'Circuit breaker active');
return;
}
// Perform comprehensive check
$monitoringData = $this->performRouterCheck($router);
// Update database with results
$this->updateRouterData($router, $monitoringData);
// Check for alerts
$this->checkAlerts($router, $monitoringData);
}
/**
* Perform comprehensive router check
*/
private function performRouterCheck($router) {
$data = [
'timestamp' => date('Y-m-d H:i:s'),
'ping_status' => false,
'api_status' => false,
'uptime' => null,
'free_memory' => null,
'total_memory' => null,
'cpu_load' => null,
'temperature' => null,
'voltage' => null,
'error' => null
];
// Step 1: Ping check
$data['ping_status'] = $this->pingRouter($router['ip_address']);
if (!$data['ping_status']) {
$data['error'] = 'Ping failed';
return $data;
}
// Step 2: RouterOS API check
try {
$client = Mikrotik::getClient($router['ip_address'], $router['username'], $router['password'], 8);
if (!$client) {
$data['error'] = 'Failed to create RouterOS client';
return $data;
}
// Get system resource data
$resourceRequest = new RouterOS\Request('/system resource print');
$resourceResponse = $client->sendSync($resourceRequest, 5);
$resourceData = $resourceResponse->getAllOfType(RouterOS\Response::TYPE_DATA)[0];
// Get system health data
$healthRequest = new RouterOS\Request('/system health print');
$healthResponse = $client->sendSync($healthRequest, 5);
$healthData = $healthResponse->getAllOfType(RouterOS\Response::TYPE_DATA)[0];
// Extract data
$data['api_status'] = true;
$data['uptime'] = $resourceData->getProperty('uptime');
$data['free_memory'] = (int)$resourceData->getProperty('free-memory');
$data['total_memory'] = (int)$resourceData->getProperty('total-memory');
$data['cpu_load'] = (int)$resourceData->getProperty('cpu-load');
$data['temperature'] = $healthData->getProperty('temperature');
$data['voltage'] = $healthData->getProperty('voltage');
// Clear circuit breaker on successful connection
$this->clearCircuitBreaker($router['id']);
} catch (TimeoutException $e) {
$data['error'] = 'API timeout';
$this->incrementCircuitBreaker($router['id']);
} catch (ConnectionException $e) {
$data['error'] = 'API connection failed';
$this->incrementCircuitBreaker($router['id']);
} catch (Exception $e) {
$data['error'] = 'API error: ' . $e->getMessage();
$this->incrementCircuitBreaker($router['id']);
}
return $data;
}
/**
* Ping router
*/
private function pingRouter($ipAddress, $timeout = 5, $count = 3) {
$ipParts = explode(':', $ipAddress);
$ip = $ipParts[0];
$escapedIp = escapeshellarg($ip);
exec("ping -c $count -W $timeout $escapedIp 2>&1", $output, $returnVar);
return $returnVar === 0;
}
/**
* Update router status in database
*/
private function updateRouterStatus($router, $status, $error = null) {
$router->status = $status;
$router->last_check = date('Y-m-d H:i:s');
if ($error) {
$router->last_error = $error;
}
$router->save();
}
/**
* Update router data in database
*/
private function updateRouterData($router, $data) {
// Update main router table
$router->status = ($data['api_status'] && $data['ping_status']) ? 'Online' : 'Offline';
$router->last_check = $data['timestamp'];
$router->last_error = $data['error'];
$router->save();
// Store detailed monitoring data
$this->storeMonitoringData($router['id'], $data);
}
/**
* Store detailed monitoring data
*/
private function storeMonitoringData($routerId, $data) {
// Create monitoring record
$monitoring = ORM::for_table('tbl_router_monitoring')->create();
$monitoring->router_id = $routerId;
$monitoring->timestamp = $data['timestamp'];
$monitoring->ping_status = $data['ping_status'] ? 1 : 0;
$monitoring->api_status = $data['api_status'] ? 1 : 0;
$monitoring->uptime = $data['uptime'];
$monitoring->free_memory = $data['free_memory'];
$monitoring->total_memory = $data['total_memory'];
$monitoring->cpu_load = $data['cpu_load'];
$monitoring->temperature = $data['temperature'];
$monitoring->voltage = $data['voltage'];
$monitoring->error = $data['error'];
$monitoring->save();
// Clean up old records (keep last 7 days)
$cutoffDate = date('Y-m-d H:i:s', strtotime('-7 days'));
ORM::for_table('tbl_router_monitoring')
->where('timestamp', '<', $cutoffDate)
->delete_many();
}
/**
* Check for alerts
*/
private function checkAlerts($router, $data) {
$alerts = [];
// CPU load alert
if ($data['cpu_load'] && $data['cpu_load'] > 80) {
$alerts[] = "High CPU load: {$data['cpu_load']}%";
}
// Memory usage alert
if ($data['free_memory'] && $data['total_memory']) {
$memoryUsage = (($data['total_memory'] - $data['free_memory']) / $data['total_memory']) * 100;
if ($memoryUsage > 90) {
$alerts[] = "High memory usage: " . round($memoryUsage, 1) . "%";
}
}
// Temperature alert
if ($data['temperature'] && $data['temperature'] > 60) {
$alerts[] = "High temperature: {$data['temperature']}°C";
}
// Send alerts if any
if (!empty($alerts)) {
$this->sendAlerts($router, $alerts);
}
}
/**
* Send alerts
*/
private function sendAlerts($router, $alerts) {
$message = "Router {$router['name']} alerts:\n" . implode("\n", $alerts);
// Send to admin users
$users = ORM::for_table('tbl_users')->where('user_type', 'Admin')->find_many();
foreach ($users as $user) {
$this->sendSMS($user['phone'], $message);
$this->sendWhatsApp($user['phone'], $message);
}
}
/**
* Circuit breaker methods
*/
private function isCircuitBreakerActive($routerId) {
if (!function_exists('apcu_fetch')) return false;
$key = "router_failures_$routerId";
$timeKey = "router_failures_{$routerId}_time";
$failureCount = apcu_fetch($key) ?: 0;
$lastFailure = apcu_fetch($timeKey) ?: 0;
return $failureCount >= 3 && (time() - $lastFailure) < 300; // 5 minutes
}
private function incrementCircuitBreaker($routerId) {
if (!function_exists('apcu_store')) return;
$key = "router_failures_$routerId";
$timeKey = "router_failures_{$routerId}_time";
$failureCount = apcu_fetch($key) ?: 0;
apcu_store($key, $failureCount + 1, 300);
apcu_store($timeKey, time(), 300);
}
private function clearCircuitBreaker($routerId) {
if (!function_exists('apcu_delete')) return;
$key = "router_failures_$routerId";
$timeKey = "router_failures_{$routerId}_time";
apcu_delete($key);
apcu_delete($timeKey);
}
/**
* Send SMS
*/
private function sendSMS($phone, $message) {
// Implementation depends on your SMS provider
// This is a placeholder
echo "SMS to $phone: $message\n";
}
/**
* Send WhatsApp
*/
private function sendWhatsApp($phone, $message) {
// Implementation depends on your WhatsApp provider
// This is a placeholder
echo "WhatsApp to $phone: $message\n";
}
}
// Run the monitor
$monitor = new RouterMonitor();
$monitor->monitorAllRouters();
?>