PHP용 웹 푸시 라이브러리
WebPush를 사용하면 웹 푸시 프로토콜에 설명된 대로 엔드포인트에 푸시 메시지를 보낼 수 있습니다.
그러면 이 푸시 메시지가 브라우저에 의해 수신되고 서비스 워커와 알림 API를 사용하여 알림을 생성할 수 있습니다.
PHP 8.1+ 및 다음 확장:
이전 PHP 버전에 대한 지원 및 유지 관리는 없지만 다음 호환 버전을 자유롭게 사용할 수 있습니다.
v1.x
v2.x
v3.x-v5.x
v6.x
v7.x
v8.x
이 README는 최신 버전과만 호환됩니다. 라이브러리의 각 버전에는 해당 README를 읽을 수 있는 git 태그가 있습니다.
작곡가를 사용하여 라이브러리와 해당 종속성을 다운로드하고 설치하십시오.
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 헤더는 JWT(JSON 웹 토큰)를 사용하여 신원을 확인합니다. 해당 토큰 페이로드에는 구독에 포함된 엔드포인트의 프로토콜 및 호스트 이름과 만료 타임스탬프(일반적으로 12~24시간 사이)가 포함되어 있으며 공개 키와 개인 키를 사용하여 서명됩니다. 따라서 동일한 푸시 서비스에 전송된 두 개의 알림은 동일한 토큰을 사용하므로 다음을 사용하여 동일한 플러시 세션에 이를 재사용하여 성능을 향상할 수 있습니다.
$ webPush -> setReuseVAPIDHeaders ( true );
각 알림에는 특정 TTL(Time To Live), 긴급성 및 주제가 있을 수 있습니다. 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(TTL, 초 단위)은 사용자 브라우저에 아직 액세스할 수 없는 경우(예: 연결되지 않은 경우) 푸시 서비스(예: Mozilla)에서 푸시 메시지를 보관하는 기간입니다. 중요한 알림에 매우 오랜 시간을 사용하고 싶을 수도 있습니다. 기본 TTL은 4주입니다. 그러나 중요하지 않은 알림을 여러 개 보내는 경우 TTL을 0으로 설정하세요. 푸시 알림은 사용자가 현재 연결된 경우에만 전달됩니다. 다른 경우에는 사용자가 여러 시간대를 사용하는 경우 최소 하루를 사용해야 하며, 그렇지 않은 경우 몇 시간이면 충분합니다.
긴급도는 "매우 낮음", "낮음", "보통" 또는 "높음"일 수 있습니다. 브라우저 공급업체가 이 기능을 구현한 경우 모바일 장치의 배터리 수명을 절약할 수 있습니다(프로토콜 참조).
이 문자열은 공급업체가 이 주제(프로토콜 참조)에 대한 마지막 알림만 사용자에게 표시하도록 합니다.
한 번에 수만 개의 알림을 보내는 경우 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
개체에 대해서는 한 번만 반복할 수 있습니다.
Firefox 오류는 autopush 문서에 나열되어 있습니다.
페이로드는 라이브러리에 의해 암호화됩니다. 최대 페이로드 길이는 이론적으로 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 );
다음을 사용할 수 있습니다.
자유롭게 추가해 보세요!
페이로드는 웹 푸시 API 사양에 따라 얻을 수 있는 사용자 공개 키와 인증 비밀을 사용하여 웹 푸시용 메시지 암호화 표준에 따라 암호화됩니다.
내부적으로 WebPush는 WebToken 프레임워크와 OpenSSL을 사용하여 암호화 키 생성 및 암호화를 처리합니다.
다음은 몇 가지 아이디어입니다.
defaultOptions
에서 설정하거나 flush()
에 대한 매개변수로 설정).flushPooled()
flush()
사용하세요. 전자는 동시 요청을 사용하여 프로세스를 가속화하고 종종 요청 속도를 두 배로 늘립니다.설치에 일부 인증서가 부족합니다.
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의 FCM(Firebase Cloud Messaging)으로 대체되었습니다.
이 라이브러리는 FCM(Firebase Cloud Messaging)을 지원하지 않습니다. 이전 Chrome 구독(2018년 이전 및 VAPID)은 FCM(Firebase Cloud Messaging)의 레거시 HTTP 프로토콜을 사용합니다. 이는 2023년부터 더 이상 사용되지 않으며 2024년 6월에 작동이 중단됩니다. 이 오래된 구독에 대한 지원은 제거됩니다.
레거시 HTTP 프로토콜과 VAPID가 포함된 웹 푸시는 동일한 엔드포인트 URL을 사용하므로 혼동하지 마십시오.
https://fcm.googleapis.com/fcm/send
VAPID를 사용한 웹 푸시는 이 URL에서 계속 사용할 수 있습니다. 현재는 추가 조치가 필요하지 않습니다.
브라우저 공급업체는 알림을 생성하지 않고 Push API를 사용하여 데이터를 보내는 것을 허용하지 않습니다. WebSocket/WebTransport 또는 백그라운드 동기화와 같은 대체 API를 사용하세요.
WebPush는 웹 앱용입니다. RMSPushNotificationsBundle(Symfony)과 같은 것이 필요합니다.
이 라이브러리는 Node.js web-push-libs/web-push 라이브러리에서 영감을 받았습니다.
server.js
파일은 신경 쓰지 마세요. 이 라이브러리가 있는 PHP 서버 코드로 대체되어야 합니다)MIT