Отправка push‑уведомлений на мобильные устройства с помощью PHP и Firebase

Краткое содержание
- Описание архитектуры и задействованных компонентов
- Создание проекта Firebase и получение Server Key
- Подготовка PHP‑приложения и примеры кода
- Регистрация токенов клиентов и хранение
- Формирование и отправка сообщений, обработка ответов
- Дополнительные параметры: data-поля, приоритет, TTL, значки на iOS
- Надёжность, обработка ошибок, безопасность и рекомендации по тестированию
Почему это важно
Push‑уведомления — основной инструмент вовлечения пользователей мобильных приложений. FCM упрощает работу с различными платформами и даёт единый API для отправки сообщений. Важные аспекты: корректная регистрация токенов, обработка ошибок доставки и защита серверных ключей.
Сопутствующие термины
- FCM: Firebase Cloud Messaging. Сервис доставки push‑уведомлений от Google.
- Server Key: конфиденциальный ключ сервера, используемый вашим бэкендом.
- FCM token / registration token: уникальный идентификатор устройства, получаемый клиентским SDK.
Описание архитектуры
Успешная доставка push‑уведомлений требует скоординированной работы нескольких компонентов:
- Firebase проект с включённым FCM и полученным Server Key.
- Клиентское приложение (iOS, Android, Web) с правильно интегрированным Firebase SDK, которое получает регистрационный токен.
- Бэкенд‑API на PHP, принимающее и сохраняющее клиентские токены и отправляющее уведомления через FCM.
Типичный поток данных:
- Клиент получает FCM токен через Firebase SDK и передаёт его бэкенду через защищённый API.
- Бэкенд сохраняет токен в базе данных (с привязкой к пользователю и устройству).
- При событии бэкенд формирует сообщение и отправляет его на FCM API, используя Server Key.
- FCM доставляет уведомление на целевые платформы (APNS для iOS, Google Play Services для Android).
- Бэкенд анализирует ответ FCM и при необходимости обновляет/удаляет токены.
Важно: FCM токен может поменяться (например, при переустановке приложения) — реализуйте механизм обновления токенов.
Создание проекта Firebase и получение Server Key

- Перейдите в Firebase Console и войдите в аккаунт Google.
- Нажмите кнопку «Добавить проект» и пройдите мастера настройки.
- В настройках проекта откройте вкладку «Cloud Messaging». Скопируйте Server Key — он понадобится серверу.

- Зарегистрируйте мобильные приложения (iOS/Android) в проекте и загрузите конфигурационные файлы (GoogleService-Info.plist для iOS и google-services.json для Android).

- Для iOS обязательно привяжите APNS ключ или сертификат в разделе Cloud Messaging, чтобы FCM мог доставлять сообщения через APNS.

