mirvmon/src/Services/NotificationService.php

285 lines
11 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// src/Services/NotificationService.php
namespace App\Services;
use Config\DatabaseConfig;
class NotificationService
{
private $pdo;
private $settings;
public function __construct()
{
$this->pdo = DatabaseConfig::getInstance();
$this->loadSettings();
}
private function loadSettings()
{
$stmt = $this->pdo->prepare("SELECT * FROM global_notification_settings WHERE id = 1");
$stmt->execute();
$this->settings = $stmt->fetch();
}
/**
* Отправить уведомление о алерте
*/
public function sendAlertNotification($serverName, $metricName, $value, $severity, $threshold)
{
if ($severity === 'resolved') {
$severityText = 'ВОССТАНОВЛЕНИЕ';
$emoji = '✅';
$subject = "{$emoji} {$severityText}: {$metricName} в норме";
$message = "Сервер: {$serverName}\n";
$message .= "Метрика: {$metricName}\n";
$message .= "Текущее значение: {$value}\n";
$message .= "Статус: Порог более не превышен\n";
$message .= "Время: " . date('d.m.Y H:i:s');
} else {
$severityText = $severity === 'critical' ? 'КРИТИЧЕСКИЙ' : 'ПРЕДУПРЕЖДЕНИЕ';
$emoji = '🚨';
$subject = "{$emoji} {$severityText}: Превышение порога {$metricName}";
$message = "Сервер: {$serverName}\n";
$message .= "Метрика: {$metricName}\n";
$message .= "Значение: {$value}\n";
$message .= "Порог: {$threshold}\n";
$message .= "Время: " . date('d.m.Y H:i:s') . "\n";
$message .= "Серьёзность: {$severityText}";
}
// Отправка Email
if (!empty($this->settings['email_enabled']) && !empty($this->settings['smtp_host'])) {
$this->sendEmail($subject, $message);
}
// Отправка Telegram
if (!empty($this->settings['telegram_enabled']) && !empty($this->settings['telegram_bot_token'])) {
$this->sendTelegram($subject, $message);
}
}
/**
* Отправить тестовое уведомление
*/
public function sendTestNotification($email, $telegramChatId)
{
$subject = "✅ Тест уведомлений — Система мониторинга";
$message = "Это тестовое сообщение от системы мониторинга.\n";
$message .= "Время: " . date('d.m.Y H:i:s') . "\n";
$message .= "Если вы получили это сообщение — уведомления работают корректно.";
$results = [];
// Тест Email
if (!empty($email)) {
$results['email'] = $this->sendEmail($subject, $message, $email);
}
// Тест Telegram
if (!empty($telegramChatId)) {
$results['telegram'] = $this->sendTelegram($subject, $message, $telegramChatId);
}
return $results;
}
/**
* Отправить Email
*/
private function sendEmail($subject, $message, $overrideEmail = null)
{
$to = $overrideEmail ?? $this->settings['smtp_from_email'];
if (empty($to) || empty($this->settings['smtp_host'])) {
return ['success' => false, 'error' => 'Не настроен SMTP'];
}
$headers = "From: {$this->settings['smtp_from_email']}\r\n";
$headers .= "Reply-To: {$this->settings['smtp_from_email']}\r\n";
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
$headers .= "X-Mailer: PHP/" . phpversion();
// Если SMTP с авторизацией — используем PHPMailer через curl
if (!empty($this->settings['smtp_username'])) {
return $this->sendEmailViaSmtp($to, $subject, $message);
}
// Простая отправка через mail()
if (mail($to, $subject, $message, $headers)) {
return ['success' => true, 'message' => 'Email отправлен'];
} else {
return ['success' => false, 'error' => 'Ошибка отправки Email'];
}
}
/**
* Отправить через SMTP с авторизацией (curl)
*/
private function sendEmailViaSmtp($to, $subject, $message)
{
$host = $this->settings['smtp_host'];
$port = $this->settings['smtp_port'];
$username = $this->settings['smtp_username'];
$password = $this->settings['smtp_password'];
$from = $this->settings['smtp_from_email'];
$encryption = $this->settings['smtp_encryption'];
// Формируем URL
$scheme = ($encryption === 'ssl') ? 'smtps' : 'smtp';
$url = "{$scheme}://{$host}:{$port}";
// Формируем email
$email = "Date: " . date('r') . "\r\n";
$email .= "From: {$from}\r\n";
$email .= "To: {$to}\r\n";
$email .= "Subject: =?UTF-8?B?" . base64_encode($subject) . "?=\r\n";
$email .= "Content-Type: text/plain; charset=UTF-8\r\n";
$email .= "\r\n" . $message . "\r\n";
// Используем curl для отправки через SMTP
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_MAIL_FROM, $from);
curl_setopt($ch, CURLOPT_MAIL_RCPT, [$to]);
curl_setopt($ch, CURLOPT_UPLOAD, true);
curl_setopt($ch, CURLOPT_READDATA, fopen('php://temp', 'r+'));
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($email));
curl_setopt($ch, CURLOPT_USERNAME, $username);
curl_setopt($ch, CURLOPT_PASSWORD, $password);
curl_setopt($ch, CURLOPT_USE_SSL, ($encryption === 'none') ? CURLUSESSL_NONE : CURLUSESSL_ALL);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Для отправки через curl нужно записать данные в stream
$temp = fopen('php://temp', 'w+');
fwrite($temp, $email);
rewind($temp);
curl_setopt($ch, CURLOPT_INFILE, $temp);
curl_setopt($ch, CURLOPT_UPLOAD, true);
$result = curl_exec($ch);
$error = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
fclose($temp);
if ($result !== false && in_array($httpCode, [250, 221])) {
return ['success' => true, 'message' => 'Email отправлен через SMTP'];
} else {
return ['success' => false, 'error' => "SMTP ошибка: " . ($error ?: "HTTP {$httpCode}")];
}
}
/**
* Отправить Telegram сообщение
*/
private function sendTelegram($subject, $message, $overrideChatId = null)
{
$botToken = $this->settings['telegram_bot_token'];
$chatId = $overrideChatId ?? $this->settings['telegram_chat_id'];
if (empty($botToken) || empty($chatId)) {
return ['success' => false, 'error' => 'Не настроен Telegram'];
}
$text = "<b>{$subject}</b>\n\n" . str_replace("\n", "\n", $message);
$url = "https://api.telegram.org/bot{$botToken}/sendMessage";
$postData = [
'chat_id' => $chatId,
'text' => $text,
'parse_mode' => 'HTML'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
// Настройки прокси для Telegram
$proxy = $this->settings['telegram_proxy'] ?? 'http://127.0.0.1:1081';
if (!empty($proxy)) {
curl_setopt($ch, CURLOPT_PROXY, $proxy);
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
}
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($response === false) {
return ['success' => false, 'error' => "Ошибка соединения: {$error}"];
}
$data = json_decode($response, true);
if ($httpCode === 200 && isset($data['ok']) && $data['ok']) {
return ['success' => true, 'message' => 'Telegram сообщение отправлено'];
} else {
$errorMsg = $data['description'] ?? 'Неизвестная ошибка';
return ['success' => false, 'error' => "Telegram API: {$errorMsg}"];
}
}
/**
* Получить настройки
*/
public function getSettings()
{
return $this->settings;
}
/**
* Сохранить настройки
*/
public function saveSettings($data)
{
$stmt = $this->pdo->prepare("
UPDATE global_notification_settings SET
smtp_host = :smtp_host,
smtp_port = :smtp_port,
smtp_username = :smtp_username,
smtp_password = :smtp_password,
smtp_encryption = :smtp_encryption,
smtp_from_email = :smtp_from_email,
telegram_bot_token = :telegram_bot_token,
telegram_chat_id = :telegram_chat_id,
telegram_proxy = :telegram_proxy,
email_enabled = :email_enabled,
telegram_enabled = :telegram_enabled,
notify_on_warning = :notify_on_warning,
notify_on_critical = :notify_on_critical
WHERE id = 1
");
$stmt->execute([
':smtp_host' => $data['smtp_host'] ?? '',
':smtp_port' => (int)($data['smtp_port'] ?? 587),
':smtp_username' => $data['smtp_username'] ?? '',
':smtp_password' => $data['smtp_password'] ?? '',
':smtp_encryption' => $data['smtp_encryption'] ?? 'tls',
':smtp_from_email' => $data['smtp_from_email'] ?? '',
':telegram_bot_token' => $data['telegram_bot_token'] ?? '',
':telegram_chat_id' => $data['telegram_chat_id'] ?? '',
':telegram_proxy' => $data['telegram_proxy'] ?? 'http://127.0.0.1:1081',
':email_enabled' => !empty($data['email_enabled']) ? 1 : 0,
':telegram_enabled' => !empty($data['telegram_enabled']) ? 1 : 0,
':notify_on_warning' => !empty($data['notify_on_warning']) ? 1 : 0,
':notify_on_critical' => !empty($data['notify_on_critical']) ? 1 : 0,
]);
// Перезагружаем настройки
$this->loadSettings();
return $this->settings;
}
}