Pemberitahuan Push Browser dalam Javascript dan PHP

Kata pengantar

Dalam upaya menemukan artikel bagus tentang menyiapkan notifikasi di browser, saya hanya menerima artikel yang terutama menjelaskan penggunaan bersama dengan Firebase, tetapi opsi ini tidak terlalu cocok untuk saya.





Dalam artikel ini, prinsip pengoperasian dan seluk-beluk pemberitahuan Push tidak akan "berkeringat", hanya kodenya, hanya hardcorenya.





Catatan penting





Pemberitahuan push hanya berfungsi dengan HTTPS .

Omong-omong, selain HTTPS, sertifikat SSL yang valid harus ada, Let's Encrypt akan melakukannya.





Localhost baik-baik saja untuk pengembangan. Seharusnya tidak ada masalah, tetapi jika Anda muncul, artikel ini akan membantu Anda mengatasinya.





Biar ada kode

Otorisasi (VAPID)

Pertama, ada baiknya menginstal pustaka WebPush ke dalam proyek php Anda:





$ composer require minishlink/web-push
      
      



Selanjutnya, untuk mengotorisasi server Anda dengan browser (VAPID), Anda perlu membuat kunci ssh publik dan pribadi. Kunci-kunci ini akan diperlukan baik di server maupun di klien (kecuali bahwa hanya kunci publik yang diperlukan di klien) .





Untuk menghasilkan kunci publik dan pribadi yang disandikan Base64 yang tidak dikompresi, masukkan yang berikut ke dalam bash Linux Anda:





$ 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
      
      



Juga, penulis perpustakaan menyediakan pembuatan kunci vapid menggunakan metode bawaan:





$vapidKeysInBase64 = VAPID::createVapidKeys();
      
      



Berlangganan

Tahap 1 (JS)

ServiceWorker, PushManager, showNotification :





app.js





function checkNotificationSupported() {
	return new Promise((fulfilled, reject) => {
  	if (!('serviceWorker' in navigator)) {
      reject(new Error('Service workers are not supported by this browser'));
      return;
    }

    if (!('PushManager' in window)) {
      reject(new Error('Push notifications are not supported by this browser'));
      return;
    }

    if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
      reject(new Error('Notifications are not supported by this browser'));
    	return;
    }
    
    fulfilled();
  })
}
      
      



sw.js :





app.js





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



:





app.js





function checkNotificationPermission() {
    return new Promise((fulfilled, reject) => {
        if (Notification.permission === 'denied') {
            return reject(new Error('Push messages are blocked.'));
        }
        if (Notification.permission === 'granted') {
            return fulfilled();
        }
        if (Notification.permission === 'default') {
            return Notification.requestPermission().then(result => {
                if (result !== 'granted') {
                    reject(new Error('Bad permission result'));
                } else {
                    fulfilled();
                }
            });
        }
        return reject(new Error('Unknown permission'));
    });
}
      
      



ssh :





<script>
	window.applicationServerKey = '<?= $yourPublicKeyFromServer ?>'
</script>
      
      



, . 10 .





app.js





document.addEventListener('DOMContentLoaded', documentLoadHandler);


function documentLoadHandler() {
    checkNotificationSupported()
        .then(() => {
          setTimeout(() => {
            serviceWorkerRegistration.pushManager.subscribe({
                    userVisibleOnly: true,
                    applicationServerKey: urlBase64ToUint8Array(window.applicationServerKey),
                })
                .then(successSubscriptionHandler, errorSubscriptionHandler)
          }, 10000);
         }, 
        	console.error
      	);
}


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 errorSubscriptionHandler(err) {
    if (Notification.permission === 'denied') {
        console.warn('Notifications are denied by the user.');
    } else {
        console.error('Impossible to subscribe to push notifications', err);
    }
}
      
      



successSubscriptionHandler





.





app.js





function successSubscriptionHandler(subscriptionData) {
    const key = subscription.getKey('p256dh');
    const token = subscription.getKey('auth');
    const contentEncoding = (PushManager.supportedContentEncodings || ['aesgcm'])[0];
    const body = new FormData();

    body.set('endpoint', subscription.endpoint);
    body.set('publicKey', key ? btoa(String.fromCharCode.apply(null, new Uint8Array(key))) : null);
    body.set('authToken', token ? btoa(String.fromCharCode.apply(null, new Uint8Array(token))) : null);
    body.set('contentEncoding', contentEncoding);

    return fetch('src/push_subscription.php', {
      method,
      body,
    }).then(() => subscription);
  }
      
      







Post Message API





self.addEventListener('push', function (event) {
    if (!(self.Notification && self.Notification.permission === 'granted')) {
        return;
    }

    const sendNotification = body => {
        const title = " ";

        return self.registration.showNotification(title, {
            body,
        });
    };

    if (event.data) {
        const message = event.data.text();
        event.waitUntil(sendNotification(message));
    }
});
      
      



2 (PHP)

php 7+





subscribeUserToPushNotifications ,





subscribeUserToPushNotifications.php





<?php 

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

// save subscription from => $subscription 
      
      



( ), .









, :





pushNotificationToClient.php





<?php 

use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;

$subscription = Subscription::create($subscriptionData);
      
      



VAPID :





pushNotificationToClient.php





<?php 

$auth = array(
    'VAPID' => array(
        'subject' => 'https://your-project-domain.com',
        'publicKey' => file_get_contents(__DIR__ . '/your_project/keys/public_key.txt'),
        'privateKey' => file_get_contents(__DIR__ . '/your_project/keys/private_key.txt'), 
    )
);
      
      



, WebPush:





pushNotificationToClient.php





<?php

$webPush = new WebPush($auth);
      
      



! Push





<?php

$report = $webPush->sendOneNotification(
  $subscription,
  "  ,     sw.js"
);
      
      



Catatan penting





Untuk mengirim notifikasi dalam iterasi, Anda harus menggunakan fungsi dengan parameter yang sama seperti pada fungsi di atas:





$webPush->queueNotification







Sumber Bermanfaat

  1. Tentang teknologi dorong





  2. Tentang WebPush dari Khabrovchanin





  3. Pustaka WebPush





  4. Contoh penggunaan dari pengembang perpustakaan








All Articles