PHP Classes

SaveSubscription failed with: SyntaxError: Unexpected token < in

Recommend this page to a friend!

      PHP Web Push Notifications Server  >  All threads  >  SaveSubscription failed with:...  >  (Un) Subscribe thread alerts  
Subject:SaveSubscription failed with:...
Summary:SaveSubscription failed with: SyntaxError: Unexpected token < in
Messages:8
Author:Sagar jain
Date:2020-10-15 05:17:40
 

  1. SaveSubscription failed with:...   Reply   Report abuse  
Picture of Sagar jain Sagar jain - 2020-10-15 05:17:40
SaveSubscription failed with: SyntaxError: Unexpected token < in JSON at position 0

  2. Re: SaveSubscription failed with:...   Reply   Report abuse  
Picture of Stefan Kientzler Stefan Kientzler - 2020-10-15 12:18:29 - In reply to message 1 from Sagar jain
Please give a more detailed description of the problem.

Obviously, the result of the HTTP request from the ServiceWorker (PNServiceWorker.js) to PNSubscriber.php is not a correctly formatted JSON string, but initially contains an HTML part, which presumably originates from a PHP-error, -warning or -notification.
In order to narrow down the source of the error, PNSubscriber.php has to be examined more closely, which I cannot do without detailed information from here.


  3. Re: SaveSubscription failed with:...   Reply   Report abuse  
Picture of Sagar jain Sagar jain - 2020-10-20 09:55:13 - In reply to message 2 from Stefan Kientzler
PNsubscriber.php

<?php
require_once 'autoloader.php';
require_once 'PNSendWelcome.php';
require_once 'MyLogger.php';

use SKien\PNServer\PNDataProviderSQLite;
use SKien\PNServer\PNSubscription;

/**
* Example to handle the HTTP-Request send from the ServiceWorker to
* subscribe our notification service.
*
* For easy setup we use the SQLite dataprovider and set the database file
* located in the same directory as this script.
* You may use the MySQL dataprovider, just locate the database in a differnet
* directory or write your own dataprovider for your project.
*
* Remember to adjust the path and name of the script in the service worker
* (PNServiceWorker.js) when implementing the requesthandler in your own project.
*
* Set $bSendWelcome=true, to send a welcome notification to each user
* newly subscribed our service, after the subscription was saved in
* the database.
*
* If you want to log several events or errors, you can pass any PSR-3 compliant
* logger of your choice to the dataprovider.
*
* THIS CODE IS INTENDED ONLY AS EXAMPLE - DONT USE IT DIRECT IN YOU PROJECT
*
* @author Stefanius <s.kien@online.de>
* @copyright MIT License - see the LICENSE file for details
*/

// set to true, if you will send songle welcome notification to each new subscription
$bSendWelcome = true;

$result = array();
// only serve POST request containing valid json data
if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
if (isset($_SERVER['CONTENT_TYPE']) && trim(strtolower($_SERVER['CONTENT_TYPE']) == 'application/json')) {
// get posted json data
if (($strJSON = trim(file_get_contents('php://input'))) === false) {
$result['msg'] = 'invalid JSON data!';
} else {
// create any PSR-3 logger of your choice in MyLogger.php
$oDP = new PNDataProviderSQLite(null, null, null, createLogger());
if ($oDP->saveSubscription($strJSON) !== false) {
$result['msg'] = 'subscription saved on server!';
if ($bSendWelcome) {
sendWelcome(PNSubscription::fromJSON($strJSON));
}
} else {
$result['msg'] = 'error saving subscription!';
}
}
} else {
$result['msg'] = 'invalid content type!';
}
} else {
$result['msg'] = 'no post request!';
}
// let the service-worker know the result
echo json_encode($result);

  4. Re: SaveSubscription failed with:...   Reply   Report abuse  
Picture of Sagar jain Sagar jain - 2020-10-20 09:56:28 - In reply to message 2 from Stefan Kientzler
PNServiceWorker.js

/**
* Serviceworker for web push notifications
* @package PNServer
*/

