PHP 用 Web プッシュ ライブラリ
WebPush は、Web プッシュ プロトコルで説明されているように、エンドポイントにプッシュ メッセージを送信するために使用できます。
このプッシュ メッセージはブラウザーによって受信され、Service Worker と通知 API を使用して通知を作成できます。
PHP 8.1 以降および次の拡張機能:
古い PHP バージョンに対するサポートとメンテナンスはありませんが、次の互換性のあるバージョンを自由に使用できます。
v1.x
v2.x
v3.x-v5.x
v6.x
v7.x
v8.x
この README は最新バージョンとのみ互換性があります。ライブラリの各バージョンには、対応する README を読むことができる git タグがあります。
Composer を使用して、ライブラリとその依存関係をダウンロードしてインストールします。
composer require minishlink/web-push
web-push-php
を使用した html+JS フロントエンドと 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
Linux bash にアクセスできない場合は、 createVapidKeys
関数の出力を印刷できます。
var_dump ( VAPID :: createVapidKeys ()); // store the keys afterwards
クライアント側では、VAPID 公開キーをapplicationServerKey
としてサブスクライブすることを忘れないでください: ( urlBase64ToUint8Array
ソースはここにあります)
serviceWorkerRegistration . pushManager . subscribe ( {
userVisibleOnly : true ,
applicationServerKey : urlBase64ToUint8Array ( vapidPublicKey )
} )
VAPID ヘッダーは、JSON Web Token (JWT) を使用して身元を確認します。このトークン ペイロードには、サブスクリプションに含まれるエンドポイントのプロトコルとホスト名、有効期限タイムスタンプ (通常は 12 ~ 24 時間) が含まれており、公開キーと秘密キーを使用して署名されています。そのため、同じプッシュ サービスに送信される 2 つの通知は同じトークンを使用するため、以下を使用して同じフラッシュ セッションでそれらを再利用してパフォーマンスを向上させることができます。
$ 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 ]);
Time To Live (TTL、秒単位) は、ユーザーのブラウザがまだアクセスできない (接続されていないなど) 場合に、プッシュ サービス (Mozilla など) によってプッシュ メッセージが保持される期間です。重要な通知には非常に長い時間を使用したい場合があります。デフォルトの TTL は 4 週間です。ただし、不要な通知を複数送信する場合は、TTL を 0 に設定します。プッシュ通知は、ユーザーが現在接続している場合にのみ配信されます。その他のケースでは、ユーザーが複数のタイムゾーンを持っている場合は少なくとも 1 日を使用する必要があり、そうでない場合は数時間で十分です。
緊急度は、「非常に低い」、「低い」、「通常」、または「高い」のいずれかです。ブラウザ ベンダーがこの機能を実装している場合、モバイル デバイスのバッテリー寿命が節約されます (プロトコルを参照)。
この文字列により、ベンダーはこのトピックの最後の通知のみをユーザーに表示します (プロトコルを参照)。
一度に数万件の通知を送信すると、Guzzle でのエンドポイントの呼び出し方法が原因でメモリ オーバーフローが発生する可能性があります。これを修正するために、WebPush は通知をバッチで送信します。デフォルトのサイズは 1000 です。サーバー構成 (メモリ) によっては、この数値を減らすことができます。これは、WebPush をインスタンス化するか、 setDefaultOptions
呼び出すときに実行します。または、これを特定のフラッシュ用にカスタマイズしたい場合は、パラメータとして指定します: $webPush->flush($batchSize)
。
エラー (プッシュ サブスクリプションの有効期限、間違ったパラメータなど) が発生した場合に、ブラウザ ベンダーのサーバーが何を送り返すかを確認できます。
sendOneNotification()
MessageSentReport
返しますflush()
MessageSentReport
オブジェクトを含むGenerator
返します。結果をループするには、結果を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
オブジェクトに対して反復できるのは1 回だけです。
Firefox のエラーは自動プッシュのドキュメントにリストされています。
ペイロードはライブラリによって暗号化されます。最大ペイロード長は理論的には 4078 バイト (または ASCII 文字) です。ただし、互換性の理由 (アーカイブ) から、ペイロードの長さは 3052 バイト未満である必要があります。
ライブラリはデフォルトでペイロードをパディングします。これはより安全ですが、サーバーとユーザーのデバイスの両方のパフォーマンスが低下します。
特定の長さの文字列を暗号化すると、最初の文字列を何回暗号化しても、結果の文字列は常に同じ長さになります。これにより、攻撃者がペイロードの内容を推測できるようになります。これを回避するために、このライブラリは初期ペイロードにヌル パディングを追加し、暗号化プロセスのすべての入力が同じ長さになるようにします。こうすることで、暗号化プロセスのすべての出力も同じ長さになり、攻撃者はペイロードの内容を推測できなくなります。
より多くのバイトを暗号化すると、サーバーでの実行時間が長くなり、復号化によるユーザーのデバイスの速度も低下します。また、パケットの送受信に時間がかかります。また、データプランが限られているユーザーにとってもあまり親切ではありません。
ニーズに合わせて自動パディングをカスタマイズできます。
設定のアイデアをいくつか示します。
Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH
(2820 バイト) (#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 プッシュ API 仕様に従うことで取得できるユーザー公開キーと認証シークレットを使用して、Web プッシュのメッセージ暗号化標準に従って暗号化されます。
内部的には、WebPush は WebToken フレームワークと OpenSSL を使用して、暗号化キーの生成と暗号化を処理します。
以下にいくつかのアイデアを示します。
defaultOptions
に設定するか、 flush()
のパラメーターとして設定します)。flush()
の代わりにflushPooled()
を使用してください。前者は同時リクエストを使用してプロセスを加速し、多くの場合リクエストの速度が 2 倍になります。インストールにいくつかの証明書がありません。
php.ini
を編集します。 [curl]
の後に、 curl.cainfo = /path/to/cacert.pem
と入力します。ピア検証を行わずにクライアントを強制的に使用することもできます。
Composer のオートローダーを必ず必要にしてください。
require __DIR__ . ' /path/to/vendor/autoload.php ' ;
保存するデータの長さに十分な大きさのデータベース フィールドがあることを確認してください (#233)。エンドポイントについては、URL の長さが 500 文字を超えないとユーザーが報告していますが、これは進化する可能性があり、ほとんどのブラウザーで 2048 文字の制限に設定できるようになります。
問題 #58 を参照してください。
このサービスはもう存在しません。 2019 年 5 月 29 日に、Google の Firebase Cloud Messaging (FCM) に置き換えられました。
このライブラリは Firebase Cloud Messaging (FCM) をサポートしていません。古い Chrome サブスクリプション (2018 年以前および VAPID) は、Firebase Cloud Messaging (FCM) によるレガシー HTTP プロトコルを使用しますが、これは 2023 年から非推奨となり、2024 年 6 月に機能しなくなります。この古いサブスクリプションのサポートは削除されます。
レガシー HTTP プロトコルと VAPID を使用した Web プッシュは同一のエンドポイント URL を使用するため、混同しないでください。
https://fcm.googleapis.com/fcm/send
VAPID を使用した Web プッシュは、引き続きこの URL で利用できます。現時点ではこれ以上のアクションは必要ありません。
ブラウザ ベンダーは、通知を作成せずにプッシュ API を使用してデータを送信することを許可していません。 WebSocket/WebTransport やバックグラウンド同期などの代替 API を使用します。
WebPush は Web アプリ用です。 RMSPushNotificationsBundle (Symfony) のようなものが必要です。
このライブラリは、Node.js web-push-libs/web-push ライブラリからインスピレーションを得たものです。
server.js
ファイルは気にしないでください。このライブラリを使用して PHP サーバー コードに置き換える必要があります)マサチューセッツ工科大学