= duration seconds // ============================================================================ function checkAlertDuration($alertKey, $conditionMet, $durationSeconds = 0) { if ($durationSeconds <= 0) { // No duration requirement - trigger immediately return $conditionMet; } $conn = getAlertConnection(); if (!$conn) { return $conditionMet; // Fallback to immediate if no DB } $now = date('Y-m-d H:i:s'); if ($conditionMet) { // Condition is currently true - check/update state $stmt = mysqli_prepare($conn, "SELECT condition_started FROM alert_condition_state WHERE alert_key = ?" ); if ($stmt) { mysqli_stmt_bind_param($stmt, 's', $alertKey); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $row = mysqli_fetch_assoc($result); mysqli_stmt_close($stmt); if ($row) { // Condition already being tracked - update last_seen $updateStmt = mysqli_prepare($conn, "UPDATE alert_condition_state SET last_seen = ? WHERE alert_key = ?" ); if ($updateStmt) { mysqli_stmt_bind_param($updateStmt, 'ss', $now, $alertKey); mysqli_stmt_execute($updateStmt); mysqli_stmt_close($updateStmt); } // Check if duration has been met $started = strtotime($row['condition_started']); $elapsed = time() - $started; return $elapsed >= $durationSeconds; } else { // First time seeing this condition - start tracking $insertStmt = mysqli_prepare($conn, "INSERT INTO alert_condition_state (alert_key, condition_started, last_seen) VALUES (?, ?, ?)" ); if ($insertStmt) { mysqli_stmt_bind_param($insertStmt, 'sss', $alertKey, $now, $now); mysqli_stmt_execute($insertStmt); mysqli_stmt_close($insertStmt); } return false; // Just started, duration not met yet } } } else { // Condition is false - clear the tracking state $deleteStmt = mysqli_prepare($conn, "DELETE FROM alert_condition_state WHERE alert_key = ?" ); if ($deleteStmt) { mysqli_stmt_bind_param($deleteStmt, 's', $alertKey); mysqli_stmt_execute($deleteStmt); mysqli_stmt_close($deleteStmt); } return false; } return $conditionMet; } // ============================================================================ // Alert Logging Function (throttled to once per minute per alert) // ============================================================================ function logAlert($alertType, $alertTag, $alertValue, $alertMessage, $threshold = null) { $conn = getAlertConnection(); if (!$conn) { return; } try { // Check throttle - only log once per minute per alert type+tag $alertKey = $alertType . ':' . $alertTag; $throttleCheck = mysqli_prepare($conn, "SELECT last_logged FROM alert_throttle WHERE alert_key = ? AND last_logged > DATE_SUB(NOW(), INTERVAL 1 MINUTE)" ); if ($throttleCheck) { mysqli_stmt_bind_param($throttleCheck, 's', $alertKey); mysqli_stmt_execute($throttleCheck); $result = mysqli_stmt_get_result($throttleCheck); $recentLog = mysqli_fetch_assoc($result); mysqli_stmt_close($throttleCheck); if ($recentLog) { return; // Skip - already logged within last minute } } // Log the alert $sourcePage = $_SERVER['PHP_SELF'] ?? 'unknown'; $stmt = mysqli_prepare($conn, "INSERT INTO alert_log (alert_type, alert_tag, alert_value, threshold_value, alert_message, source_page) VALUES (?, ?, ?, ?, ?, ?)" ); if ($stmt) { mysqli_stmt_bind_param($stmt, 'ssddss', $alertType, $alertTag, $alertValue, $threshold, $alertMessage, $sourcePage ); mysqli_stmt_execute($stmt); mysqli_stmt_close($stmt); // Update throttle timestamp $throttleUpdate = mysqli_prepare($conn, "INSERT INTO alert_throttle (alert_key, last_logged) VALUES (?, NOW()) ON DUPLICATE KEY UPDATE last_logged = NOW()" ); if ($throttleUpdate) { mysqli_stmt_bind_param($throttleUpdate, 's', $alertKey); mysqli_stmt_execute($throttleUpdate); mysqli_stmt_close($throttleUpdate); } } } catch (Exception $e) { // Silent fail - logging should never break the page error_log('Alert logging failed: ' . $e->getMessage()); } } // ============================================================================ // Alert Definitions (Now managed via alerts-admin.php) // ============================================================================ // All alerts are now loaded from the alert_definitions table below. // Use the admin panel at /alerts-admin.php to add, edit, or disable alerts. // ============================================================================ // Database-Driven Alerts (from alerts-admin.php) // ============================================================================ $alertConn = getAlertConnection(); if ($alertConn) { $defResult = mysqli_query($alertConn, "SELECT * FROM alert_definitions WHERE is_active = 1" ); if ($defResult) { while ($def = mysqli_fetch_assoc($defResult)) { $tagName = $def['tag_name']; $tagValue = $value[$tagName] ?? null; if ($tagValue === null) { continue; // Tag not found in current data } // Evaluate condition based on comparison operator $conditionMet = false; $threshold = floatval($def['threshold_value']); switch ($def['comparison']) { case '<': $conditionMet = ($tagValue < $threshold); break; case '<=': $conditionMet = ($tagValue <= $threshold); break; case '>': $conditionMet = ($tagValue > $threshold); break; case '>=': $conditionMet = ($tagValue >= $threshold); break; case '=': $conditionMet = ($tagValue == $threshold); break; case '!=': $conditionMet = ($tagValue != $threshold); break; } // Check duration requirement $alertKey = 'db_' . $def['id'] . '_' . $tagName; $durationMet = checkAlertDuration($alertKey, $conditionMet, intval($def['duration_seconds'])); if ($durationMet) { // Build message from template $alertMessage = str_replace( ['{value}', '{threshold}', '{tag}'], [$tagValue, $threshold, $tagName], $def['message_template'] ); $alerts[] = [ 'type' => $def['alert_type'], 'icon' => $def['icon'], 'tag' => $tagName, 'value' => $tagValue, 'threshold' => $threshold, 'display' => $def['display_alert'], 'message' => htmlspecialchars($alertMessage, ENT_QUOTES, 'UTF-8') ]; logAlert($def['alert_type'], $tagName, $tagValue, $alertMessage, $threshold); } } } } // ============================================================================ // Render Alerts (info alerts are logged only, not displayed) // ============================================================================ if (!empty($alerts)) { foreach ($alerts as $alert) { // Skip info alerts - they are logged but not displayed if ($alert['type'] === 'info') { continue; } // Skip alerts with display=0 (database-driven alerts can disable display) if (isset($alert['display']) && !$alert['display']) { continue; } $bgColor = '#c62828'; // danger (red) if ($alert['type'] === 'warning') { $bgColor = '#f57c00'; // warning (orange) } echo '