minishlink/web-push
PHP library to send Web Push notifications to browser push endpoints (RFC 8030). Handles VAPID and payload encryption, supports batching and reporting, and works with modern PHP (8.2+) via Composer for integrating push into your backend.
WebPush now depends on standard interfaces instead of Guzzle directly. Any PSR-18 client now works.
If you already have guzzlehttp/guzzle installed and call new WebPush(...) with no client-related arguments: no code changes needed. php-http/discovery auto-detects Guzzle and uses it. If you use flushPooled(), you now need one extra package, see below.
If you pass the old $timeout / $clientOptions constructor arguments, you must update that call.
Before:
public function __construct(
array $auth = [],
array $defaultOptions = [],
?int $timeout = 30,
array $clientOptions = [],
?LoggerInterface $logger = null
)
After:
public function __construct(
array $auth = [],
array $defaultOptions = [],
?ClientInterface $client = null, // PSR-18
?RequestFactoryInterface $requestFactory = null, // PSR-17
?StreamFactoryInterface $streamFactory = null, // PSR-17
?HttpAsyncClient $asyncClient = null, // HTTPlug, optional, only needed for flushPooled()
?LoggerInterface $logger = null
)
$timeout and $clientOptions are replaced by configuring your client instance directly:
Before:
$timeout = 20;
$clientOptions = [\GuzzleHttp\RequestOptions::ALLOW_REDIRECTS => false];
$webPush = new WebPush([], [], $timeout, $clientOptions);
After:
$client = new \GuzzleHttp\Client([
'timeout' => 20,
\GuzzleHttp\RequestOptions::ALLOW_REDIRECTS => false,
]);
$webPush = new WebPush([], [], $client);
If you were relying on the default (new WebPush()), nothing changes.
flushPooled() used Guzzle's Pool for real concurrent requests. PSR-18 has no concept of concurrency, so this now requires an HTTPlug async client: composer require php-http/guzzle7-adapter (if you use guzzle)
The requestConcurrency option is no longer used, HTTPlug async clients manage their own concurrency (e.g. php-http/guzzle7-adapter delegates to Guzzle's MultiCurl handler).
composer remove guzzlehttp/guzzle
composer require symfony/http-client nyholm/psr7
$psr18Client = new \Symfony\Component\HttpClient\Psr18Client();
$webPush = new WebPush([], [], $psr18Client, $psr18Client, $psr18Client);
For concurrent sending with a non-Guzzle stack (flushPooled), check the php-http adapter list for an HTTPlug adapter matching your client; otherwise use flush().
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v10.1.0...v11.0.0
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v10.0.3...v10.1.0
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v10.0.2...v10.0.3
json_encode by @Rotzbua in https://github.com/web-push-libs/web-push-php/pull/437web-token/jwt-library by @Rotzbua in https://github.com/web-push-libs/web-push-php/pull/438Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v10.0.1...v10.0.2
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v10.0.0...v10.0.1
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v9.0.4...v10.0.0
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v9.0.3...v9.0.4
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v9.0.2...v9.0.3
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v9.0.1...v9.0.2
flushPooled by @sleptor in https://github.com/web-push-libs/web-push-php/pull/410Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v9.0.0...v9.0.1
flushPooled (alternative to flush) to make use of Guzzle Pool to improve efficiency by @Gugu7264 in https://github.com/web-push-libs/web-push-php/pull/401
flushPooled method should not replace flush in a future major release, please comment on this PRinstantiating by @Rotzbua in https://github.com/web-push-libs/web-push-php/pull/374Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v8.0.0...v9.0.0
In this release candidate:
In the final version v9.0.0, there will be additional breaking changes with PR #394:
flushPooled (alternative to flush) to make use of Guzzle Pool to improve efficiency by @Gugu7264 in https://github.com/web-push-libs/web-push-php/pull/401
flushPooled method should not replace flush in a future major release, please comment on this PRspomky-labs/base64url with paragonie/constant_time_encoding by @Cyperghost in https://github.com/web-push-libs/web-push-php/pull/397" (see https://github.com/web-push-libs/web-push-php/pull/397#issuecomment-2105992954)See also v9.0.0-rc1
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v9.0.0-rc1...v9.0.0-rc2
In this release candidate:
In the final version v9.0.0, there will be additional breaking changes with PR #394:
instantiating by @Rotzbua in https://github.com/web-push-libs/web-push-php/pull/374spomky-labs/base64url with paragonie/constant_time_encoding by @Cyperghost in https://github.com/web-push-libs/web-push-php/pull/397Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v8.0.0...v9.0.0-rc1
The only breaking change is dropping support for PHP 7, which is not maintained anymore. (thanks @Rotzbua!)
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v7.0.0...v8.0.0
There is no breaking change apart PHP 7.2 being now unsupported. @marc1706 did an awesome job bringing back CI testing on the repo, it means pull requests are now easily mergeable. If you have ideas for the library, now is a great time to contribute! (please propose small iterative changes 🙂)
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v6.0.7...v7.0.0
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v6.0.6...v6.0.7
Full Changelog: https://github.com/web-push-libs/web-push-php/compare/v6.0.5...v6.0.6
openssl_pkey_free (thx @smujaddid!)You might want to use v5 since the encryption sometimes fails on certain machines. @Spomky is currently looking at this.
SubscriptionInterface (thx @BR0kEN-!)fcm/send endpoints, so the endpoint is no longer replaced with wpBreaking changes
You now need to iterate over the results of flush in order to actually send the notifications.
The way you handle the results of the flush() method should be changed. In v5 the flush always returns a Generator object. This means that you can still iterate over it, but you wouldn't be able to store it, at least not as-is. Using the example from the docs, the responses would now look different:
PLEASE NOTE:
\Generator is returned even if you only send one message.
BEFORE:
$res = [
[ // first notification (failed)
'success' => false,
'endpoint' => $theEndpointToDeleteInYourDatabaseIfExpired,
'message' => $responseMessage,
'statusCode' => $responseStatusCode,
'headers' => $responseHeaders,
'content' => $responseContent, // you may have more infos here
'expired' => $isTheEndpointWrongOrExpired,
],
[ // second notification (succeeded)
'success' => true,
],
[ // third notification
...
], ...
];
AFTER:
var_dump($res); // \Generator
/** \Minishlink\WebPush\MessageSentReport */
foreach ($res as $result) {
// you now have access to request & response objects
/** [@var](https://github.com/var) \Psr\Http\Message\RequestInterface $request */
$request = $result-> getRequest();
/** [@var](https://github.com/var) \Psr\Http\Message\ResponseInterface $response */
$response = $result->getResponse();
if ($result->isSuccess()) {
// process successful message sent
$logger->log('Notification with payload %s successfully sent for endpoint %s.' [
json_decode((string) $response->getBody()),
$result->getEndpoint()
]);
} else {
// or a failed one - check expiration first
if ($result->isSubscriptionExpired()) {
// this is just an example code, not included in library!
$db->markExpired($result->getEndpoint());
} else {
// process faulty message
$logger->log('Notification failed: %s. Payload: %s, endpoint: %s' [
$result->getReason(),
json_decode((string) $response->getBody()),
$result->getEndpoint()
]);
}
}
}
How can I help you explore Laravel packages today?