Каждый, кто хоть раз делал сайт с формой обратной связи или интернет-магазин, сталкивался с ситуацией: пользователь что-то сделал, а вы об этом не знаете. Или знаете, но только когда заглянули в админку. А если у вас 10 000 пользователей? Тогда без системы уведомлений — как без рук. В этой статье я покажу, как построить такую систему на PHP, начиная с простого и заканчивая современными подходами. Не переживайте, если вы новичок — объясню всё на пальцах, с примерами и лайфхаками.
Что такое уведомления и зачем они нужны
Уведомление — это способ сообщить пользователю или администратору о каком-то событии. Например, кто-то оставил комментарий, заказ, или на сервере произошла ошибка. Без уведомлений вы будете терять клиентов и время.
Уведомления бывают разные:
- Email-уведомления — классика, но письма могут теряться или попадать в спам.
- SMS — дорого, но срочно.
- Push-уведомления в браузере или на телефоне — требуют настройки.
- Внутренние уведомления (на самом сайте) — когда пользователь заходит, видит колокольчик с цифрой.
В этой статье мы сделаем внутренние уведомления и добавим email-рассылку. А для тех, кто хочет «реального времени», покажу, как подключить WebSockets.
С чего начать: база данных для уведомлений
Прежде чем писать код, нужно спроектировать таблицу для хранения уведомлений. Вот простая схема:
| Поле | Тип | Описание |
|---|---|---|
| id | INT AUTO_INCREMENT | Первичный ключ |
| user_id | INT | Кому адресовано |
| type | VARCHAR(50) | Тип (например, 'comment', 'order') |
| message | TEXT | Текст уведомления |
| is_read | BOOLEAN | Прочитано или нет |
| created_at | DATETIME | Когда создано |
Для начала этого достаточно. Если хотите хранить ссылку на переход, добавьте поле link — VARCHAR(255).
CREATE TABLE notifications (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
type VARCHAR(50) NOT NULL,
message TEXT NOT NULL,
is_read BOOLEAN DEFAULT FALSE,
link VARCHAR(255) DEFAULT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
Простой класс для работы с уведомлениями
Теперь напишем PHP-класс, который будет добавлять, получать и отмечать уведомления. Я использую PDO для работы с базой — это безопасно и удобно.
class Notification {
private $db;
public function __construct($pdo) {
$this->db = $pdo;
}
// Добавить уведомление
public function add($userId, $type, $message, $link = null) {
$stmt = $this->db->prepare("INSERT INTO notifications (user_id, type, message, link) VALUES (?, ?, ?, ?)");
$stmt->execute([$userId, $type, $message, $link]);
return $this->db->lastInsertId();
}
// Получить непрочитанные для пользователя
public function getUnread($userId) {
$stmt = $this->db->prepare("SELECT * FROM notifications WHERE user_id = ? AND is_read = FALSE ORDER BY created_at DESC");
$stmt->execute([$userId]);
return $stmt->fetchAll();
}
// Отметить как прочитанное
public function markAsRead($notificationId, $userId) {
$stmt = $this->db->prepare("UPDATE notifications SET is_read = TRUE WHERE id = ? AND user_id = ?");
$stmt->execute([$notificationId, $userId]);
}
// Получить количество непрочитанных
public function countUnread($userId) {
$stmt = $this->db->prepare("SELECT COUNT(*) FROM notifications WHERE user_id = ? AND is_read = FALSE");
$stmt->execute([$userId]);
return $stmt->fetchColumn();
}
}
Использовать просто:
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$notification = new Notification($pdo);
// Добавить уведомление для пользователя с id=1
$notification->add(1, 'order', 'Ваш заказ отправлен!', '/orders/123');
// Получить непрочитанные
$unread = $notification->getUnread(1);
Как показывать уведомления на сайте
Теперь сделаем так, чтобы пользователь видел свои уведомления. Обычно это колокольчик в шапке сайта с числом непрочитанных. Когда пользователь кликает — выпадает список.
Для этого понадобится HTML-разметка и немного JavaScript для AJAX-запросов. Сначала создадим PHP-скрипт, который вернёт данные в формате JSON.
// get_notifications.php
session_start();
require 'Notification.php';
// Предположим, пользователь авторизован и его id в сессии
$userId = $_SESSION['user_id'];
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$notification = new Notification($pdo);
$unread = $notification->getUnread($userId);
$count = $notification->countUnread($userId);
echo json_encode(['count' => $count, 'items' => $unread]);
Теперь HTML-часть с кнопкой и списком:
<div class="notification-wrapper">
<button id="notification-btn" class="notification-btn">
Уведомления <span id="notification-count">0</span>
</button>
<ul id="notification-list" class="notification-list" style="display: none;"></ul>
</div>
И JavaScript, который подгружает уведомления и обновляет счётчик:
document.getElementById('notification-btn').addEventListener('click', function() {
var list = document.getElementById('notification-list');
if (list.style.display === 'none') {
list.style.display = 'block';
loadNotifications();
} else {
list.style.display = 'none';
}
});
function loadNotifications() {
fetch('get_notifications.php')
.then(response => response.json())
.then(data => {
document.getElementById('notification-count').textContent = data.count;
var list = document.getElementById('notification-list');
list.innerHTML = '';
data.items.forEach(function(item) {
var li = document.createElement('li');
li.textContent = item.message;
if (item.link) {
var a = document.createElement('a');
a.href = item.link;
a.textContent = ' Перейти';
li.appendChild(a);
}
list.appendChild(li);
});
});
}
Обратите внимание: мы не используем jQuery, а работаем на чистом JS — это современно и быстро.
Отправка email-уведомлений: классика жанра
Иногда внутренних уведомлений мало. Например, пользователь хочет получать письма на почту. Для этого в PHP есть функция mail(), но она часто не работает на хостинге и письма попадают в спам. Лучше использовать библиотеку PHPMailer.
Сначала установите PHPMailer через Composer:
composer require phpmailer/phpmailer
Теперь напишем функцию отправки:
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
function sendEmail($to, $subject, $body) {
$mail = new PHPMailer(true);
try {
// Настройки сервера
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@example.com';
$mail->Password = 'your_password';
$mail->SMTPSecure = 'tls';
$mail->Port = 587;
// Отправитель и получатель
$mail->setFrom('noreply@example.com', 'Ваш сайт');
$mail->addAddress($to);
// Контент
$mail->isHTML(true);
$mail->Subject = $subject;
$mail->Body = $body;
$mail->AltBody = strip_tags($body);
$mail->send();
echo 'Письмо отправлено';
} catch (Exception $e) {
echo "Ошибка: {$mail->ErrorInfo}";
}
}
Теперь при добавлении уведомления можно вызывать и отправку письма. Но не делайте это синхронно, иначе страница будет грузиться долго. Лучше поставить задачу в очередь, например, через RabbitMQ или просто cron.
Реальное время: WebSockets и Pusher
Если вы хотите, чтобы уведомления появлялись мгновенно, без перезагрузки страницы, нужны WebSockets. Но реализовать их на чистом PHP сложно. Есть два пути:
- Использовать ReactPHP или Ratchet — это библиотеки для асинхронного PHP.
- Использовать готовые сервисы, например Pusher или Ably. Они предоставляют API и SDK.
Второй путь проще. Вот пример с Pusher:
require 'vendor/autoload.php';
$options = [
'cluster' => 'eu',
'useTLS' => true
];
$pusher = new Pusher\Pusher('key', 'secret', 'app_id', $options);
// Отправляем событие на канал user_1
$pusher->trigger('user_1', 'new-notification', ['message' => 'Привет!']);
А на клиенте подписываемся на канал и ловим событие:
// Подключаем библиотеку Pusher (можно через CDN)
Это отличный вариант для MVP. Но учтите, что бесплатный план Pusher имеет ограничения. Если проект серьёзный, лучше поднять свой WebSocket-сервер на Node.js или Go.
Оптимизация и лучшие практики
Чтобы система уведомлений работала быстро и не падала, следуйте простым правилам:
- Индексируйте таблицу по полям user_id и created_at. Это ускорит выборку.
- Не храните уведомления вечно. Раз в месяц удаляйте старые (например, старше 90 дней).
- Для массовой рассылки используйте очереди. Не отправляйте 1000 писем в одном цикле.
- Кэшируйте количество непрочитанных уведомлений, чтобы не нагружать базу.
Пример кэширования через Memcached:
$cache = new Memcached();
$cache->addServer('localhost', 11211);
$userId = 1;
$count = $cache->get('unread_count_' . $userId);
if ($count === false) {
// Запрос к БД
$count = $notification->countUnread($userId);
$cache->set('unread_count_' . $userId, $count, 60); // на 60 секунд
}
И не забывайте про безопасность: всегда проверяйте, что пользователь имеет право на просмотр уведомлений (по user_id).
Что в итоге
Мы разобрали, как создать систему уведомлений на PHP с нуля. Начали с таблицы, написали класс для работы с базой, добавили интерфейс с AJAX, настроили email-рассылку и даже заглянули в реальное время. Теперь вы можете добавить уведомления на свой сайт — это повысит вовлечённость пользователей и упростит вам жизнь.
Главное — не пытайтесь объять необъятное. Начните с простого, а потом улучшайте. И помните: код должен быть чистым и понятным, даже если это внутренний проект.



