Biblioteca Web Push para PHP
WebPush se puede utilizar para enviar mensajes push a puntos finales como se describe en el protocolo Web Push.
Luego, el navegador recibe este mensaje push, que luego puede crear una notificación utilizando el trabajador del servicio y la API de notificaciones.
PHP 8.1+ y las siguientes extensiones:
No hay soporte ni mantenimiento para versiones anteriores de PHP; sin embargo, puedes utilizar las siguientes versiones compatibles:
v1.x
v2.x
v3.x-v5.x
v6.x
v7.x
v8.x
Este archivo README solo es compatible con la última versión. Cada versión de la biblioteca tiene una etiqueta git donde se puede leer el archivo README correspondiente.
Utilice Composer para descargar e instalar la biblioteca y sus dependencias.
composer require minishlink/web-push
Puede encontrar un ejemplo completo con el frontend html+JS y el backend php usando web-push-php
aquí: 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)
);
Los navegadores necesitan verificar su identidad. Un estándar llamado VAPID puede autenticarlo en todos los navegadores. Deberá crear y proporcionar una clave pública y privada para su servidor. Estas claves deben almacenarse de forma segura y no deben cambiarse.
Puede especificar sus detalles de autenticación al crear una instancia de WebPush. Las claves se pueden pasar directamente (recomendado), o puedes cargar un archivo PEM o su contenido:
<?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 (...);
Para generar la clave pública y secreta sin comprimir, codificada en Base64, ingrese lo siguiente en su bash de Linux:
$ 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
Si no puede acceder a un bash de Linux, puede imprimir el resultado de la función createVapidKeys
:
var_dump ( VAPID :: createVapidKeys ()); // store the keys afterwards
En el lado del cliente, no olvide suscribirse con la clave pública VAPID como applicationServerKey
: (fuente urlBase64ToUint8Array
aquí)
serviceWorkerRegistration . pushManager . subscribe ( {
userVisibleOnly : true ,
applicationServerKey : urlBase64ToUint8Array ( vapidPublicKey )
} )
Los encabezados VAPID utilizan un token web JSON (JWT) para verificar su identidad. Esa carga útil del token incluye el protocolo y el nombre de host del punto final incluido en la suscripción y una marca de tiempo de vencimiento (generalmente entre 12 y 24 horas), y está firmada con su clave pública y privada. Dado esto, dos notificaciones enviadas al mismo servicio push usarán el mismo token, por lo que puedes reutilizarlas para la misma sesión de descarga para mejorar el rendimiento usando:
$ webPush -> setReuseVAPIDHeaders ( true );
Cada notificación puede tener un tiempo de vida, una urgencia y un tema específicos. El estándar WebPush establece que urgency
es opcional, pero algunos usuarios informan que Safari arroja errores cuando no se especifica. Esto podría solucionarse en el futuro. Puedes cambiar las opciones predeterminadas con setDefaultOptions()
o en el constructor:
<?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 ]);
El tiempo de vida (TTL, en segundos) es el tiempo que el servicio push retiene un mensaje push (por ejemplo, Mozilla) en caso de que el navegador del usuario aún no sea accesible (por ejemplo, no esté conectado). Es posible que desee utilizar un tiempo muy largo para notificaciones importantes. El TTL predeterminado es 4 semanas. Sin embargo, si envía varias notificaciones no esenciales, establezca un TTL de 0: la notificación push se entregará solo si el usuario está conectado actualmente. Para otros casos, deberás utilizar un mínimo de un día si tus usuarios tienen múltiples zonas horarias, y si no las tienen, bastarán con varias horas.
La urgencia puede ser "muy baja", "baja", "normal" o "alta". Si el proveedor del navegador ha implementado esta función, ahorrará batería en los dispositivos móviles (ver protocolo).
Esta cadena hará que el proveedor muestre al usuario sólo la última notificación de este tema (cf. protocolo).
Si envía decenas de miles de notificaciones a la vez, es posible que experimente desbordamientos de memoria debido a cómo se llaman los puntos finales en Guzzle. Para solucionar este problema, WebPush envía notificaciones en lotes. El tamaño predeterminado es 1000. Dependiendo de la configuración de su servidor (memoria), es posible que desee disminuir este número. Haga esto mientras crea una instancia de WebPush o llama setDefaultOptions
. O, si desea personalizar esto para una descarga específica, proporciónelo como parámetro: $webPush->flush($batchSize)
.
Puede ver lo que devuelve el servidor del proveedor del navegador en caso de que encuentre un error (caducidad de la suscripción push, parámetros incorrectos...).
sendOneNotification()
devuelve un MessageSentReport
flush()
devuelve un Generator
con objetos MessageSentReport
. Para recorrer los resultados, simplemente páselo a foreach
. También puede utilizar iterator_to_array
para comprobar el contenido durante la depuración. <?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 ();
}
}
TENGA EN CUENTA: Sólo puede iterar una vez sobre el objeto Generator
.
Los errores de Firefox se enumeran en la documentación de autopush.
Las cargas útiles están cifradas por la biblioteca. La longitud máxima de la carga útil es teóricamente de 4078 bytes (o caracteres ASCII). Sin embargo, por razones de compatibilidad (archivado), su carga útil debe tener menos de 3052 bytes.
La biblioteca rellena la carga útil de forma predeterminada. Esto es más seguro pero disminuye el rendimiento tanto de su servidor como del dispositivo de su usuario.
Cuando cifra una cadena de cierta longitud, la cadena resultante siempre tendrá la misma longitud, sin importar cuántas veces cifre la cadena inicial. Esto puede hacer que los atacantes adivinen el contenido de la carga útil. Para evitar esto, esta biblioteca agrega algo de relleno nulo a la carga útil inicial, de modo que todas las entradas del proceso de cifrado tengan la misma longitud. De esta manera, todo el resultado del proceso de cifrado también tendrá la misma longitud y los atacantes no podrán adivinar el contenido de su carga útil.
Cifrar más bytes requiere más tiempo de ejecución en su servidor y también ralentiza el dispositivo del usuario con el descifrado. Además, enviar y recibir el paquete llevará más tiempo. Tampoco es muy amigable con usuarios que tienen planes de datos limitados.
Puede personalizar el relleno automático para que se ajuste mejor a sus necesidades.
Aquí hay algunas ideas de configuración:
Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH
(2820 bytes) para fines de compatibilidad con Firefox para Android (consulte el n.° 108)Encryption::MAX_PAYLOAD_LENGTH
(4078 bytes) para máxima seguridadfalse
para obtener el máximo rendimientoX
bytes, configúrelo en X
para obtener el mejor equilibrio entre seguridad y rendimiento. <?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 utiliza Guzzle. Utilizará el cliente más apropiado que encuentre, y la mayoría de las veces será MultiCurl
, que permite enviar múltiples notificaciones en paralelo.
Puede personalizar las opciones de solicitud predeterminadas y el tiempo de espera al crear una instancia de WebPush:
<?php
use Minishlink WebPush WebPush ;
$ timeout = 20 ; // seconds
$ clientOptions = [
GuzzleHttp RequestOptions:: ALLOW_REDIRECTS => false ,
]; // see GuzzleHttp RequestOptions
$ webPush = new WebPush ([], [], $ timeout , $ clientOptions );
Están disponibles los siguientes:
¡Siéntete libre de agregar el tuyo!
La carga útil se cifra de acuerdo con el estándar Message Encryption for Web Push, utilizando la clave pública del usuario y el secreto de autenticación que puede obtener siguiendo la especificación Web Push API.
Internamente, WebPush utiliza el marco WebToken y OpenSSL para manejar la generación y el cifrado de claves de cifrado.
Aquí hay algunas ideas:
defaultOptions
o como parámetro para flush()
)flushPooled()
en lugar de flush()
. El primero utiliza solicitudes simultáneas, acelerando el proceso y, a menudo, duplicando la velocidad de las solicitudes.A tu instalación le faltan algunos certificados.
php.ini
: después de [curl]
, escriba curl.cainfo = /path/to/cacert.pem
.También puede forzar el uso de un cliente sin verificación por parte de pares.
Asegúrese de requerir el cargador automático de Composer.
require __DIR__ . ' /path/to/vendor/autoload.php ' ;
Asegúrese de tener campos de base de datos que sean lo suficientemente grandes para la longitud de los datos que está almacenando (#233). Para el punto final, los usuarios han informado que la longitud de la URL no supera los 500 caracteres, pero esto puede evolucionar para que pueda configurarla en el límite de 2048 caracteres de la mayoría de los navegadores.
Consulte el número 58.
Este servicio ya no existe. Fue reemplazado por Firebase Cloud Messaging (FCM) de Google el 29 de mayo de 2019.
Esta biblioteca no es compatible con Firebase Cloud Messaging (FCM). Las suscripciones antiguas de Chrome (anteriores a 2018 y VAPID) utilizan el protocolo HTTP heredado de Firebase Cloud Messaging (FCM), que está en desuso desde 2023 y dejará de funcionar en junio de 2024. Se eliminó la compatibilidad con esta suscripción desactualizada.
No se confunda, ya que el protocolo HTTP heredado y Web Push con VAPID utilizan la URL de punto final idéntica:
https://fcm.googleapis.com/fcm/send
Web Push con VAPID permanecerá disponible en esta URL. Actualmente no se requiere ninguna otra acción.
Los proveedores de navegadores no permiten enviar datos utilizando Push API sin crear una notificación. Utilice algunas API alternativas como WebSocket/WebTransport o sincronización en segundo plano.
WebPush es para aplicaciones web. Necesitas algo como RMSPushNotificationsBundle (Symfony).
Esta biblioteca se inspiró en la biblioteca web-push-libs/web-push de Node.js.
server.js
: debe reemplazarse por el código de su servidor PHP con esta biblioteca)MIT