- Install library 'composer require minishlink/web-push'
- You should generate VAPID keys.
- Than replace "VAPID PUBLIC KEY" and "VAPID PRIVATE KEY" inside php script. Replace:
- 'BFrp-TvkuqCeNsytRt...'
- '9BvI1aN1CR4w4iceMS...'
- Than replace "VAPID PUBLIC KEY" inside js script. Replace: 'BFrp-TvkuqCeNsytRt...'
- Than upload files ('service-worker.js', 'index.html', 'send.php') to web site
- Open 'index.html' in browser and allow push notification. After that you will see 'endpoint', 'p256dh', 'auth' in console.
- Set these params ('endpoint', 'p256dh', 'auth') to php script ('send.php'). Replace:
- 'https://fcm.googleapis.com/fcm/send/djRg_IDPtSs:APA91bFwYCC73F4X3cXELK...'
- 'SPB_NNfRw...'
- 'BP-WMuJdP7buopSb_HrNX...'
- Open 'send.php' in browser. And push will be sent.
This code is working in Chrome and Mozilla.
generate.php - to generate VAPID keys:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
header('Content-Type: text/html; charset=utf-8');
require __DIR__ . '/vendor/autoload.php';
use Minishlink\WebPush\VAPID;
print_r(VAPID::createVapidKeys());
service-worker.js
'use strict';
/**
* Received push
*/
self.addEventListener('push', function (event) {
let pushMessageJSON = event.data.json();
self.registration.showNotification(pushMessageJSON.title, {
body: pushMessageJSON.body,
icon: pushMessageJSON.icon,
vibrate: pushMessageJSON.data.vibrate,
data: {
additionalData: pushMessageJSON.data.additionalData,
url: pushMessageJSON.data.url,
},
});
console.info("**** Recv'd a push message::", event);
});
/**
* Click by push
*/
self.addEventListener('notificationclick', function(event) {
let url = event.notification.data.url;
event.notification.close(); // Android needs explicit close.
if (!url) return;
event.waitUntil(
clients.matchAll({type: 'window'}).then( windowClients => {
// Check if there is already a window/tab open with the target URL
for (var i = 0; i < windowClients.length; i++) {
var client = windowClients[i];
// If so, just focus it.
if (client.url === url && 'focus' in client) {
return client.focus();
}
}
// If not, then open the target URL in a new window/tab.
if (clients.openWindow) {
return clients.openWindow(url);
}
})
);
});
self.addEventListener('message', function (event) {
// A message has been sent to this service worker.
console.log("sw Handling message event:", event);
});
self.addEventListener('pushsubscriptionchange', function (event) {
// The Push subscription ID has changed. The App should send this
// information back to the App Server.
console.log("sw Push Subscription Change", event);
event.waitUntil(
self.clients.matchAll()
.then(clientList => {
let sent = false;
console.debug("Service worker found clients",
JSON.stringify(clients));
clientList.forEach(client => {
console.debug("Service worker sending to client...", client);
sent = true;
client.postMessage({'type': 'update'});
});
if (sent == false) {
throw new Error("No valid client to send to.");
}
})
.catch(err => {
console.error("Service worker couldn't send message: ", err);
})
);
});
self.addEventListener('registration', function (event) {
// The service worker has been registered.
console.log("sw Registration: ", event);
});
self.addEventListener('install', function (event) {
// The serivce worker has been loaded and installed.
// The browser aggressively caches the service worker code.
console.log("sw Install: ", JSON.stringify(event));
// This replaces currently active service workers with this one
// making this service worker a singleton.
event.waitUntil(self.skipWaiting());
console.log("sw Installed: ", JSON.stringify(event));
});
self.addEventListener('activate', function (event) {
// The service worker is now Active and functioning.
console.log("sw Activate : ", JSON.stringify(event));
// Again, ensure that this is the only active service worker for this
// page.
event.waitUntil(self.clients.claim());
console.log("sw Activated: ", JSON.stringify(event));
navigator.serviceWorker
});
index.html to request push notification
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1"/>
</head>
<body>
<script>
if (!Notification) {
console.log('*Browser does not support Web Notification');
}
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('service-worker.js?v=1', {scope: './'})
.then(function (registration) {
console.log("Service Worker Registered");
})
.catch(function (err) {
console.log("Service Worker Failed to Register", err);
})
}
navigator.serviceWorker.ready.then((reg) => {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: 'BFrp-TvkuqCeNsytRt...'
};
reg.pushManager.subscribe(subscribeOptions).then((subscription) => {
//send endpoint, p256dh and auth to backend
console.log('endpoint is: ' + subscription.endpoint);
console.log('p256dh is: ' + subscription.toJSON().keys.p256dh);
console.log('auth is: ' + subscription.toJSON().keys.auth);
document.write('<p>endpoint is: ' + subscription.endpoint + '</p>');
document.write('<p>p256dh is: ' + subscription.toJSON().keys.p256dh + '</p>');
document.write('<p>auth is: ' + subscription.toJSON().keys.auth + '</p>');
});
});
</script>
</body>
</html>
send.php to send push notification
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
header('Content-Type: text/html; charset=utf-8');
require __DIR__ . '/vendor/autoload.php';
use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;
$push = [
'subscription' => Subscription::create([
'endpoint' => 'https://fcm.googleapis.com/fcm/send/djRg_IDPtSs:APA91bFwYCC73F4X3cXELK...',
'keys' => [
'auth' => 'SPB_NNfRw...',
'p256dh' => 'BP-WMuJdP7buopSb_HrNX...'
]
]),
'payload' => json_encode([
'title' => "Hello",
'body' => "How are you?",
'icon' => "https://cdn-icons-png.flaticon.com/512/3884/3884851.png",
'data' => [
'vibrate' => [100, 200],
'additionalData' => [],
'url' => "https://google.com",
],
]),
];
$auth = [
'VAPID' => [
'subject' => 'support@gmail.com', // can be a mailto: or your website address
'publicKey' => 'BFrp-TvkuqCeNsytRt...', // (recommended) uncompressed public key P-256 encoded in Base64-URL
'privateKey' => '9BvI1aN1CR4w4iceMS...', // (recommended) in fact the secret multiplier of the private key encoded in Base64-URL
],
];
$webPush = new WebPush($auth);
try {
$webPush->queueNotification(
$push['subscription'],
$push['payload']
);
$report = $webPush->flush()->current();
$is_success = $report->isSuccess();
$response = $report->getResponseContent();
} catch (\Throwable $th) {
$is_success = false;
$response = $th->getMessage();
}
if ($is_success) {
echo "Push was sent";
} else {
echo "Push was not sent. Error message: " . $response;
}