285 lines
11 KiB
PHP
Executable File
285 lines
11 KiB
PHP
Executable File
<?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;
|
||
}
|
||
}
|