Web-Push-Bibliothek für PHP
Mit WebPush können Push-Nachrichten an Endpunkte gesendet werden, wie im Web Push-Protokoll beschrieben.
Diese Push-Nachricht wird dann vom Browser empfangen, der dann mithilfe des Service Workers und der Notifications API eine Benachrichtigung erstellen kann.
PHP 8.1+ und die folgenden Erweiterungen:
Für ältere PHP-Versionen gibt es keinen Support und keine Wartung, Sie können jedoch die folgenden kompatiblen Versionen verwenden:
v1.x
v2.x
v3.x-v5.x
v6.x
v7.x
v8.x
Diese README-Datei ist nur mit der neuesten Version kompatibel. Jede Version der Bibliothek verfügt über ein Git-Tag, in dem die entsprechende README-Datei gelesen werden kann.
Verwenden Sie Composer, um die Bibliothek und ihre Abhängigkeiten herunterzuladen und zu installieren.
composer require minishlink/web-push
Ein vollständiges Beispiel mit HTML+JS-Frontend und PHP-Backend unter Verwendung von web-push-php
finden Sie hier: 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)
);
Browser müssen Ihre Identität überprüfen. Ein Standard namens VAPID kann Sie für alle Browser authentifizieren. Sie müssen einen öffentlichen und einen privaten Schlüssel für Ihren Server erstellen und bereitstellen. Diese Schlüssel müssen sicher aufbewahrt werden und dürfen nicht verändert werden.
Sie können Ihre Authentifizierungsdetails bei der Instanziierung von WebPush angeben. Die Schlüssel können direkt übergeben werden (empfohlen), oder Sie können eine PEM-Datei oder deren Inhalt laden:
<?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 (...);
Um den unkomprimierten öffentlichen und geheimen Schlüssel, codiert in Base64, zu generieren, geben Sie Folgendes in Ihre Linux-Bash ein:
$ 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
Wenn Sie nicht auf eine Linux-Bash zugreifen können, können Sie die Ausgabe der Funktion „ createVapidKeys
ausdrucken:
var_dump ( VAPID :: createVapidKeys ()); // store the keys afterwards
Vergessen Sie auf der Clientseite nicht, sich mit dem öffentlichen VAPID-Schlüssel als applicationServerKey
anzumelden: ( urlBase64ToUint8Array
-Quelle hier)
serviceWorkerRegistration . pushManager . subscribe ( {
userVisibleOnly : true ,
applicationServerKey : urlBase64ToUint8Array ( vapidPublicKey )
} )
VAPID-Header nutzen ein JSON Web Token (JWT), um Ihre Identität zu überprüfen. Diese Token-Nutzlast umfasst das Protokoll und den Hostnamen des im Abonnement enthaltenen Endpunkts sowie einen Ablaufzeitstempel (normalerweise zwischen 12 und 24 Stunden) und wird mit Ihrem öffentlichen und privaten Schlüssel signiert. Da zwei an denselben Push-Dienst gesendete Benachrichtigungen dasselbe Token verwenden, können Sie sie für dieselbe Flush-Sitzung wiederverwenden, um die Leistung zu steigern, indem Sie Folgendes verwenden:
$ webPush -> setReuseVAPIDHeaders ( true );
Jede Benachrichtigung kann eine bestimmte Gültigkeitsdauer, Dringlichkeit und ein bestimmtes Thema haben. Der WebPush-Standard besagt, dass urgency
optional ist, aber einige Benutzer berichten, dass Safari Fehler auslöst, wenn sie nicht angegeben ist. Dies könnte in Zukunft behoben werden. Sie können die Standardoptionen mit setDefaultOptions()
oder im Konstruktor ändern:
<?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 ]);
Time To Live (TTL, in Sekunden) gibt an, wie lange eine Push-Nachricht vom Push-Dienst (z. B. Mozilla) aufbewahrt wird, für den Fall, dass auf den Browser des Benutzers noch nicht zugegriffen werden kann (z. B. keine Verbindung besteht). Möglicherweise möchten Sie für wichtige Benachrichtigungen eine sehr lange Zeitspanne verwenden. Die Standard-TTL beträgt 4 Wochen. Wenn Sie jedoch mehrere nicht unbedingt erforderliche Benachrichtigungen senden, legen Sie eine TTL von 0 fest: Die Push-Benachrichtigung wird nur zugestellt, wenn der Benutzer derzeit verbunden ist. In anderen Fällen sollten Sie mindestens einen Tag verwenden, wenn Ihre Benutzer über mehrere Zeitzonen verfügen. Wenn dies nicht der Fall ist, reichen mehrere Stunden aus.
Die Dringlichkeit kann entweder „sehr niedrig“, „niedrig“, „normal“ oder „hoch“ sein. Wenn der Browser-Hersteller diese Funktion implementiert hat, verlängert sich dadurch die Akkulaufzeit auf Mobilgeräten (siehe Protokoll).
Diese Zeichenfolge bewirkt, dass der Anbieter dem Benutzer nur die letzte Benachrichtigung zu diesem Thema anzeigt (siehe Protokoll).
Wenn Sie Zehntausende Benachrichtigungen gleichzeitig senden, kann es aufgrund der Art und Weise, wie Endpunkte in Guzzle aufgerufen werden, zu Speicherüberläufen kommen. Um dies zu beheben, sendet WebPush Benachrichtigungen in Stapeln. Die Standardgröße beträgt 1000. Abhängig von Ihrer Serverkonfiguration (Speicher) möchten Sie diese Zahl möglicherweise verringern. Tun Sie dies, während Sie WebPush instanziieren oder setDefaultOptions
aufrufen. Oder, wenn Sie dies für eine bestimmte Spülung anpassen möchten, geben Sie es als Parameter an: $webPush->flush($batchSize)
.
Sie können sehen, was der Server des Browser-Anbieters zurücksendet, falls ein Fehler auftritt (Ablauf des Push-Abonnements, falsche Parameter usw.).
sendOneNotification()
gibt einen MessageSentReport
zurückflush()
gibt einen Generator
mit MessageSentReport
Objekten zurück. Um die Ergebnisse zu durchlaufen, übergeben Sie sie einfach an foreach
. Sie können iterator_to_array
auch verwenden, um den Inhalt während des Debuggens zu überprüfen. <?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 ();
}
}
BITTE BEACHTEN: Sie können das Generator
Objekt nur einmal durchlaufen.
Firefox-Fehler sind in der Autopush-Dokumentation aufgeführt.
Nutzlasten werden von der Bibliothek verschlüsselt. Die maximale Nutzlastlänge beträgt theoretisch 4078 Bytes (oder ASCII-Zeichen). Aus Kompatibilitätsgründen (archiviert) sollte Ihre Nutzlast jedoch weniger als 3052 Bytes lang sein.
Die Bibliothek füllt die Nutzlast standardmäßig auf. Dies ist sicherer, verringert jedoch die Leistung sowohl Ihres Servers als auch des Geräts Ihres Benutzers.
Wenn Sie eine Zeichenfolge einer bestimmten Länge verschlüsseln, hat die resultierende Zeichenfolge immer die gleiche Länge, unabhängig davon, wie oft Sie die ursprüngliche Zeichenfolge verschlüsseln. Dies kann dazu führen, dass Angreifer den Inhalt der Nutzlast erraten. Um dies zu umgehen, fügt diese Bibliothek der anfänglichen Nutzlast etwas Nullauffüllung hinzu, sodass alle Eingaben des Verschlüsselungsprozesses die gleiche Länge haben. Auf diese Weise haben auch alle Ausgaben des Verschlüsselungsprozesses die gleiche Länge und Angreifer können den Inhalt Ihrer Nutzlast nicht erraten.
Das Verschlüsseln von mehr Bytes nimmt mehr Laufzeit auf Ihrem Server in Anspruch und verlangsamt außerdem das Gerät des Benutzers durch die Entschlüsselung. Darüber hinaus dauert das Senden und Empfangen des Pakets länger. Es ist auch nicht sehr freundlich zu Benutzern mit begrenzten Datentarifen.
Sie können die automatische Auffüllung anpassen, um sie besser an Ihre Bedürfnisse anzupassen.
Hier sind einige Ideen für Einstellungen:
Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH
(2820 Bytes) aus Kompatibilitätsgründen mit Firefox für Android (siehe Nr. 108)Encryption::MAX_PAYLOAD_LENGTH
(4078 Bytes) für maximale Sicherheitfalse
für maximale LeistungX
Bytes nicht überschreiten, legen Sie den Wert auf X
fest, um das beste Gleichgewicht zwischen Sicherheit und Leistung zu erzielen. <?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 verwendet Guzzle. Es verwendet den am besten geeigneten Client, den es findet, und in den meisten Fällen handelt es sich um MultiCurl
, das das parallele Senden mehrerer Benachrichtigungen ermöglicht.
Sie können die Standardanforderungsoptionen und das Zeitlimit beim Instanziieren von WebPush anpassen:
<?php
use Minishlink WebPush WebPush ;
$ timeout = 20 ; // seconds
$ clientOptions = [
GuzzleHttp RequestOptions:: ALLOW_REDIRECTS => false ,
]; // see GuzzleHttp RequestOptions
$ webPush = new WebPush ([], [], $ timeout , $ clientOptions );
Folgendes ist verfügbar:
Fühlen Sie sich frei, Ihre eigenen hinzuzufügen!
Die Nutzlast wird gemäß dem Message Encryption for Web Push-Standard verschlüsselt, wobei der öffentliche Benutzerschlüssel und das Authentifizierungsgeheimnis verwendet werden, die Sie erhalten können, indem Sie der Web Push API-Spezifikation folgen.
Intern verwendet WebPush das WebToken-Framework und OpenSSL, um die Generierung und Verschlüsselung von Verschlüsselungsschlüsseln zu verwalten.
Hier sind einige Ideen:
defaultOptions
oder als Parameter für flush()
fest).flushPooled()
anstelle von flush()
. Ersteres verwendet gleichzeitige Anfragen, was den Prozess beschleunigt und oft die Geschwindigkeit der Anfragen verdoppelt.Ihrer Installation fehlen einige Zertifikate.
php.ini
: Geben Sie nach [curl]
curl.cainfo = /path/to/cacert.pem
ein.Sie können die Verwendung eines Clients auch ohne Peer-Verifizierung erzwingen.
Stellen Sie sicher, dass Sie den Autoloader von Composer benötigen.
require __DIR__ . ' /path/to/vendor/autoload.php ' ;
Stellen Sie sicher, dass die Datenbankfelder groß genug für die Länge der von Ihnen gespeicherten Daten sind (#233). Für den Endpunkt haben Benutzer berichtet, dass die URL-Länge 500 Zeichen nicht überschreitet. Dies kann sich jedoch ändern, sodass Sie die 2048-Zeichen-Grenze der meisten Browser festlegen können.
Siehe Ausgabe Nr. 58.
Dieser Dienst existiert nicht mehr. Es wurde am 29. Mai 2019 durch Googles Firebase Cloud Messaging (FCM) ersetzt.
Diese Bibliothek unterstützt Firebase Cloud Messaging (FCM) nicht. Alte Chrome-Abonnements (vor 2018 und VAPID) verwenden das Legacy-HTTP-Protokoll von Firebase Cloud Messaging (FCM), das seit 2023 veraltet ist und im Juni 2024 nicht mehr funktioniert. Die Unterstützung für dieses veraltete Abonnement wird entfernt.
Bitte lassen Sie sich nicht verwechseln, da das Legacy-HTTP-Protokoll und Web Push mit VAPID die identische Endpunkt-URL verwenden:
https://fcm.googleapis.com/fcm/send
Web Push mit VAPID bleibt unter dieser URL verfügbar. Derzeit besteht kein weiterer Handlungsbedarf.
Die Browser-Anbieter erlauben nicht, Daten über die Push-API zu senden, ohne eine Benachrichtigung zu erstellen. Verwenden Sie einige alternative APIs wie WebSocket/WebTransport oder Hintergrundsynchronisierung.
WebPush ist für Web-Apps. Sie benötigen so etwas wie RMSPushNotificationsBundle (Symfony).
Diese Bibliothek wurde von der Node.js-Bibliothek web-push-libs/web-push inspiriert.
server.js
macht Ihnen nichts aus: Sie sollte durch Ihren PHP-Servercode mit dieser Bibliothek ersetzt werden)MIT