// values to be modified for own project
// VAPID appPublic key
const strAppPublicKey = 'BKyNMt9rSHMvsmxXSsaU21sx4QtJgKUuGTsNG68oUf2ciZo1O88vk7_MZeIJ9rZRNYeAWikRjC_pbGOD5ZXC6Uc';
// URL to save subscription on server via Fetch API
//const strSubscriberURL = 'https://test-abroad.ubuy.com.kw/testpush/PNSubscriber.php';
const strSubscriberURL = 'http://localhost/testpush/PNSubscriber.php';
// default Notification Title if not pushed by server
const strDefTitle = 'Test';
// default Notification Icon if not pushed by server
const strDefIcon = './elephpant.png';

/**
* encode the public key to Array buffer
* @param {string} strBase64 - key to encode
* @return {Array} - UInt8Array
*/
function encodeToUint8Array(strBase64) {
var strPadding = '='.repeat((4 - (strBase64.length % 4)) % 4);
var strBase64 = (strBase64 + strPadding).replace(/\-/g, '+').replace(/_/g, '/');
var rawData = atob(strBase64);
var aOutput = new Uint8Array(rawData.length);
for (i = 0; i < rawData.length; ++i) {
aOutput[i] = rawData.charCodeAt(i);
}
return aOutput;
}

/**
* event listener to subscribe notifications and save subscription at server
* @param {ExtendableEvent} event
*/
async function pnSubscribe(event) {
console.log('Serviceworker: activate event');
try {
var appPublicKey = encodeToUint8Array(strAppPublicKey);
var opt = {
applicationServerKey: appPublicKey,
userVisibleOnly: true
};

self.registration.pushManager.subscribe(opt)
.then((sub) => {
// subscription succeeded - send to server
pnSaveSubscription(sub)
.then((response) => {
console.log(response);
}).catch((e) => {
// registration failed
console.log('SaveSubscription failed with: ' + e);
});
}, ).catch((e) => {
// registration failed
console.log('Subscription failed with: ' + e);
});

} catch (e) {
console.log('Error subscribing notifications: ' + e);
}
}

/**
* event listener handling when subscription change
* just re-subscribe
* @param {PushSubscriptionChangeEvent} event
*/
async function pnSubscriptionChange(event) {
console.log('Serviceworker: subscription change event: ' + event);
try {
// re-subscribe with old options
self.registration.pushManager.subscribe(event.oldSubscription.options)
.then((sub) => {
// subscription succeeded - send to server
pnSaveSubscription(sub)
.then((response) => {
console.log(response);
}).catch((e) => {
// registration failed
console.log('SaveSubscription failed with: ' + e);
});
}, ).catch((e) => {
// registration failed
console.log('Subscription failed with: ' + e);
});

} catch (e) {
console.log('Error subscribing notifications: ' + e);
}
}

/**
* save subscription on server
* using Fetch API to send subscription infos to the server
* subscription is encance with the userAgent for internal use on the server
* @param {object} sub - PushSubscription
* @return {string} - response of the request
*/
async function pnSaveSubscription(sub) {
// stringify and parse again to add 'custom' property
// ... otherwise added property will be ignored when stringify subscription direct to body!
var body = JSON.parse(JSON.stringify(sub));
body.userAgent = navigator.userAgent;
var fetchdata = {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
};
// we're using fetch() to post the data to the server
var response = await fetch(strSubscriberURL, fetchdata);
return response.json();
}

/**
* event listener to show notification
* @param {PushEvent} event
*/
function pnPushNotification(event) {
console.log('push event: ' + event);
var strTitle = strDefTitle;
var oPayload = null;
var opt = { icon: strDefIcon };
if (event.data) {
// PushMessageData Object containing the pushed payload
try {
// try to parse payload JSON-string
oPayload = JSON.parse(event.data.text());
} catch (e) {
// if no valid JSON Data take text as it is...
// ... comes maybe while testing directly from DevTools
opt = {
icon: strDefIcon,
body: event.data.text(),
};
}
if (oPayload) {
if (oPayload.title != undefined && oPayload.title != '') {
strTitle = oPayload.title;
}
opt = oPayload.opt;
if (oPayload.opt.icon == undefined ||
oPayload.opt.icon == null ||
oPayload.icon == '') {
// if no icon defined, use default
opt.icon = strDefIcon;
}
}
}
var promise = self.registration.showNotification(strTitle, opt);
event.waitUntil(promise);
}