Важно: Server Key и APNS ключ — секреты. Храните их за пределами репозитория и выдавайте только сервисам, которым доверяете.
Подготовка PHP‑приложения
Рекомендуется использовать Composer и библиотеку PHP‑FCM для удобства. Установка:
composer require sngrl/php-firebase-cloud-messagingВ исходной статье встречаются фрагменты с некорректно записанными use‑операторами. Ниже сохранён оригинал (не меняя формат):
use sngrlPhpFirebaseCloudMessagingClientClient;$client = new Client();
$client -> setApiKey(“FCM-SERVER-KEY”);
$client -> injectGuzzleHttpClient(new GuzzleHttpClient());
Рекомендация: используйте корректные пространства имён и нормальную инициализацию. Исправленный и рабочий пример инициализации клиента с Guzzle:
use sngrl\Firebase\Firebase; // пример пространства имён — проверьте в вашей версии библиотеки use sngrl\PhpFirebaseCloudMessaging\Client; use GuzzleHttp\Client as GuzzleClient;
$guzzle = new GuzzleClient([‘timeout’ => 10]); $client = new Client(); $client->setApiKey(getenv(‘FCM_SERVER_KEY’)); $client->injectGuzzleHttpClient($guzzle);
Советы по хранению ключей:
- Server Key храните в переменных окружения или в менеджере секретов.
- Не выводите ключ в логах.
- Ограничьте доступ к секретам на уровне инфраструктуры.
## Регистрация клиентских токенов
Клиентское приложение получает токен и должно отправить его бэкенду. На стороне сервера реализуйте защищённый API‑эндпоинт (HTTPS, авторизация), который принимает и сохраняет токены:
Оригинальный пример кода из статьи (сохранён без изменений):
$token = $_POST[“fcmToken”];
$userId = ((int) $_POST["userId"]);
/**
* Call a function which persists a user/token
* association to your database
*/
saveUserFcmToken($userId, $token);Этот пример демонстрационный — в продакшне избегайте прямого доступа к $_POST без валидации и авторизации. Пример улучшенного обработчика (псевдокод):
- Авторизовать запрос (JWT, сессия, API‑ключ).
- Проверить формат токена (не пустой, соответствует ожидаемой длине/шаблону).
- Сохранить запись: user_id, token, device_id, platform, last_seen.
- Ответ: 200 OK или подробная ошибка.
Пример SQL‑схемы таблицы fcm_tokens (упрощённо):
- id (PK)
- user_id
- token (unique)
- device_id
- platform (android|ios|web)
- created_at
- updated_at
- last_active
Стоит хранить дополнительно метаинформацию, чтобы отслеживать, какие токены устарели.
Отправка уведомлений
PHP‑FCM моделирует уведомление через объекты Message и Notification. Оригинальные примеры оставлены в статье; ниже они тоже сохранены. Оригинал создания Notification:
use sngrlPhpFirebaseCloudMessagingClientNotification;$notification = new Notification(
“Notification Title”,
“The longer text of the notification, displayed below the title.”
);
Создание и отправка Message из оригинала:
use sngrlPhpFirebaseCloudMessagingClientMessage;
$message = new Message();
$message -> setNotification($notification);
Добавление получателей (оригинал):
use sngrlPhpFirebaseCloudMessagingClientRecipientDevice;$message -> addReceipient(new Device(“FCM-CLIENT-TOKEN-USER-1”));
$message -> addReceipient(new Device(“FCM-CLIENT-TOKEN-USER-2”));
$client -> send($message);
Полная функция отправки из оригинала (сохранена):
use sngrlPhpFirebaseCloudMessagingClientClient;
use sngrlPhpFirebaseCloudMessagingClientMessage;
use sngrlPhpFirebaseCloudMessagingClientNotification;
use sngrlPhpFirebaseCloudMessagingClientRecipientDevice;
$client = new Client();
$client -> setApiKey("FCM-SERVER-KEY");
$client -> injectGuzzleHttpClient(new GuzzleHttpClient());
function sendNotification(
Client $client,
string $title,
string $body,
string ...$clientTokens) : void {
$message = new Message();
$message -> setNotification(
new Notification(
$title,
$body
)
);
foreach ($clientTokens as $clientToken) {
$message -> addRecipient(new Device($clientToken));
}
$client -> send($message);
}
sendNotification($client, "Hello World", "Test Notification", "FCM-CLIENT-TOKEN-1");Замечания и улучшения:
- Оригинальные use‑строки в статье выглядят слитыми: проверьте актуальное пространство имён в установленной версии библиотеки.
- Для массовых рассылок используйте батчи или тему (topic) в FCM, а не отправку по одному токену в цикле.
- Ограничьте скорость отправки согласно квотам и используйте очередь задач (RabbitMQ, Redis Queue, cron, worker) для рассылок.
Пример отправки на группу токенов с использованием HTTP v1 API (альтернатива PHP‑FCM):
POST https://fcm.googleapis.com/fcm/send
Headers:
Authorization: key=SERVER_KEY
Content-Type: application/json
Body:
{
"registration_ids": ["token1","token2"],
"notification": {"title":"Hello","body":"World"},
"data": {"customKey":"value"}
}Обработка ответа FCM
Оригинальный пример (сохранён):
$message = new Message();$message -> setNotification(new Notification(“Test”, “Test”));
$message -> addReceipient(new Device(“FCM-CLIENT-TOKEN-USER-1”));
$message -> addReceipient(new Device(“FCM-CLIENT-TOKEN-USER-2”));
$response = $client -> send($message);
$responseData = $response -> json();
Пример возможного ответа (сохранён):
{
“success”: 1,
“failure”: 1,
“results”: [
{
“message_id”: 100
},
{
“error”: “InvalidRegistration”
}
]
}
Ключевые моменты при работе с результатами:
- results — массив статусов для каждого отправленного токена в том же порядке, в котором вы добавляли получателей.
- При ошибках InvalidRegistration, NotRegistered, или других — нужно удалить или обновить токен в базе.
- Возможно получение Canonical ID — это означает, что токен изменился: замените старый токен на новый.
Пример обработки ошибок (оригинал сохранён):
$recipients = [
“FCM-CLIENT-TOKEN-USER-1”,
“FCM-CLIENT-TOKEN-USER-2”
];
$message = new Message();
$message -> setNotification(new Notification(“Test”, “Test”));
foreach ($recipients as $recipient) {
$message -> addReceipient(new Device($recipient));
}
$response = $client -> send($message);
$responseData = $response -> json();
foreach ($responseData[“results”] as $i => $result) {
if (isset($result[“error”])) {
deleteUserFcmToken($recipients[$i]);
}
}
Рекомендации:
- Логируйте не только ошибку, но и контекст (user_id, token, время).
- Для transient‑ошибок (например, UNAVAILABLE) реализуйте повторную отправку с экспоненциальным бэкоффом.
- Для больших списков используйте асинхронные очереди и мониторинг успешности.
## Добавление произвольных данных в уведомления
Оригинальный пример (сохранён):
$message = new Message();
$message -> setNotification(
new Notification(
"Breaking News!",
"A breaking news story is available."
)
);
$message -> setData([
"uri" => "/news/latest-stories"
]);Практическая польза data‑поля:
- Клиентское приложение может направлять пользователя по deep link, открывать определённый экран или выполнить фоновую синхронизацию.
- На Android data‑payload может приходить в onMessageReceived даже если приложение в фоне (в зависимости от типа сообщения).
- На iOS приоритет и тип сообщения определяют, попадёт ли data‑payload в обработчик приложения или только в уведомление.
Совет: отделяйте пользовательский контент (notification) от управляющих данных (data). Пользователь видит notification, а data используется приложением.
Приоритеты сообщений
Оригинал описывает поведение приоритетов. Сохраняем пример:
// Indicate a high-priority message
$message -> setPriority("high");Ключевые обозначения:
- high — попытка немедленной доставки, будит устройство на Android.
- normal или значение 5 для iOS — совместимые варианты.
Важно:
- Не злоупотребляйте высоким приоритетом: система может начать понижать приоритет ваших сообщений, если пользователи не взаимодействуют с ними.
- Приоритеты работают по-разному на Android и iOS — тестируйте поведение на реальных устройствах.
Time to Live
TTL определяет, сколько времени FCM будет пытаться доставить сообщение, если устройство оффлайн. Оригинальные примеры сохранены:
$message = new Message();$message -> setNotification(
new Notification(
“Server rotation scheduled for 12pm”,
“Cancel within the next 10 minutes.”
)
);
$message -> setTimeToLive(600);
Рекомендации:
- Для мгновенно релевантных уведомлений (например, одноразовые токены или временные акции) указывайте короткий TTL.
- Для фоновых синхронизаций можно указать более длинный TTL или оставить значение по умолчанию.
## Значки на iOS
Оригинальный пример (сохранён):
$message = new Message();
$notification = new Notification(
"Server rotation scheduled for 12pm",
"Cancel within the next 10 minutes."
);
$notification -> setBadge(1);
$message -> setNotification($notification);
$message -> setTimeToLive(600);Дополнительно: класс Notification предоставляет методы для платформенно‑специфичных параметров: setIcon, setSound, setTag и другие. Документация FCM описывает нюансы поведения на Android и iOS.
Когда этот подход не подходит
- Если вам нужна крайне детальная контроль над APNS/FCM HTTP v1 API (например, OAuth2 с service account), возможно, стоит работать напрямую с FCM HTTP v1 API.
- Для сверхмассовых рассылок с миллионами устройств нужна архитектура очередей и разделение по регионам/кластеризации.
- Если вы не хотите хранить токены — используйте topic‑подписки на стороне клиента, но при этом теряете гибкость таргетинга на конкретного пользователя.
Альтернативные подходы
- Прямые HTTP вызовы к FCM v1 API с OAuth2 (service account) вместо Server Key.
- Использование облачных функций (Cloud Functions) для отправки уведомлений при изменениях в БД.
- Сторонние сервисы рассылки (OneSignal, Airship) если нужна аналитика и UI‑управление уведомлениями.
Мини‑методология отправки push‑уведомлений (шаблон действий)
- Сбор токенов: клиент → защищённый API → база.
- Валидация: проверка токенов, платформы, user_id.
- Формирование payload: notification + data, priority, TTL.
- Отправка через очередь воркеров.
- Обработка ответа: удаление/обновление токенов, логирование.
- Метрики: успешные/неуспешные доставки, latency, rate limits.
Чек‑лист по ролям
Разработчик фронта:
- Получает токен и отправляет на бэкенд.
- Обрабатывает глубинные ссылки и data-поля.
- Обрабатывает обновление токена и пересылает новый на сервер.
Разработчик бэкенда:
- Хранит токены и метаинформацию.
- Реализует очереди и повторные попытки с бэкоффом.
- Защищает Server Key и логирует ошибки.
DevOps/Безопасность:
- Ограничивает доступ к секретам.
- Настраивает мониторинг и алерты по сбоям рассылок.
Критерии приёмки
- Сервер успешно отправляет уведомления на тестовые iOS и Android устройства.
- В базе корректно сохраняются токены и связаны с user_id.
- При получении ошибок NotRegistered/InvalidRegistration токены удаляются.
- TTL и приоритеты работают как ожидается в тестах.
- Нет утечек Server Key в логах или репозиториях.
Руководство по инцидентам при сбоe доставки
- Проверить логи рассылки и ответы FCM на предмет ошибок (UNAVAILABLE, INTERNAL_ERROR).
- Если ошибки связаны с квотами или лимитами, замедлить скорость отправки и оповестить команду.
- При массовой утрате доставляемости проверить корректность Server Key и состояние APNS сертификатов.
- Временно переключиться на отложенные/ручные рассылки и восстановить стабильность через тесты.
Тесты и критерии приёмки
- Интеграционные тесты: эмулировать FCM ответы и проверить реакцию кода на разные results.
- End‑to‑end: отправка тестового уведомления на физическое устройство (iOS + Android).
- Нагрузочное тестирование: проверить поведение очередей при рассылке на тысячи токенов.
Безопасность и конфиденциальность
- Храните Server Key в защищённом хранилище секретов.
- Ограничьте доступ на уровне IAM к ресурсам, которые могут читать секреты.
- В логах храните хэш токена, а не сам токен, если есть риск утечки.
- Для соответствия GDPR: храните только необходимые данные, реализуйте права пользователя (удаление данных по запросу).
Дополнительные советы по надёжности
- Используйте очередь задач для массовых рассылок, чтобы выдерживать spike‑нагрузки.
- Реализуйте экспоненциальный бэкофф для transient‑ошибок.
- Мониторьте частоту ошибок и долю неуспешных доставок; добавьте алерты.
- Периодически запускайте процесс валидации токенов (например, раз в 24 часа удалять устаревшие).
Глоссарий 1 строка
- Server Key: секретный ключ проекта Firebase для авторизации запросов от сервера.
- Registration token: уникальный идентификатор устройства, выданный Firebase SDK.
- TTL: время жизни сообщения в секундах.
- Priority: приоритет доставки сообщения (high/normal).
Шаблоны тестовых сценариев
- Отправка уведомления на один валидный токен → ожидать успех.
- Отправка на mix валидных и невалидных токенов → ожидать partial success и удаление невалидных токенов.
- Отправка high priority на Android и проверка wakeup‑поведения.
- Отправка с data‑полем и проверка обработки deep link в приложении.
Когда стоит перейти к прямой работе с FCM HTTP v1 API
- Нужна поддержка OAuth2 с service accounts и тонкая настройка политики доставки.
- Необходим доступ к возможностям, которых нет в используемой библиотеке PHP‑FCM.
Короткое резюме
- FCM даёт единый канал доставки уведомлений на Android, iOS и web.
- На стороне сервера храните и обновляйте токены, обрабатывайте ответы FCM.
- Используйте очереди и бэкоффы для надёжности и устойчивости к ошибкам.
- Защитите Server Key, следите за метриками и реагируйте на инциденты.
Важно: тестируйте на реальных устройствах и разных версиях ОС, так как поведение delivery и data‑payload может отличаться.
Рекомендации для социальных сетей
Обычный анонс (100–200 слов):
Хотите отправлять push‑уведомления с PHP на iOS и Android? В статье показан практический путь: от настройки Firebase и получения Server Key до готового PHP‑кода для отправки уведомлений, обработки ответов и управления токенами. Вы найдёте советы по приоритетам, TTL, безопасности и методику, которую можно применить в продакшне.
Публикация завершена.
Похожие материалы
Обрезка видео в Clipchamp через транскрипт
Как управлять и архивировать заказы на Amazon
Резервное копирование сохранений игр в Windows 10
Как записать HD‑видео с веб‑камеры на ПК
Отключить отправку данных о загрузках в Firefox