web-push-php
web-push-php copied to clipboard
Issue with push notification to chrome
I have implemented the web push notification using the web-push-PHP library and it was working well but now an issue has occurred Users can be subscribed successfully but not able to send the notification. I have print the response of $webPush->sendNotification( $notification['subscription'], $notification['payload'] // optional (defaults null) ); and its return 1 even though notification not push to chrome browser, if I push notification manually from crome-developer mode / application/service-worker then notification will push.
operating system: Linux PHP Version: 7.3
When you send a push using package do you see any errors on chrome? Usually if you keep the website open with the console opened it shows up a message if anything goes wrong (or right). Can you check it and post it here? It would help as well if you could show your service worker file or at least the part where renders the push.
Thanks for the response. When you send a push using package do you see any errors on chrome? Ans- No.
For reference, please check the video URL: https://www.loom.com/share/b08148f79406429385af1e8fee8a25e6
Code for the manifest file
self.addEventListener('push', function(event) { event.waitUntil( self.registration.pushManager.getSubscription().then(function(sub){ subscription_id=sub.endpoint.split("/").slice(-1)[0]; url='data_json.php?sub_id='+subscription_id+'¶m='+Math.random();
}).then(function(obj){
fetch(url).then(function(response) {
return response.text();
}).then(function(ret_content) {
data = JSON.parse(ret_content);
var title = data.notification.title;
var message = data.notification.message;
var icon = data.notification.icon;
return self.registration.showNotification(title, {
body: message,
icon: icon,
tag:'removeNotificationQueue',
data: {
url: data.notification.url
}
});
}).catch(function(err) {
});
})
); });
code for send notification to chrome:
$Subscriber_data = $this->getModel()->getUserData($sub_ids);
foreach($Subscriber_data as $data){
$auth = array(
'VAPID' => array(
'subject' => "subject",
'publicKey' => $data['publickey'],
'privateKey' => $data['privatekey'], // in the real world, this would be in a secret file
),
);
$push_info['title'] = $data['title'];
$push_info['body'] = $data['message'];
$push_info['target_url'] = $data['url'];
$push_info['icon'] = $data['icon'];
// echo"<pre>";print_r($data);die;
$webPush = new WebPush($auth);
$webPush->sendNotification(
$data['endpoint'],
json_encode($push_info), // optional (defaults null)
$data['userpublickey'], // optional (defaults null)
$data['secretkey'] // optional (defaults null)
);
$res = $webPush->flush();
So, i see a problem here:
$webPush = new WebPush($auth);
$webPush->sendNotification(
$data['endpoint'],
json_encode($push_info), // optional (defaults null)
$data['userpublickey'], // optional (defaults null)
$data['secretkey'] // optional (defaults null)
);
you see, the first two arguments of the method sendNotification should be a Subscription object and the JSON payload.
something like this should do the trick:
$push_info['title'] = $data['title'];
$push_info['message'] = $data['message'];
$push_info['url'] = $data['url'];
$push_info['icon'] = $data['icon'];
$subscription = Subscription::create([
'endpoint' => $data['endpoint'],
'publicKey' => $data['userpublickey'],
'authToken' => $data['secretkey']
]);
$webPush = new WebPush($auth);
$webPush->sendNotification(
$subscription,
json_encode($push_info)
);
$res = $webPush->flush();
Let me know what happens, see if you can check any errors in the php logs or something.
Also, just to boost performance, I would leave the loop to do what REALLY needs to be looped. if you devices need different VAPID keys, I would suggest you to find a way to group and loop subscribers that use the same VAPID keys, this way only this section will need to be inside the loop:
$subscription = Subscription::create([
'endpoint' => $data['endpoint'],
'publicKey' => $data['userpublickey'],
'authToken' => $data['secretkey']
]);
$webPush->sendNotification(
$subscription,
$push_info_json
);
Assign the $auth,$webPush variables, json_encoding, and flushing could be outside the loop.
Of course I do not know what are the requirements of your projects, these are all just tips about conventions that are usually followed.
Hi, I'm currenty facing the same issue. I noticed that the push-event of Chrome's service worker is not triggered as long as a payload is supplied although the message seems to be submitted successfully according to this loop:
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()}";
}
}
As soon as the payload is removed the push-event will be triggered but of course with no data. Also formatting the payload in different ways changed nothing for me. I'm guessing Chrome's push service has some sort of rule related to the payload but even though I've been searching the internet for information for two days now I can't seem to find anything related other than this issue and that Chrome used to force you to fetch the content of a notification from within your SW's push-event. But from what I read this isn't supposed to be the case anymore because it used up unneccessary amounts of data.
@edeljokaa You can send payload as long as you use VAPID keys (as far as I know, I might be wrong), so if you are not using VAPID the payload (title and body of the push, among the other properties) will not go through.
Thanks for your response.
From what I understand this is how you use VAPID keys, right?
$payload = array(
"title" => "Testing",
"msg" => "The best test of the world!",
);
$options = array(
'TTL' => 60,
);
$auth = array(
'VAPID' => array(
'subject' => 'mailto:******@**********',
'publicKey' => $this->publicKey,
'privateKey' => $this->privateKey,
),
);
$webPush = new WebPush($auth,$options);
$subscription = Subscription::create(
array(
'endpoint' => $endpoint,
'publicKey' => $this->publicKey,
'authToken' => $this->privateKey,
)
);
if (!is_array($payload)) {
$payload = array($payload);
}
if (count($payload) > 0) {
$payload = json_encode($payload);
}
$webPush->sendNotification(
$subscription,
$payload,
true
);
I hid the e-mailaddress in order to post but it is a valid one. The public and private key were generated using the three openssl commands found in the VAPID-section.
@edeljokaa Your implementation seems to be correct, I tested the second snippet you posted and it is working for me, something weird happened tho:
When I used true for the flush param on sendNotification the push notification would only be deployed if I looped through the response of it. Like this:
$response = $webPush->sendNotification(
$subscription,
$payload,
true
);
foreach($response as $result){
dd($result->isSuccess());
}
Without that last foreach the push never reaches the browser, I'm not sure if that's a bug or something that I got wrong.
Now, when I used the $webPush->flush() method inside a loop (like in the package examples) everything seemed to work just fine.
I'm not really sure what is causing your issue...
@bemontibeller Thanks for your input. At least I know I'm using everything in the correct way. I'll keep searching but since it worked for you, I'm guessing it has something to do with our development environment which is a bit unique.
@bemontibeller thanks for the response,
The problem is only with the desktop Chrome web browser. Web push perfectly works with Mozilla(Firefox), chrome with Android device. I am not understanding if it working with firefox, mobile chrome browser then why is not working with desktop chrome web browser.
Also, just to boost performance, I would leave the loop to do what REALLY needs to be looped. if you devices need different VAPID keys, I would suggest you to find a way to group and loop subscribers that use the same VAPID keys, this way only this section will need to be inside the loop:
$subscription = Subscription::create([ 'endpoint' => $data['endpoint'], 'publicKey' => $data['userpublickey'], 'authToken' => $data['secretkey'] ]); $webPush->sendNotification( $subscription, $push_info_json );Assign the
$auth,$webPushvariables, json_encoding, and flushing could be outside the loop. Of course I do not know what are the requirements of your projects, these are all just tips about conventions that are usually followed.
@bemontibeller thanks for the response,
The problem is only with the desktop Chrome web browser. Web push perfectly works with Mozilla(Firefox), chrome with Android device. I am not understanding if it working with firefox, mobile chrome browser then why is not working with desktop chrome web browser.
@edeljokaa Your implementation seems to be correct, I tested the second snippet you posted and it is working for me, something weird happened tho: When I used
truefor the flush param onsendNotificationthe push notification would only be deployed if I looped through the response of it. Like this:$response = $webPush->sendNotification( $subscription, $payload, true ); foreach($response as $result){ dd($result->isSuccess()); }Without that last foreach the push never reaches the browser, I'm not sure if that's a bug or something that I got wrong. Now, when I used the
$webPush->flush()method inside a loop (like in the package examples) everything seemed to work just fine. I'm not really sure what is causing your issue...
I think it's intended behavior because the sendNotifications method returns a generator. Methods that yield values must be called before they are able to exhaust their contents. So, the notifications in the flush can't send to the endpoints unless they're triggered by a loop