Skip to content

Commit 761a9d2

Browse files
committed
Merge remote-tracking branch 'origin/payload' into payload
2 parents 33453af + c6e2360 commit 761a9d2

File tree

4 files changed

+175
-115
lines changed

4 files changed

+175
-115
lines changed

README.md

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,42 @@ As it is standardized, you don't have to worry about what server type it relies
1414

1515
use Minishlink\WebPush\WebPush;
1616

17-
// array of endpoints
18-
$endpoints = array(
19-
'https://updates.push.services.mozilla.com/push/abc...', // Firefox 43+
20-
'https://updates.push.services.mozilla.com/push/def...',
21-
'https://example.com/other/endpoint/of/another/vendor/abc...',
22-
'https://example.com/other/endpoint/of/another/vendor/abc...',
23-
);
24-
25-
// array of payloads which are strings or null (json_encode your arrays)
26-
$payloads = array(
27-
'hello !',
28-
'{"msg":"test"}',
29-
null,
30-
'',
31-
);
32-
33-
// array of the public keys of each users
34-
$userPublicKeys = array(
35-
'thePublicKeysCorrespondingToFirstEndpoint',
36-
'thePublicKeysCorrespondingToSecondEndpoint',
37-
'thePublicKeysCorrespondingToThirdEndpoint',
38-
'thePublicKeysCorrespondingToFourthEndpoint',
17+
// array of notifications
18+
$notifications = array(
19+
array(
20+
'endpoint' => 'https://updates.push.services.mozilla.com/push/abc...', // Firefox 43+
21+
'payload' => 'hello !',
22+
'userPublicKey' => 'dahaj5365sq',
23+
), array(
24+
'endpoint' => 'https://android.googleapis.com/gcm/send/abcdef...', // Chrome
25+
'payload' => null,
26+
'userPublicKey' => null,
27+
), array(
28+
'endpoint' => 'https://example.com/other/endpoint/of/another/vendor/abcdef...',
29+
'payload' => '{"msg":"test"}',
30+
'userPublicKey' => 'fsqdjknadsanlk',
31+
),
3932
);
4033

4134
$webPush = new WebPush();
42-
$webPush->sendNotification($endpoints[0]); // send one notification without payload
43-
$webPush->sendNotifications($endpoints); // send multiple notifications without payloads
4435

45-
$webPush->sendNotification($endpoints[0], $payloads[0], $userPublicKeys[0]); // send one notification with payload
46-
$webPush->sendNotifications($endpoints, $payloads, $userPublicKeys); // send multiple notifications with payloads
36+
// send multiple notifications with payload
37+
foreach ($notifications as $notification) {
38+
$webPush->sendNotification(
39+
$notification['endpoint'],
40+
$notification['payload'], // optional (defaults null)
41+
$notification['userPublicKey'] // optional (defaults null)
42+
);
43+
}
44+
$webPush->flush();
45+
46+
// send one notification and flush directly
47+
$webPush->sendNotification(
48+
$notifications[0]['endpoint'],
49+
$notifications[0]['payload'], // optional (defaults null)
50+
$notifications[0]['userPublicKey'], // optional (defaults null)
51+
true // optional (defaults false)
52+
);
4753
```
4854

4955
### GCM servers notes (Chrome)
@@ -64,7 +70,7 @@ $apiKeys = array(
6470
);
6571

6672
$webPush = new WebPush($apiKeys);
67-
$webPush->sendNotification($endpoint);
73+
$webPush->sendNotification($endpoint, null, null, true);
6874
```
6975

7076
### Changing the browser client
@@ -96,6 +102,13 @@ $browser = $webPush->getBrowser();
96102

97103
## Common questions
98104

105+
### Is there any plugin/bundle/extension for my favorite PHP framework?
106+
The following are available:
107+
108+
- Symfony: [MinishlinkWebPushBundle](https://github.com/Minishlink/web-push-bundle)
109+
110+
Feel free to add your own!
111+
99112
### Is the API stable?
100113
Not until the [Push API spec](http://www.w3.org/TR/push-api/) is finished.
101114

src/Notification.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the WebPush library.
5+
*
6+
* (c) Louis Lagrange <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Minishlink\WebPush;
13+
14+
class Notification
15+
{
16+
/** @var string */
17+
private $endpoint;
18+
19+
/** @var string|null */
20+
private $payload;
21+
22+
/** @var string|null Base64 encoded */
23+
private $userPublicKey;
24+
25+
public function __construct($endpoint, $payload, $userPublicKey)
26+
{
27+
$this->endpoint = $endpoint;
28+
$this->payload = $payload;
29+
$this->userPublicKey = $userPublicKey;
30+
}
31+
32+
/**
33+
* @return string
34+
*/
35+
public function getEndpoint()
36+
{
37+
return $this->endpoint;
38+
}
39+
40+
/**
41+
* @return null|string
42+
*/
43+
public function getPayload()
44+
{
45+
return $this->payload;
46+
}
47+
48+
/**
49+
* @return null|string
50+
*/
51+
public function getUserPublicKey()
52+
{
53+
return $this->userPublicKey;
54+
}
55+
}

src/WebPush.php

Lines changed: 64 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ class WebPush
2828
/** @var array Key is push server type and value is the API key */
2929
protected $apiKeys;
3030

31+
/** @var array Array of array of Notifications by server type */
32+
private $notificationsByServerType;
33+
34+
/** @var array Array of not standard endpoint sources */
35+
private $urlByServerType = array(
36+
'GCM' => 'https://android.googleapis.com/gcm/send',
37+
);
38+
3139
/**
3240
* WebPush constructor.
3341
*
@@ -48,57 +56,56 @@ public function __construct(array $apiKeys = array(), $TTL = null, $timeout = nu
4856
}
4957

5058
/**
51-
* Send one notification.
59+
* Send a notification.
5260
*
5361
* @param string $endpoint
54-
* @param string|null $payload If you want to send an array, json_encode it.
62+
* @param string|null $payload If you want to send an array, json_encode it.
5563
* @param string|null $userPublicKey
64+
* @param bool $flush If you want to flush directly (usually when you send only one notification)
5665
*
57-
* @return array
58-
*
66+
* @return bool|array Return an array of information if $flush is set to true and the request has failed. Else return true.
5967
* @throws \ErrorException
6068
*/
61-
public function sendNotification($endpoint, $payload = null, $userPublicKey = null)
69+
public function sendNotification($endpoint, $payload = null, $userPublicKey = null, $flush = false)
6270
{
63-
$endpoints = array($endpoint);
64-
$payloads = isset($payload) ? array($payload) : null;
65-
$userPublicKeys = isset($userPublicKey) ? array($userPublicKey) : null;
71+
// sort notification by server type
72+
$type = $this->sortEndpoint($endpoint);
73+
$this->notificationsByServerType[$type][] = new Notification($endpoint, $payload, $userPublicKey);
6674

67-
return $this->sendNotifications($endpoints, $payloads, $userPublicKeys);
75+
if ($flush) {
76+
$res = $this->flush();
77+
return is_array($res) ? $res[0] : true;
78+
}
79+
80+
return true;
6881
}
6982

7083
/**
71-
* Send multiple notifications.
72-
*
73-
* @param array $endpoints
74-
* @param array|null $payloads
75-
* @param array|null $userPublicKeys
84+
* Flush notifications. Triggers the requests.
7685
*
77-
* @return array
86+
* @return array|bool If there are no errors, return true.
87+
* Else return an array of information for each notification sent (success, statusCode, headers).
7888
*
7989
* @throws \ErrorException
8090
*/
81-
public function sendNotifications(array $endpoints, array $payloads = null, array $userPublicKeys = null)
91+
public function flush()
8292
{
83-
// sort endpoints by server type
84-
$endpointsByServerType = $this->sortEndpoints($endpoints);
85-
86-
// if GCM we should check for the API key
87-
if (array_key_exists('GCM', $endpointsByServerType)) {
93+
// if GCM is present, we should check for the API key
94+
if (array_key_exists('GCM', $this->notificationsByServerType)) {
8895
if (empty($this->apiKeys['GCM'])) {
8996
throw new \ErrorException('No GCM API Key specified.');
9097
}
9198
}
9299

93100
// for each endpoint server type
94101
$responses = array();
95-
foreach ($endpointsByServerType as $serverType => $endpoints) {
102+
foreach ($this->notificationsByServerType as $serverType => $notifications) {
96103
switch ($serverType) {
97104
case 'GCM':
98-
$responses += $this->sendToGCMEndpoints($endpoints);
105+
$responses += $this->sendToGCMEndpoints($notifications);
99106
break;
100107
case 'standard':
101-
$responses += $this->sendToStandardEndpoints($endpoints, $payloads, $userPublicKeys);
108+
$responses += $this->sendToStandardEndpoints($notifications);
102109
break;
103110
}
104111
}
@@ -111,23 +118,31 @@ public function sendNotifications(array $endpoints, array $payloads = null, arra
111118
}
112119

113120
/** @var Response|null $response */
121+
$return = array();
122+
$completeSuccess = true;
114123
foreach ($responses as $response) {
115124
if (!isset($response)) {
116-
return array(
125+
$return[] = array(
117126
'success' => false,
118127
);
128+
129+
$completeSuccess = false;
119130
} elseif (!$response->isSuccessful()) {
120-
return array(
131+
$return[] = array(
121132
'success' => false,
122133
'statusCode' => $response->getStatusCode(),
123134
'headers' => $response->getHeaders(),
124135
);
136+
137+
$completeSuccess = false;
138+
} else {
139+
$return[] = array(
140+
'success' => true,
141+
);
125142
}
126143
}
127144

128-
return array(
129-
'success' => true,
130-
);
145+
return $completeSuccess ? true : $return;
131146
}
132147

133148
/**
@@ -172,23 +187,16 @@ private function encrypt($userPublicKey, $payload)
172187
);
173188
}
174189

175-
/**
176-
* @param array $endpoints
177-
* @param array|null $payloads
178-
* @param array|null $userPublicKeys
179-
*
180-
* @return array
181-
*
182-
* @throws \ErrorException
183-
*/
184-
private function sendToStandardEndpoints(array $endpoints, array $payloads = null, array $userPublicKeys = null)
190+
private function sendToStandardEndpoints(array $notifications)
185191
{
186192
$responses = array();
187-
foreach ($endpoints as $i => $endpoint) {
188-
$payload = $payloads[$i];
193+
/** @var Notification $notification */
194+
foreach ($notifications as $notification) {
195+
$payload = $notification->getPayload();
196+
$userPublicKey = $notification->getUserPublicKey();
189197

190-
if (isset($payload)) {
191-
$encrypted = $this->encrypt($userPublicKeys[$i], $payload);
198+
if (isset($payload) && isset($userPublicKey)) {
199+
$encrypted = $this->encrypt($userPublicKey, $payload);
192200

193201
$headers = array(
194202
'Content-Length' => strlen($encrypted['cipherText']),
@@ -211,29 +219,25 @@ private function sendToStandardEndpoints(array $endpoints, array $payloads = nul
211219
$headers['TTL'] = $this->TTL;
212220
}
213221

214-
$responses[] = $this->sendRequest($endpoint, $headers, $content);
222+
$responses[] = $this->sendRequest($notification->getEndpoint(), $headers, $content);
215223
}
216224

217225
return $responses;
218226
}
219227

220-
/**
221-
* @param array $endpoints
222-
*
223-
* @return array
224-
*/
225-
private function sendToGCMEndpoints(array $endpoints)
228+
private function sendToGCMEndpoints(array $notifications)
226229
{
227230
$maxBatchSubscriptionIds = 1000;
228-
$url = 'https://android.googleapis.com/gcm/send';
231+
$url = $this->urlByServerType['GCM'];
229232

230233
$headers['Authorization'] = 'key='.$this->apiKeys['GCM'];
231234
$headers['Content-Type'] = 'application/json';
232235

233236
$subscriptionIds = array();
234-
foreach ($endpoints as $endpoint) {
237+
/** @var Notification $notification */
238+
foreach ($notifications as $notification) {
235239
// get all subscriptions ids
236-
$endpointsSections = explode('/', $endpoint);
240+
$endpointsSections = explode('/', $notification->getEndpoint());
237241
$subscriptionIds[] = $endpointsSections[count($endpointsSections) - 1];
238242
}
239243

@@ -273,35 +277,19 @@ private function sendRequest($url, array $headers, $content)
273277
}
274278

275279
/**
276-
* @param array $endpoints
280+
* @param string $endpoint
277281
*
278-
* @return array
282+
* @return string
279283
*/
280-
private function sortEndpoints(array $endpoints)
284+
private function sortEndpoint($endpoint)
281285
{
282-
$sortedEndpoints = array();
283-
284-
$serverTypesByUrl = array(
285-
'GCM' => 'https://android.googleapis.com/gcm/send',
286-
);
287-
288-
foreach ($endpoints as $endpoint) {
289-
$standard = true;
290-
291-
foreach ($serverTypesByUrl as $type => $url) {
292-
if (substr($endpoint, 0, strlen($url)) === $url) {
293-
$sortedEndpoints[$type][] = $endpoint;
294-
$standard = false;
295-
break;
296-
}
297-
}
298-
299-
if ($standard) {
300-
$sortedEndpoints['standard'][] = $endpoint;
286+
foreach ($this->urlByServerType as $type => $url) {
287+
if (substr($endpoint, 0, strlen($url)) === $url) {
288+
return $type;
301289
}
302290
}
303291

304-
return $sortedEndpoints;
292+
return 'standard';
305293
}
306294

307295
/**

0 commit comments

Comments
 (0)