Библиотека Web Push для PHP
WebPush можно использовать для отправки push-сообщений конечным точкам, как описано в протоколе Web Push.
Затем это push-сообщение принимается браузером, который затем может создать уведомление с помощью работника службы и API уведомлений.
PHP 8.1+ и следующие расширения:
Более старые версии PHP не поддерживаются и не обслуживаются, однако вы можете использовать следующие совместимые версии:
v1.x
v2.x
v3.x-v5.x
v6.x
v7.x
v8.x
Этот README совместим только с последней версией. Каждая версия библиотеки имеет тег git, в котором можно прочитать соответствующий README.
Используйте композитор, чтобы загрузить и установить библиотеку и ее зависимости.
composer require minishlink/web-push
Полный пример с интерфейсом html+JS и серверной частью php с использованием web-push-php
можно найти здесь: Minishlink/web-push-php-example.
<?php
use Minishlink WebPush WebPush ;
use Minishlink WebPush Subscription ;
// store the client - side `PushSubscription` object ( calling ` . toJSON` on it) as - is and then create a WebPush Subscription from it
$ subscription = Subscription:: create ( json_decode ( $ clientSidePushSubscriptionJSON , true ));
// array of notifications
$ notifications = [
[
' subscription ' => $ subscription ,
' payload ' => ' {"message":"Hello World!"} ' ,
], [
// current PushSubscription format ( browsers might change this in the future)
' subscription ' => Subscription:: create ([
" endpoint " => " https://example.com/other/endpoint/of/another/vendor/abcdef... " ,
" keys " => [
' p256dh ' => ' (stringOf88Chars) ' ,
' auth ' => ' (stringOf24Chars) '
],
]),
' payload ' => ' {"message":"Hello World!"} ' ,
], [
// old Firefox PushSubscription format
' subscription ' => Subscription:: create ([
' endpoint ' => ' https://updates.push.services.mozilla.com/push/abc... ' , // Firefox 43 + ,
' publicKey ' => ' BPcMbnWQL5GOYX/5LKZXT6sLmHiMsJSiEvIFvfcDvX7IZ9qqtq68onpTPEYmyxSQNiH7UD/98AUcQ12kBoxz/0s= ' , // base 64 encoded , should be 88 chars
' authToken ' => ' CxVX6QsVToEGEcjfYPqXQw== ' , // base 64 encoded , should be 24 chars
]),
' payload ' => ' hello ! ' ,
], [
// old Chrome PushSubscription format
' subscription ' => Subscription:: create ([
' endpoint ' => ' https://fcm.googleapis.com/fcm/send/abcdef... ' ,
]),
' payload ' => null ,
], [
// old PushSubscription format
' subscription ' => Subscription:: create ([
' endpoint ' => ' https://example.com/other/endpoint/of/another/vendor/abcdef... ' ,
' publicKey ' => ' (stringOf88Chars) ' ,
' authToken ' => ' (stringOf24Chars) ' ,
' contentEncoding ' => ' aesgcm ' , // one of PushManager . supportedContentEncodings
]),
' payload ' => ' {"message":"test"} ' ,
]
];
$ webPush = new WebPush ();
// send multiple notifications with payload
foreach ( $ notifications as $ notification ) {
$ webPush -> queueNotification (
$ notification [ ' subscription ' ],
$ notification [ ' payload ' ] // optional ( defaults null)
);
}
/**
* Check sent results
* @ var MessageSentReport $ report
* /
foreach ( $ webPush -> flush () as $ report ) {
$ endpoint = $ report -> getRequest ()-> getUri ()-> __toString ();
if ( $ report -> isSuccess ()) {
echo " [v] Message sent successfully for subscription { $ endpoint } . " ;
} else {
echo " [x] Message failed to sent for subscription { $ endpoint } : { $ report -> getReason ()}" ;
}
}
/**
* send one notification and flush directly
* @ var MessageSentReport $ report
* /
$ report = $ webPush -> sendOneNotification (
$ notifications [ 0 ][ ' subscription ' ],
$ notifications [ 0 ][ ' payload ' ], // optional ( defaults null)
);
Браузеры должны подтвердить вашу личность. Стандарт под названием VAPID может аутентифицировать вас во всех браузерах. Вам нужно будет создать и предоставить открытый и закрытый ключ для вашего сервера. Эти ключи должны надежно храниться и не подлежат изменению.
Вы можете указать данные аутентификации при создании экземпляра WebPush. Ключи можно передать напрямую (рекомендуется) или загрузить PEM-файл или его содержимое:
<?php
use Minishlink WebPush WebPush ;
$ endpoint = ' https://fcm.googleapis.com/fcm/send/abcdef... ' ; // Chrome
$ auth = [
' VAPID ' => [
' subject ' => ' mailto:[email protected] ' , // can be a mailto : or your website address
' publicKey ' => ' ~88 chars ' , // (recommended) uncompressed public key P - 256 encoded in Base64 - URL
' privateKey ' => ' ~44 chars ' , // (recommended) in fact the secret multiplier of the private key encoded in Base64 - URL
' pemFile ' => ' path/to/pem ' , // if you have a PEM file and can link to it on your filesystem
' pem ' => ' pemFileContent ' , // if you have a PEM file and want to hardcode its content
],
];
$ webPush = new WebPush ( $ auth );
$ webPush -> queueNotification (...);
Чтобы сгенерировать несжатый открытый и секретный ключ, закодированный в Base64, введите в свой Linux bash следующее:
$ openssl ecparam -genkey -name prime256v1 -out private_key.pem
$ openssl ec -in private_key.pem -pubout -outform DER | tail -c 65 | base64 | tr -d ' = ' | tr ' /+ ' ' _- ' >> public_key.txt
$ openssl ec -in private_key.pem -outform DER | tail -c +8 | head -c 32 | base64 | tr -d ' = ' | tr ' /+ ' ' _- ' >> private_key.txt
Если у вас нет доступа к bash Linux, вы можете распечатать выходные данные функции createVapidKeys
:
var_dump ( VAPID :: createVapidKeys ()); // store the keys afterwards
На стороне клиента не забудьте подписаться с открытым ключом VAPID в качестве applicationServerKey
: (источник urlBase64ToUint8Array
здесь)
serviceWorkerRegistration . pushManager . subscribe ( {
userVisibleOnly : true ,
applicationServerKey : urlBase64ToUint8Array ( vapidPublicKey )
} )
Заголовки VAPID используют веб-токен JSON (JWT) для проверки вашей личности. Полезная нагрузка этого токена включает протокол и имя хоста конечной точки, включенной в подписку, а также отметку времени истечения срока действия (обычно 12–24 часа) и подписывается с использованием вашего открытого и закрытого ключей. Учитывая это, два уведомления, отправленные в одну и ту же службу push-уведомлений, будут использовать один и тот же токен, поэтому вы можете повторно использовать их для одного и того же сеанса очистки, чтобы повысить производительность, используя:
$ webPush -> setReuseVAPIDHeaders ( true );
Каждое уведомление может иметь определенное время жизни, срочность и тему. Стандарт WebPush гласит, что urgency
не является обязательной, но некоторые пользователи сообщают, что Safari выдает ошибки, если она не указана. Возможно, это будет исправлено в будущем. Вы можете изменить параметры по умолчанию с помощью setDefaultOptions()
или в конструкторе:
<?php
use Minishlink WebPush WebPush ;
$ defaultOptions = [
' TTL ' => 300 , // defaults to 4 weeks
' urgency ' => ' normal ' , // protocol defaults to "normal" . ( very - low , low , normal , or high)
' topic ' => ' newEvent ' , // not defined by default . Max . 32 characters from the URL or filename - safe Base64 characters sets
' batchSize ' => 200 , // defaults to 1000
];
// for every notification
$ webPush = new WebPush ([], $ defaultOptions );
$ webPush -> setDefaultOptions ( $ defaultOptions );
// or for one notification
$ webPush -> sendOneNotification ( $ subscription , $ payload , [ ' TTL ' => 5000 ]);
Время жизни (TTL, в секундах) — это время, в течение которого push-сообщение сохраняется службой push-уведомлений (например, Mozilla) в случае, если браузер пользователя еще недоступен (например, не подключен). Возможно, вы захотите использовать очень долгое время для важных уведомлений. Срок жизни по умолчанию составляет 4 недели. Однако если вы отправляете несколько несущественных уведомлений, установите TTL равным 0: push-уведомление будет доставлено только в том случае, если пользователь в данный момент подключен. В других случаях вам следует использовать минимум один день, если у ваших пользователей несколько часовых поясов, а если нет, то будет достаточно нескольких часов.
Срочность может быть «очень низкой», «низкой», «нормальной» или «высокой». Если производитель браузера реализовал эту функцию, это позволит сэкономить заряд батареи на мобильных устройствах (см. протокол).
Эта строка заставит поставщика показывать пользователю только последнее уведомление по этой теме (см. протокол).
Если вы отправляете десятки тысяч уведомлений одновременно, вы можете получить переполнение памяти из-за того, как конечные точки вызываются в Guzzle. Чтобы это исправить, WebPush отправляет уведомления пакетно. Размер по умолчанию — 1000. В зависимости от конфигурации вашего сервера (памяти) вы можете уменьшить это число. Сделайте это при создании экземпляра WebPush или вызове setDefaultOptions
. Или, если вы хотите настроить это для конкретного сброса, укажите его в качестве параметра: $webPush->flush($batchSize)
.
Вы можете увидеть, что сервер поставщика браузера отправляет обратно в случае возникновения ошибки (истечение срока принудительной подписки, неверные параметры...).
sendOneNotification()
возвращает MessageSentReport
flush()
возвращает Generator
с объектами MessageSentReport
. Чтобы просмотреть результаты, просто передайте их в foreach
. Вы также можете использовать iterator_to_array
для проверки содержимого во время отладки. <?php
/** @var MinishlinkWebPush MessageSentReport $ report * /
foreach ( $ webPush -> flush () as $ report ) {
$ endpoint = $ report -> getEndpoint ();
if ( $ report -> isSuccess ()) {
echo " [v] Message sent successfully for subscription { $ endpoint } . " ;
} else {
echo " [x] Message failed to sent for subscription { $ endpoint } : { $ report -> getReason ()}" ;
// also available ( to get more info )
/** @var Psr Http Message RequestInterface $ requestToPushService * /
$ requestToPushService = $ report -> getRequest ();
/** @var Psr Http Message ResponseInterface $ responseOfPushService * /
$ responseOfPushService = $ report -> getResponse ();
/** @var string $ failReason */
$ failReason = $ report -> getReason ();
/** @var bool $ isTheEndpointWrongOrExpired */
$ isTheEndpointWrongOrExpired = $ report -> isSubscriptionExpired ();
}
}
ОБРАТИТЕ ВНИМАНИЕ: Вы можете перебирать объект Generator
только один раз .
Ошибки Firefox перечислены в документации autopush.
Полезные данные шифруются библиотекой. Максимальная длина полезных данных теоретически составляет 4078 байт (или символов ASCII). Однако по соображениям совместимости (в архиве) ваша полезная нагрузка должна иметь длину менее 3052 байт.
Библиотека по умолчанию дополняет полезную нагрузку. Это более безопасно, но снижает производительность как вашего сервера, так и устройства вашего пользователя.
Когда вы зашифровываете строку определенной длины, результирующая строка всегда будет иметь одинаковую длину, независимо от того, сколько раз вы шифруете исходную строку. Это может заставить злоумышленников угадать содержимое полезной нагрузки. Чтобы обойти это, эта библиотека добавляет к исходной полезной нагрузке некоторое заполнение нулями, чтобы все входные данные процесса шифрования имели одинаковую длину. Таким образом, все выходные данные процесса шифрования также будут иметь одинаковую длину, и злоумышленники не смогут угадать содержимое вашей полезной нагрузки.
Шифрование большего количества байтов требует больше времени работы на вашем сервере, а также замедляет работу устройства пользователя при расшифровке. Более того, отправка и получение пакета займут больше времени. Он также не очень дружелюбен к пользователям, у которых ограниченный тарифный план.
Вы можете настроить автоматическое заполнение в соответствии с вашими потребностями.
Вот несколько идей настроек:
Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH
(2820 байт) для совместимости с Firefox для Android (см. № 108).Encryption::MAX_PAYLOAD_LENGTH
(4078 байт) для максимальной безопасности.false
для максимальной производительностиX
байт, установите значение X
для наилучшего баланса между безопасностью и производительностью. <?php
use Minishlink WebPush WebPush ;
$ webPush = new WebPush ();
$ webPush -> setAutomaticPadding ( false ); // disable automatic padding
$ webPush -> setAutomaticPadding ( 512 ); // enable automatic padding to 512 bytes ( you should make sure that your payload is less than 512 bytes , or else an attacker could guess the content )
$ webPush -> setAutomaticPadding ( true ); // enable automatic padding to default maximum compatibility length
WebPush использует Guzzle. Он будет использовать наиболее подходящий клиент, который найдет, и в большинстве случаев это будет MultiCurl
, который позволяет отправлять несколько уведомлений параллельно.
Вы можете настроить параметры запроса по умолчанию и время ожидания при создании экземпляра WebPush:
<?php
use Minishlink WebPush WebPush ;
$ timeout = 20 ; // seconds
$ clientOptions = [
GuzzleHttp RequestOptions:: ALLOW_REDIRECTS => false ,
]; // see GuzzleHttp RequestOptions
$ webPush = new WebPush ([], [], $ timeout , $ clientOptions );
Доступны следующие возможности:
Не стесняйтесь добавлять свои собственные!
Полезная нагрузка шифруется в соответствии со стандартом шифрования сообщений для Web Push с использованием открытого ключа пользователя и секрета аутентификации, которые вы можете получить, следуя спецификации Web Push API.
Внутри WebPush использует структуру WebToken и OpenSSL для генерации и шифрования ключей шифрования.
Вот несколько идей:
defaultOptions
или в качестве flush()
)flushPooled()
вместоlush flush()
. Первый использует параллельные запросы, ускоряя процесс и часто удваивая скорость запросов.В вашей установке отсутствуют некоторые сертификаты.
php.ini
: после [curl]
введите curl.cainfo = /path/to/cacert.pem
.Вы также можете принудительно использовать клиент без одноранговой проверки.
Обязательно требуется автозагрузчик Composer.
require __DIR__ . ' /path/to/vendor/autoload.php ' ;
Убедитесь, что поля базы данных достаточно велики для длины сохраняемых данных (#233). Пользователи сообщили, что длина URL-адреса конечной точки не превышает 500 символов, но это может измениться, поэтому вы можете установить ограничение в 2048 символов, установленное в большинстве браузеров.
См. выпуск №58.
Данной услуги больше не существует. 29 мая 2019 года он был заменен Google Firebase Cloud Messaging (FCM).
Эта библиотека не поддерживает Firebase Cloud Messaging (FCM). Старые подписки Chrome (до 2018 года и VAPID) используют устаревший протокол HTTP от Firebase Cloud Messaging (FCM), который устарел с 2023 года и перестанет работать в июне 2024 года. Поддержка этой устаревшей подписки прекращена.
Не путайте, поскольку устаревший протокол HTTP и Web Push с VAPID используют одинаковый URL-адрес конечной точки:
https://fcm.googleapis.com/fcm/send
Web Push с VAPID останется доступным по этому URL. Никаких дальнейших действий на данный момент не требуется.
Поставщики браузеров не позволяют отправлять данные с помощью Push API без создания уведомления. Используйте некоторые альтернативные API, такие как WebSocket/WebTransport или фоновая синхронизация.
WebPush предназначен для веб-приложений. Вам нужно что-то вроде RMSPushNotificationsBundle (Symfony).
Эта библиотека была вдохновлена библиотекой web-push-libs/web-push Node.js.
server.js
: его следует заменить кодом вашего сервера PHP с этой библиотекой)Массачусетский технологический институт