How To Create Web Push Notification Or Browser Notification Using PHP

What is Web Push Notification Or Browser Notification ?

Web push notification Or Browser Notification is clickable content that sent by website to your device to re-engage the audience. Web

How to integrate the Web Push Notification Or Browser Notification to our website?

we are using Web Push Library For this tutorial

Install library using composer commandcomposer require minishlink/web-push

Requirements

  • PHP 7.1+
    • gmp
    • mbstring
    • curl
    • openssl

To work with this code you need to generate application server keys. You can generate from this link https://web-push-codelab.glitch.me/

Copy your public key into app.js

const applicationServerKey =<Your Public Key>;

Now we have to Register a Service Worker

Service worker contain two event listener.

  • showNotification(push) Listener
  • notificationclick Listener

serviceWorker.js File

let notification_data = false;
self.addEventListener('push', function(event) {
    notification_data = JSON.parse(event.data.text());

    if (!(self.Notification && self.Notification.permission === 'granted')) {
        return;
    }
    if (event.data) {

        const title = notification_data.title;
        const options = {
            body: notification_data.body,
            icon: notification_data.icon,
            badge: notification_data.badge
        };
        event.waitUntil(self.registration.showNotification(title, options));
    }
});

self.addEventListener('notificationclick', function(event) {
    console.log('[Service Worker] Notification click Received.');
    console.log(notification_data);
    // var notification_data = JSON.parse(event.data.text());
    event.notification.close();

    event.waitUntil(
        clients.openWindow(notification_data.url)
    );
});

When a push message is received, showNotification() event listener will be fired, and we create a notification registration.

Create send_push_notification.php  file contains the send notification code

<?php
require 'vendor/autoload.php';
use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;

// here I'll get the subscription endpoint in the POST parameters
// but in reality, you'll get this information in your database
// because you already stored it (cf. push_subscription.php)
$request_data=json_decode(file_get_contents('php://input'), true);
// print_r($request_data);exit;
$subscription = Subscription::create($request_data);

$auth = array(
    'VAPID' => array(
        'subject' => 'https://github.com/Minishlink/web-push-php-example/',
        'publicKey' => 'Your Public Key', // don't forget that your public key also lives in app.js
        'privateKey' => 'Your Private Key', // in the real world, this would be in a secret file
    ),
);
// print_r($subscription);exit;
$webPush = new WebPush($auth);
$notification_data['title']=($request_data['body_data']['title'])?$request_data['body_data']['title']:'This is title';
$notification_data['body']=($request_data['body_data']['body'])?$request_data['body_data']['body']:'This is body';
$notification_data['url']=($request_data['body_data']['url'])?$request_data['body_data']['url']:'https://www.itinfotech.in/';
$notification_data['icon']='images/icon.png';
$notification_data['badge']='images/badge.png';

$res = $webPush->sendNotification(
    $subscription,
    json_encode($notification_data)
);

// handle eventual errors here, and remove the subscription from your server if it is expired
foreach ($webPush->flush() as $report) {
    $endpoint = $report->getRequest()->getUri()->__toString();

    if ($report->isSuccess()) {
        $response_data['code']=1;
        $response_data['msg']="Notification sent successfully for subscription {$endpoint}";
        echo json_encode($response_data);exit;
    } else {
        $response_data['code']=0;
        $response_data['msg']="[x] Message failed to sent for subscription {$endpoint}: {$report->getReason()}";
        echo json_encode($response_data);exit;
       
    }
}

Create app.js File. File contains the subscription related Code