/**
* event listener to notification click
* if URL passed, just open the window...
* @param {NotificationClick} event
*/
function pnNotificationClick(event) {
console.log('notificationclick event: ' + event);
if (event.notification.data && event.notification.data.url) {
const promise = clients.openWindow(event.notification.data.url);
event.waitUntil(promise);
}
if (event.action != "") {
// add handler for user defined action here...
// pnNotificationAction(event.action);
console.log('notificationclick action: ' + event.action);
}
}

/**
* event listener to notification close
* ... if you want to do something for e.g. analytics
* @param {NotificationClose} event
*/
function pnNotificationClose(event) {
console.log('notificationclose event: ' + event);
}

/**=========================================================
* add all needed event-listeners
* - activate: subscribe notifications and send to server
* - push: show push notification
* - click: handle click an notification and/or action
* button
* - change: subscription has changed
* - close: notification was closed by the user
*=========================================================*/
// add event listener to subscribe and send subscription to server
self.addEventListener('activate', pnSubscribe);
// and listen to incomming push notifications
self.addEventListener('push', pnPushNotification);
// ... and listen to the click
self.addEventListener('notificationclick', pnNotificationClick);
// subscription has changed
self.addEventListener('pushsubscriptionchange', pnSubscriptionChange);
// notification was closed without further action
self.addEventListener('notificationclose', pnNotificationClose);

  5. Re: SaveSubscription failed with:...   Reply   Report abuse  
Picture of Stefan Kientzler Stefan Kientzler - 2020-10-20 14:07:33 - In reply to message 4 from Sagar jain
Hello Sagar,
Posting the whole source code doesn't really help me - I know that code ... if you post code, please only lines of code that you have changed, as it is extremely difficult for me to see anything in the unformatted code in the message ;-)

what I see of your changes is on PNServiceWorker.js, line 11:

strSubscriberURL = 'http: //localhost/testpush/PNSubscriber.php';

that you are working on your localhost, which cannot work because the entire notification mechanism only works in a secure context (https://).

However, as I wrote in my first answer, this is not your current problem.
Inside the PHP code of PNSubscriber.php there must be an Error/Warning/Notice, which means that no correct JSON is returned as response.

Please make the following changes in PNServiceworker.js from line 111:

var response = await fetch(strSubscriberURL, fetchdata);
var cloned = response.clone();
console.log('Response: ', await cloned.text());
return await response.json();


After that you have to test everything on your real (https) server:
- Open PNTestClient.html and also the console.
- Deregister the 'old' service worker using the [unregister Service Worker] button
- Reload the page with [F5]
- Now run the registration again.

The complete response text containing the PHP error should now be displayed in the console - further troubleshooting results from this message!

regards Stefan

  6. Re: SaveSubscription failed with:...   Reply   Report abuse  
Picture of Matthias Lehmann Matthias Lehmann - 2023-03-05 14:06:55 - In reply to message 5 from Stefan Kientzler
I had the same problem and did what you requested ("Please make the following changes in PNServiceworker.js from line 111:..."). The console gave me the following: "Response: <br />
<b>Parse error</b>: syntax error, unexpected 'string' (T_STRING), expecting variable (T_VARIABLE) in <b>/var/[..]/SKien/PNServer/PNDataProviderSQLite.php</b> on line <b>24</b><br />"

I haven't had changed anything in PNDataProviderSQLite.php

  7. Re: SaveSubscription failed with:...   Reply   Report abuse  
Picture of Stefan Kientzler Stefan Kientzler - 2023-03-05 16:32:28 - In reply to message 6 from Matthias Lehmann
Hi Matthias - obviously you are working with an old PHP version that does not yet support type hinting for class properties (so the type hinting on the data type 'string' leads to the corresponding PHP error message you get).

The entire package requires PHP version 7.4 as stated in the readme file!

  8. Re: SaveSubscription failed with:...   Reply   Report abuse  
Picture of Matthias Lehmann Matthias Lehmann - 2023-03-05 17:56:53 - In reply to message 7 from Stefan Kientzler
This is it. Thank you so much. I would have never get this on my own.