diff --git a/monitor.log b/monitor.log index df96920..6dff0f0 100644 Binary files a/monitor.log and b/monitor.log differ diff --git a/monitor.php b/monitor.php index 2f92ed5..2a539e6 100644 --- a/monitor.php +++ b/monitor.php @@ -5,102 +5,125 @@ require_once __DIR__ . '/db/config.php'; $lockFile = __DIR__ . '/monitor.lock'; $fp = fopen($lockFile, 'c'); if (!flock($fp, LOCK_EX | LOCK_NB)) { - die("Another instance is already running.\n"); + // Silently exit if already running (good for cron) + exit(0); } echo "Monitoring started with Multi-Threading...\n"; function sendTelegramNotification($message) { - $db = db(); - $stmt = $db->query("SELECT name, value FROM settings WHERE name IN ('telegram_bot_token', 'telegram_chat_id')"); - $settings = []; - while ($row = $stmt->fetch()) { - $settings[$row['name']] = $row['value']; + try { + $db = db(); + $stmt = $db->query("SELECT name, value FROM settings WHERE name IN ('telegram_bot_token', 'telegram_chat_id')"); + $settings = []; + while ($row = $stmt->fetch()) { + $settings[$row['name']] = $row['value']; + } + + if (empty($settings['telegram_bot_token']) || empty($settings['telegram_chat_id'])) { + return; + } + + $url = "https://api.telegram.org/bot" . $settings['telegram_bot_token'] . "/sendMessage"; + $data = [ + 'chat_id' => $settings['telegram_chat_id'], + 'text' => $message, + 'parse_mode' => 'HTML' + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_exec($ch); + curl_close($ch); + } catch (Exception $e) { + // Suppress errors to not break the monitor loop } - - if (empty($settings['telegram_bot_token']) || empty($settings['telegram_chat_id'])) { - return; - } - - $url = "https://api.telegram.org/bot" . $settings['telegram_bot_token'] . "/sendMessage"; - $data = [ - 'chat_id' => $settings['telegram_chat_id'], - 'text' => $message, - 'parse_mode' => 'HTML' - ]; - - $ch = curl_init($url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); - curl_setopt($ch, CURLOPT_TIMEOUT, 10); - curl_exec($ch); - curl_close($ch); } +// Loop indefinitely while (true) { - $startLoop = microtime(true); - - $db = db(); - $urls = $db->query("SELECT * FROM urls WHERE is_active = 1")->fetchAll(); + try { + $db = db(); + $urls = $db->query("SELECT * FROM urls WHERE is_active = 1")->fetchAll(); - if (count($urls) > 0) { - $mh = curl_multi_init(); - $ch_list = []; + if (count($urls) > 0) { + $mh = curl_multi_init(); + $curl_arr = []; + $url_info = []; - foreach ($urls as $urlData) { - $ch = curl_init($urlData['url']); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HEADER, true); - curl_setopt($ch, CURLOPT_NOBODY, true); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($ch, CURLOPT_TIMEOUT, 5); - curl_multi_add_handle($mh, $ch); - $ch_list[(int)$ch] = [ - 'id' => $urlData['id'], - 'url' => $urlData['url'], - 'old_status' => $urlData['status'], - 'start_time' => microtime(true) - ]; - } - - $active = null; - do { - $mrc = curl_multi_exec($mh, $active); - } while ($mrc == CURLM_CALL_MULTI_PERFORM); - - while ($active && $mrc == CURLM_OK) { - if (curl_multi_select($mh) != -1) { - do { - $mrc = curl_multi_exec($mh, $active); - } while ($mrc == CURLM_CALL_MULTI_PERFORM); + // Add handles + foreach ($urls as $urlData) { + $ch = curl_init($urlData['url']); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, false); // We don't need body, just headers + curl_setopt($ch, CURLOPT_NOBODY, true); // HEAD request is faster + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 10s timeout + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + + curl_multi_add_handle($mh, $ch); + $curl_arr[] = $ch; + // Store info mapped by intval of handle + $url_info[(int)$ch] = $urlData; } - } - foreach ($ch_list as $ch_id => $data) { - $ch = null; - // Find the handle - foreach ($ch_list as $handle_id => $info) { - if ($handle_id == $ch_id) { - // This is tricky in PHP to get handle by int. - // Actually we can just keep the handles in an array. + // Execute handles + $active = null; + do { + $mrc = curl_multi_exec($mh, $active); + } while ($mrc == CURLM_CALL_MULTI_PERFORM); + + while ($active && $mrc == CURLM_OK) { + if (curl_multi_select($mh) != -1) { + do { + $mrc = curl_multi_exec($mh, $active); + } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } + + // Read results + foreach ($curl_arr as $ch) { + $ch_id = (int)$ch; + $urlData = $url_info[$ch_id]; + + $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $total_time = curl_getinfo($ch, CURLINFO_TOTAL_TIME); + $total_time_ms = round($total_time * 1000); + + // Determine new status: UP if 200-399 + $new_status = ($http_code >= 200 && $http_code < 400) ? 'UP' : 'DOWN'; + $old_status = $urlData['status']; + + // Update database + $stmt = $db->prepare("UPDATE urls SET status = ?, last_checked = NOW() WHERE id = ?"); + $stmt->execute([$new_status, $urlData['id']]); + + $stmt = $db->prepare("INSERT INTO logs (url_id, status, response_time, checked_at) VALUES (?, ?, ?, NOW())"); + $stmt->execute([$urlData['id'], $new_status, $total_time_ms]); + + // Check for status change and notify + if ($old_status && $old_status !== $new_status) { + $icon = $new_status === 'UP' ? '✅' : '🚨'; + $msg = "{$icon} Monitor Alert\n\n"; + $msg .= "URL: {$urlData['url']}\n"; + $msg .= "Status: {$new_status} (HTTP {$http_code})\n"; + $msg .= "Response: {$total_time_ms}ms"; + sendTelegramNotification($msg); + } + + curl_multi_remove_handle($mh, $ch); + curl_close($ch); + } + curl_multi_close($mh); } - - // Re-doing the loop for better handle management - foreach ($ch_list as $ch_int => $info) { - // Wait, I need the actual handle. - } + } catch (Exception $e) { + echo "Error: " . $e->getMessage() . "\n"; } - // SIMPLIFIED Sequential for stability if multi is complex in 1s loop - // Let's stick to sequential but optimized for now, or fix multi properly. - // Actually, curl_multi is better. Let's do it right. - - // (Self-correction: curl_multi is better but I need to store the handles properly) - - $endLoop = microtime(true); - // ... sleep ... - usleep(1000000); // Temporary simplified sleep -} + // Wait 30 seconds before next check + sleep(30); +} \ No newline at end of file