document.addEventListener('DOMContentLoaded', () => {
    const applicationServerKey =Your Public Key';
    let isPushEnabled = false;

    const pushButton = document.querySelector('#push-subscription-button');
    if (!pushButton) {
        return;
    }

    pushButton.addEventListener('click', function() {
        if (isPushEnabled) {
            push_unsubscribe();
        } else {
            push_subscribe();
        }
    });

    if (!('serviceWorker' in navigator)) {
        console.warn('Service workers are not supported by this browser');
        changePushButtonState('incompatible');
        return;
    }

    if (!('PushManager' in window)) {
        console.warn('Push notifications are not supported by this browser');
        changePushButtonState('incompatible');
        return;
    }

    if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
        console.warn('Notifications are not supported by this browser');
        changePushButtonState('incompatible');
        return;
    }

    // Check the current Notification permission.
    // If its denied, the button should appears as such, until the user changes the permission manually
    if (Notification.permission === 'denied') {
        console.warn('Notifications are denied by the user');
        changePushButtonState('incompatible');
        return;
    }

    navigator.serviceWorker.register('serviceWorker.js').then(
        () => {
            console.log('[SW] Service worker has been registered');
            push_updateSubscription();
        },
        e => {
            console.error('[SW] Service worker registration failed', e);
            changePushButtonState('incompatible');
        }
    );

    function changePushButtonState(state) {
        switch (state) {
            case 'enabled':
                pushButton.disabled = false;
                pushButton.textContent = 'Disable Push notifications';
                isPushEnabled = true;
                break;
            case 'disabled':
                pushButton.disabled = false;
                pushButton.textContent = 'Enable Push notifications';
                isPushEnabled = false;
                break;
            case 'computing':
                pushButton.disabled = true;
                pushButton.textContent = 'Loading...';
                break;
            case 'incompatible':
                pushButton.disabled = true;
                pushButton.textContent = 'Push notifications are not compatible with this browser';
                break;
            default:
                console.error('Unhandled push button state', state);
                break;
        }
    }

    function urlBase64ToUint8Array(base64String) {
        const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
        const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');

        const rawData = window.atob(base64);
        const outputArray = new Uint8Array(rawData.length);

        for (let i = 0; i < rawData.length; ++i) {
            outputArray[i] = rawData.charCodeAt(i);
        }
        return outputArray;
    }

    function checkNotificationPermission() {
        return new Promise((resolve, reject) => {
            if (Notification.permission === 'denied') {
                return reject(new Error('Push messages are blocked.'));
            }

            if (Notification.permission === 'granted') {
                return resolve();
            }

            if (Notification.permission === 'default') {
                return Notification.requestPermission().then(result => {
                    if (result !== 'granted') {
                        reject(new Error('Bad permission result'));
                    }

                    resolve();
                });
            }
        });
    }

    function push_subscribe() {
        changePushButtonState('computing');

        return checkNotificationPermission()
            .then(() => navigator.serviceWorker.ready)
            .then(serviceWorkerRegistration =>
                serviceWorkerRegistration.pushManager.subscribe({
                    userVisibleOnly: true,
                    applicationServerKey: urlBase64ToUint8Array(applicationServerKey),
                })
            )
            .then(subscription => {
                // Subscription was successful
                // create subscription on your server
                return push_sendSubscriptionToServer(subscription, 'POST');
            })
            .then(subscription => subscription && changePushButtonState('enabled')) // update your UI
            .catch(e => {
                if (Notification.permission === 'denied') {
                    // The user denied the notification permission which
                    // means we failed to subscribe and the user will need
                    // to manually change the notification permission to
                    // subscribe to push messages
                    console.warn('Notifications are denied by the user.');
                    changePushButtonState('incompatible');
                } else {
                    // A problem occurred with the subscription; common reasons
                    // include network errors or the user skipped the permission
                    console.error('Impossible to subscribe to push notifications', e);
                    changePushButtonState('disabled');
                }
            });
    }

    function push_updateSubscription() {
        navigator.serviceWorker.ready
            .then(serviceWorkerRegistration => serviceWorkerRegistration.pushManager.getSubscription())
            .then(subscription => {
                changePushButtonState('disabled');

                if (!subscription) {
                    // We aren't subscribed to push, so set UI to allow the user to enable push
                    return;
                }

                // Keep your server in sync with the latest endpoint
                return push_sendSubscriptionToServer(subscription, 'PUT');
            })
            .then(subscription => subscription && changePushButtonState('enabled')) // Set your UI to show they have subscribed for push messages
            .catch(e => {
                console.error('Error when updating the subscription', e);
            });
    }

    function push_unsubscribe() {
        changePushButtonState('computing');

        // To unsubscribe from push messaging, you need to get the subscription object
        navigator.serviceWorker.ready
            .then(serviceWorkerRegistration => serviceWorkerRegistration.pushManager.getSubscription())
            .then(subscription => {
                // Check that we have a subscription to unsubscribe
                if (!subscription) {
                    // No subscription object, so set the state
                    // to allow the user to subscribe to push
                    changePushButtonState('disabled');
                    return;
                }

                // We have a subscription, unsubscribe
                // Remove push subscription from server
                return push_sendSubscriptionToServer(subscription, 'DELETE');
            })
            .then(subscription => subscription.unsubscribe())
            .then(() => changePushButtonState('disabled'))
            .catch(e => {
                // We failed to unsubscribe, this can lead to
                // an unusual state, so  it may be best to remove
                // the users data from your data store and
                // inform the user that you have done so
                console.error('Error when unsubscribing the user', e);
                changePushButtonState('disabled');
            });
    }

    function push_sendSubscriptionToServer(subscription, method) {
        const key = subscription.getKey('p256dh');
        const token = subscription.getKey('auth');
        const contentEncoding = (PushManager.supportedContentEncodings || ['aesgcm'])[0];

        return fetch('push_subscription.php', {
            method,
            body: JSON.stringify({
                endpoint: subscription.endpoint,
                publicKey: key ? btoa(String.fromCharCode.apply(null, new Uint8Array(key))) : null,
                authToken: token ? btoa(String.fromCharCode.apply(null, new Uint8Array(token))) : null,
                contentEncoding,
            }),
        }).then(() => subscription);
    }

    /**
     * START send_push_notification
     * this part handles the button that calls the endpoint that triggers a notification
     * in the real world, you wouldn't need this, because notifications are typically sent from backend logic
     */

    const sendPushButton = document.querySelector('#send-push-button');
    if (!sendPushButton) {
        return;
    }

    sendPushButton.addEventListener('click', () =>
        navigator.serviceWorker.ready
        .then(serviceWorkerRegistration => serviceWorkerRegistration.pushManager.getSubscription())
        .then(subscription => {
            if (!subscription) {
                $('#alert_error').show();
                $('#alert_error').html('Please enable push notifications');
                return;
            }
            $('#alert_error').hide();
            const contentEncoding = (PushManager.supportedContentEncodings || ['aesgcm'])[0];
            const body_data = { 'title': $('#title').val(), 'body': $('#body').val(), 'url': $('#body').val() };
            const jsonSubscription = subscription.toJSON();
            const request = async() => {
                let response = fetch('send_push_notification.php', {
                        method: 'POST',
                        body: JSON.stringify(Object.assign(jsonSubscription, { contentEncoding }, { body_data })),
                    }).then(response => response.json())
                    .then(result => {
                        if (result.code) {
                            $('#alert_error').hide();
                            $('#alert_success').show();
                            $('#alert_success').html(result.msg);
                        } else {
                            $('#alert_success').hide();
                            $('#alert_error').show();
                            $('#alert_error').html(result.msg);
                        }
                        // console.log('Success:', result);

                    }).catch(error => {
                        $('#alert_error').show();
                        $('#alert_error').html(error);
                        // console.error('Error:', error);
                    });
            };
            request();
        }));
    /**
     * END send_push_notification
     */
});

Create push_subscription.php File. File contains the subscription related code

<?php
$subscription = json_decode(file_get_contents('php://input'), true);

if (!isset($subscription['endpoint'])) {
    echo 'Error: not a subscription';
    return;
}

$method = $_SERVER['REQUEST_METHOD'];

switch ($method) {
    case 'POST':
        // create a new subscription entry in your database (endpoint is unique)
        break;
    case 'PUT':
        // update the key and token of subscription corresponding to the endpoint
        break;
    case 'DELETE':
        // delete the subscription corresponding to the endpoint
        break;
    default:
        echo "Error: method not handled";
        return;
}

We are done web push notification. Thank You

Add a Comment

Your email address will not be published. Required fields are marked *