From d98b7f3efe9416db8b5fbe71eaf616c554c5c963 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 00:03:54 -0800 Subject: [PATCH 01/62] Add files via upload --- library/CodeMonkeysRu/GCM/Exception.php | 30 ++++- library/CodeMonkeysRu/GCM/Message.php | 27 ++++- library/CodeMonkeysRu/GCM/Response.php | 151 ++++++++++++++++++++++-- library/CodeMonkeysRu/GCM/Sender.php | 100 +++++++++++----- 4 files changed, 266 insertions(+), 42 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Exception.php b/library/CodeMonkeysRu/GCM/Exception.php index 6611539..daa2423 100644 --- a/library/CodeMonkeysRu/GCM/Exception.php +++ b/library/CodeMonkeysRu/GCM/Exception.php @@ -9,5 +9,33 @@ class Exception extends \Exception const MALFORMED_REQUEST = 3; const UNKNOWN_ERROR = 4; const MALFORMED_RESPONSE = 5; + const INTERNAL_SERVER_ERROR = 6; + const SERVICE_UNAVAILABLE = 7; + const INVALID_DATA_KEY = 8; //payload uses a data key used by GCM + const CURL_ERROR = 9; + + // mismatch sender id (wrong sender id in app), DeviceMessageRateExceeded handled case-by-case. -} \ No newline at end of file +} + +/* +Copyright (c) 2014 Vladimir Savenkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ diff --git a/library/CodeMonkeysRu/GCM/Message.php b/library/CodeMonkeysRu/GCM/Message.php index d8bdc60..c237b06 100644 --- a/library/CodeMonkeysRu/GCM/Message.php +++ b/library/CodeMonkeysRu/GCM/Message.php @@ -54,7 +54,7 @@ class Message * @var array|null */ private $notification = null; - + /** * Indicates that the message should not be sent immediately if the device is idle. * The server will wait for the device to become active, and then only the last message @@ -156,7 +156,7 @@ public function setData($data) $this->data = $data; return $this; } - + public function getNotification() { return $this->notification; @@ -222,4 +222,25 @@ public function setContentAvailable($contentAvailable) $this->contentAvailable = $contentAvailable; return $this; } -} \ No newline at end of file +} +/* +Copyright (c) 2014 Vladimir Savenkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 208c95e..ca5c159 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -1,9 +1,6 @@ - */ class Response { @@ -34,6 +31,12 @@ class Response * @var integer */ private $canonicalIds = null; + + //raw response. + private $responseBody = null; + + //response headers. + private $responseHeaders = null; /** * Array of objects representing the status of the messages processed. @@ -53,22 +56,34 @@ class Response */ private $results = array(); - public function __construct(Message $message, $responseBody) + public function __construct(Message $message, $responseBody, $responseHeaders) { + $this->responseBody = $responseBody; + $this->responseHeaders = $responseHeaders; + $data = \json_decode($responseBody, true); if ($data === null) { - throw new Exception("Malformed reponse body. ".$responseBody, Exception::MALFORMED_RESPONSE); + throw new Exception("Malformed reponse body. ". $responseBody, Exception::MALFORMED_RESPONSE); } $this->multicastId = $data['multicast_id']; $this->failure = $data['failure']; $this->success = $data['success']; $this->canonicalIds = $data['canonical_ids']; $this->results = array(); + foreach ($message->getRegistrationIds() as $key => $registrationId) { $this->results[$registrationId] = $data['results'][$key]; } } - + + public function getRawResponse() { + return $this->responseBody; + } + + public function getResponseHeadersArray() { + return $this->responseHeaders; + } + public function getMulticastId() { return $this->multicastId; @@ -78,8 +93,13 @@ public function getSuccessCount() { return $this->success; } - - public function getFailureCount() + + public function getTotallyNormalCount() + { + return($this->success - $this->canonicalIds); + } + + public function getFailureCount() //both implementation errors and server errors are included here. { return $this->failure; } @@ -88,12 +108,31 @@ public function getNewRegistrationIdsCount() { return $this->canonicalIds; } + + public function isTotallyNormal() + { + return (($this->getNewRegistrationIdsCount() == 0) && ($this->getFailureCount() == 0)); + } public function getResults() { return $this->results; } + + /** + * Return a numeric array of registration ids which worked without any error or need to update. + */ + + public function getAsWrittenIds() + { + $filteredResults = array_filter($this->results, + function($result) { + return isset($result['message_id']) && !isset($result['registration_id']); + }); + return array_keys($filteredResults); + } + /** * Return an array of expired registration ids linked to new id * All old registration ids must be updated to new ones in DB @@ -116,6 +155,12 @@ function($result) { return $data; } + + public function someIdsNew() + { + $bool = (count($this->getNewRegistrationIds()) != 0); + return $bool; + } /** * Returns an array containing invalid registration ids @@ -136,7 +181,9 @@ function($result) { ( ($result['error'] == "NotRegistered") || - ($result['error'] == "InvalidRegistration") + ($result['error'] == "InvalidRegistration") + || + ($result['error'] == "DeviceMessageRateExceeded") ) ); }); @@ -144,6 +191,12 @@ function($result) { return array_keys($filteredResults); } + public function someIdsInvalid() + { + $bool = (count($this->getInvalidRegistrationIds()) != 0); + return $bool; + } + /** * Returns an array of registration ids for which you must resend a message (?), * cause devices aren't available now. @@ -162,11 +215,89 @@ function($result) { return ( isset($result['error']) && + ( ($result['error'] == "Unavailable") + || + ($result['error'] == "InternalServerError") + ) ); }); return array_keys($filteredResults); } + + public function someIdsUnavailable() { + $bool = (count($this->getUnavailableRegistrationIds()) != 0); + return $bool; + } + + //invalid data key + + public function getInvalidDataKeysIds() { + if ($this->getFailureCount() == 0) { + return array(); + } + $filteredResults = array_filter($this->results, + function($result) { + return ( + isset($result['error']) + && + ($result['error'] == "InvalidDataKey") + ); + }); + + return array_keys($filteredResults); + + } + + public function existsInvalidDataKey() { + $bool = (count($this->getInvalidDataKeysIds()) != 0); + return $bool; + } + + //mismatch sender id + + public function getMismatchSenderIdIds() { + if ($this->getFailureCount() == 0) { + return array(); + } + $filteredResults = array_filter($this->results, + function($result) { + return ( + isset($result['error']) + && + ($result['error'] == "MismatchSenderId") + ); + }); + + return array_keys($filteredResults); + } + + public function existsMismatchSenderId() { + $bool = (count($this->getMismatchSenderIdIds()) != 0); + return $bool; + } + +} + +/* +Copyright (c) 2014 Vladimir Savenkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -} \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index 0a0e466..f0bad27 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -76,7 +76,7 @@ public function send(Message $message) if (count($message->getRegistrationIds()) > 1000) { throw new Exception("Malformed request: Registration Ids exceed the GCM imposed limit of 1000", Exception::MALFORMED_REQUEST); } - + $rawData = $this->formMessageData($message); $this->validatePayloadSize($rawData, 'data', 4096); $this->validatePayloadSize($rawData, 'notification', 2048); @@ -94,41 +94,64 @@ public function send(Message $message) curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - + + curl_setopt($ch, CURLOPT_HEADER, 1); // return HTTP headers with response + + if ($this->caInfoPath !== false) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_CAINFO, $this->caInfoPath); } else { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - + + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); - $resultBody = curl_exec($ch); + $resp = curl_exec($ch); + + if ($resp === FALSE) { + throw new Exception('cURL error: '. curl_error($ch), Exception::CURL_ERROR); + + } + + list($responseHeaders, $resultBody) = explode("\r\n\r\n", $resp, 2); + // $headers now has a string of the HTTP headers + // $resultBody is the body of the HTTP response + + $responseHeaders = explode("\n", $responseHeaders); + $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); - - switch ($resultHttpCode) { - case "200": - //All fine. Continue response processing. - break; - - case "400": - throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); - break; - - case "401": - throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); - break; - - default: - //TODO: Retry-after - throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); - break; + + if ($resultHttpCode == "200") { + ;//check for errors wrt individual devices later with the Response object. } - - return new Response($message, $resultBody); + + elseif ($resultHttpCode == "400") { + throw new Exception('Malformed request. '. $resultBody, Exception::MALFORMED_REQUEST); + } + + elseif ($resultHttpCode == "401") { + throw new Exception('Authentication Error. '. $resultBody, Exception::AUTHENTICATION_ERROR); + } + + elseif ($resultHttpCode == "500") { + throw new Exception('Internal Server Error. ' . $resultBody, Exception::INTERNAL_SERVER_ERROR); + } + + elseif ((600 > (int) $resultHttpCode) && ((int) $resultHttpCode > 500)) { + throw new Exception('Service Unavailable. ' . $resultBody, Exception::SERVICE_UNAVAILABLE); + } + + else { + throw new Exception("Unknown error. ". $resultBody, Exception::UNKNOWN_ERROR); + } + + + + return new Response($message, $resultBody, $responseHeaders); } /** @@ -147,12 +170,12 @@ private function formMessageData(Message $message) 'registration_ids' => 'getRegistrationIds', 'collapse_key' => 'getCollapseKey', 'data' => 'getData', - 'notification' => 'getNotification', + 'notification' => 'getNotification', 'delay_while_idle' => 'getDelayWhileIdle', 'time_to_live' => 'getTtl', 'restricted_package_name' => 'getRestrictedPackageName', 'dry_run' => 'getDryRun', - 'content_available' => 'getContentAvailable', + 'content_available' => 'getContentAvailable' ); foreach ($dataFields as $fieldName => $getter) { @@ -163,7 +186,7 @@ private function formMessageData(Message $message) return $data; } - + /** * Validate size of json representation of passed payload * @@ -183,5 +206,26 @@ private function validatePayloadSize(array $rawData, $fieldName, $maxSize) ); } } - } + +/* +Copyright (c) 2014 Vladimir Savenkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ From 8a5f0f50d64d440e4c893149a471837bd23fdde0 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 00:53:42 -0800 Subject: [PATCH 02/62] Update README.md --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/README.md b/README.md index a49741b..1342a2d 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,12 @@ $message try { $response = $sender->send($message); + if ($response->getMustRetry() { + $waitSeconds = $response->getWaitSeconds(); + //Try again after that many seconds, and use exponential backoff subsequently, as needed. + //TODO + } + if ($response->getNewRegistrationIdsCount() > 0) { $newRegistrationIds = $response->getNewRegistrationIds(); foreach ($newRegistrationIds as $oldRegistrationId => $newRegistrationId){ @@ -40,6 +46,19 @@ try { } if ($response->getFailureCount() > 0) { + + if ($response->existsInvalidDataKey()) { + //You used a reserved data key + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + throw new Exception($error_msg, Exception::INVALID_DATA_KEY); + } + + if ($response->existsMismatchSenderId()) { + //A client sent the wrong senderId when it registered for pushes + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); + throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); + } + $invalidRegistrationIds = $GCMresponse->getInvalidRegistrationIds(); foreach($invalidRegistrationIds as $invalidRegistrationId) { //Remove $invalidRegistrationId from DB @@ -48,6 +67,7 @@ try { //Schedule to resend messages to unavailable devices $unavailableIds = $response->getUnavailableRegistrationIds(); + //Suggestion: try again, using exponential back-off. Or put in a queue and use a cronjob. //TODO } } catch (GCM\Exception $e) { @@ -58,6 +78,11 @@ try { case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: + case GCM\Exception::INTERNAL_SERVER_ERROR: //gcm server problem + case GCM\Exception::SERVICE_UNAVAILABLE: //gcm server problem + case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification + case GCM\Exception::CURL_ERROR: //problem posting to gcm server + case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes //Deal with it break; } @@ -80,6 +105,12 @@ try { "collapse_key" ); + if ($response->getMustRetry() { + $waitSeconds = $response->getWaitSeconds(); + //Try again after that many seconds, and use exponential backoff subsequently, as needed. + //TODO + } + if ($response->getNewRegistrationIdsCount() > 0) { $newRegistrationIds = $response->getNewRegistrationIds(); foreach ($newRegistrationIds as $oldRegistrationId => $newRegistrationId){ @@ -89,6 +120,19 @@ try { } if ($response->getFailureCount() > 0) { + + if ($response->existsInvalidDataKey()) { + //You used a reserved data key + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + throw new Exception($error_msg, Exception::INVALID_DATA_KEY); + } + + if ($response->existsMismatchSenderId()) { + //A client sent the wrong senderId when it registered for pushes + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); + throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); + } + $invalidRegistrationIds = $GCMresponse->getInvalidRegistrationIds(); foreach($invalidRegistrationIds as $invalidRegistrationId) { //Remove $invalidRegistrationId from DB @@ -97,6 +141,7 @@ try { //Schedule to resend messages to unavailable devices $unavailableIds = $response->getUnavailableRegistrationIds(); + //Suggestion: try again, using exponential back-off. Or put in a queue and use a cronjob. //TODO } } catch (GCM\Exception $e) { @@ -107,6 +152,11 @@ try { case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: + case GCM\Exception::INTERNAL_SERVER_ERROR: //gcm server problem + case GCM\Exception::SERVICE_UNAVAILABLE: //gcm server problem + case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification + case GCM\Exception::CURL_ERROR: //problem posting to gcm server + case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes //Deal with it break; } From f0b18bf90c0a93cde0d176ca1d3214800933c539 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 00:55:11 -0800 Subject: [PATCH 03/62] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1342a2d..6420f4a 100644 --- a/README.md +++ b/README.md @@ -49,13 +49,13 @@ try { if ($response->existsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->existsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } @@ -123,13 +123,13 @@ try { if ($response->existsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->existsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } From da554d7569a00400de2715998c72020bd4760e96 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 01:14:27 -0800 Subject: [PATCH 04/62] Add files via upload --- library/CodeMonkeysRu/GCM/Exception.php | 6 ++-- library/CodeMonkeysRu/GCM/Response.php | 48 +++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Exception.php b/library/CodeMonkeysRu/GCM/Exception.php index daa2423..89fe987 100644 --- a/library/CodeMonkeysRu/GCM/Exception.php +++ b/library/CodeMonkeysRu/GCM/Exception.php @@ -11,11 +11,9 @@ class Exception extends \Exception const MALFORMED_RESPONSE = 5; const INTERNAL_SERVER_ERROR = 6; const SERVICE_UNAVAILABLE = 7; - const INVALID_DATA_KEY = 8; //payload uses a data key used by GCM + const INVALID_DATA_KEY = 8; const CURL_ERROR = 9; - - // mismatch sender id (wrong sender id in app), DeviceMessageRateExceeded handled case-by-case. - + const MISMATCH_SENDER_ID = 10; } /* diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index ca5c159..517981f 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -32,11 +32,33 @@ class Response */ private $canonicalIds = null; - //raw response. + /** + * Raw response. + * + * @var string + */ private $responseBody = null; - //response headers. + /** + * Response headers. + * + * @var string[] + */ private $responseHeaders = null; + + /** + * Did Google demand that we try again. + * + * @var boolean + */ + private $mustRetry = null; + + /** + * Number of seconds to wait. + * + * @var integer + */ + private $waitSeconds = null; /** * Array of objects representing the status of the messages processed. @@ -60,7 +82,17 @@ public function __construct(Message $message, $responseBody, $responseHeaders) { $this->responseBody = $responseBody; $this->responseHeaders = $responseHeaders; - + + $this->mustRetry = false; + + foreach($responseHeaders as $header) { + if (strpos($header, 'Retry-After') !== false) { + $this->mustRetry = true; + $this->waitSeconds = (int) explode(" ", $header)[1]; + break; + } + } + $data = \json_decode($responseBody, true); if ($data === null) { throw new Exception("Malformed reponse body. ". $responseBody, Exception::MALFORMED_RESPONSE); @@ -88,6 +120,16 @@ public function getMulticastId() { return $this->multicastId; } + + public function getMustRetry() + { + return $this->mustRetry; + } + + public function getWaitSeconds() + { + return $this->waitSeconds; + } public function getSuccessCount() { From 60abcd7ceee119c0b7f2664b7005900dced34b2b Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 01:14:50 -0800 Subject: [PATCH 05/62] Update Exception.php --- library/CodeMonkeysRu/GCM/Exception.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Exception.php b/library/CodeMonkeysRu/GCM/Exception.php index 89fe987..67e2962 100644 --- a/library/CodeMonkeysRu/GCM/Exception.php +++ b/library/CodeMonkeysRu/GCM/Exception.php @@ -13,7 +13,7 @@ class Exception extends \Exception const SERVICE_UNAVAILABLE = 7; const INVALID_DATA_KEY = 8; const CURL_ERROR = 9; - const MISMATCH_SENDER_ID = 10; + const MISMATCH_SENDER_ID = 10; } /* From 8f74f3e3d3b56523fe52168d6c88f451806aac6a Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 01:19:46 -0800 Subject: [PATCH 06/62] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 6420f4a..ca03e7b 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,6 @@ try { //Schedule to resend messages to unavailable devices $unavailableIds = $response->getUnavailableRegistrationIds(); - //Suggestion: try again, using exponential back-off. Or put in a queue and use a cronjob. //TODO } } catch (GCM\Exception $e) { @@ -141,7 +140,6 @@ try { //Schedule to resend messages to unavailable devices $unavailableIds = $response->getUnavailableRegistrationIds(); - //Suggestion: try again, using exponential back-off. Or put in a queue and use a cronjob. //TODO } } catch (GCM\Exception $e) { From 530f345ec70cbf960d084d21eeb3d1f6e8be135e Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 01:24:49 -0800 Subject: [PATCH 07/62] Update Response.php --- library/CodeMonkeysRu/GCM/Response.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 517981f..93bd325 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -51,14 +51,14 @@ class Response * * @var boolean */ - private $mustRetry = null; + private $mustRetry = null; /** * Number of seconds to wait. * * @var integer */ - private $waitSeconds = null; + private $waitSeconds = null; /** * Array of objects representing the status of the messages processed. @@ -70,7 +70,7 @@ class Response * registration ID for that device, so sender should replace the IDs on future requests * (otherwise they might be rejected). This field is never set if there is an error in the request. * error: String describing an error that occurred while processing the message for that recipient. - * The possible values are the same as documented in the above table, plus "Unavailable" + * The possible values are the same as documented in the above table. Note in particular "Unavailable" * (meaning GCM servers were busy and could not process the message for that particular recipient, * so it could be retried). * @@ -83,13 +83,13 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $this->responseBody = $responseBody; $this->responseHeaders = $responseHeaders; - $this->mustRetry = false; + $this->mustRetry = false; - foreach($responseHeaders as $header) { + foreach($responseHeaders as $header) { if (strpos($header, 'Retry-After') !== false) { - $this->mustRetry = true; + $this->mustRetry = true; $this->waitSeconds = (int) explode(" ", $header)[1]; - break; + break; } } From bf1d7e55c179ea820f979e78553cfa9a56bf7dff Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 01:54:27 -0800 Subject: [PATCH 08/62] Stop storing raw response --- library/CodeMonkeysRu/GCM/Response.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 93bd325..8c735c7 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -32,13 +32,6 @@ class Response */ private $canonicalIds = null; - /** - * Raw response. - * - * @var string - */ - private $responseBody = null; - /** * Response headers. * @@ -80,7 +73,6 @@ class Response public function __construct(Message $message, $responseBody, $responseHeaders) { - $this->responseBody = $responseBody; $this->responseHeaders = $responseHeaders; $this->mustRetry = false; From 266823cf2e06e4890e38b7b9263294bf35998073 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 01:55:08 -0800 Subject: [PATCH 09/62] Update Response.php --- library/CodeMonkeysRu/GCM/Response.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 8c735c7..95fd384 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -100,10 +100,6 @@ public function __construct(Message $message, $responseBody, $responseHeaders) } } - public function getRawResponse() { - return $this->responseBody; - } - public function getResponseHeadersArray() { return $this->responseHeaders; } From 4e5bc71f4103f649606a3ffe737a04e444cc5af1 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sun, 8 Jan 2017 02:11:57 -0800 Subject: [PATCH 10/62] Update Response.php --- library/CodeMonkeysRu/GCM/Response.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 95fd384..750cd1f 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -82,8 +82,8 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $this->mustRetry = true; $this->waitSeconds = (int) explode(" ", $header)[1]; break; - } - } + } + } $data = \json_decode($responseBody, true); if ($data === null) { From bc6b5a5277a8597114770d24d0a4d16f68aab166 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Mon, 9 Jan 2017 22:37:03 -0800 Subject: [PATCH 11/62] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ca03e7b..80069de 100644 --- a/README.md +++ b/README.md @@ -49,13 +49,13 @@ try { if ($response->existsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->existsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } @@ -122,13 +122,13 @@ try { if ($response->existsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->existsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } From 705fc9be54572f0b7b0d2fc64b839db3d6bd1cc2 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Mon, 9 Jan 2017 22:55:22 -0800 Subject: [PATCH 12/62] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 80069de..b0bc7dd 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,13 @@ try { if ($response->getFailureCount() > 0) { - if ($response->existsInvalidDataKey()) { + if ($response->getExistsInvalidDataKey()) { //You used a reserved data key $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } - if ($response->existsMismatchSenderId()) { + if ($response->getExistsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); @@ -120,13 +120,13 @@ try { if ($response->getFailureCount() > 0) { - if ($response->existsInvalidDataKey()) { + if ($response->getExistsInvalidDataKey()) { //You used a reserved data key $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } - if ($response->existsMismatchSenderId()) { + if ($response->getExistsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); From b758c7c2b2e011f42ddef324166dabad8d44d2f1 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Mon, 9 Jan 2017 22:56:12 -0800 Subject: [PATCH 13/62] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b0bc7dd..fd9a046 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ try { throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } - $invalidRegistrationIds = $GCMresponse->getInvalidRegistrationIds(); + $invalidRegistrationIds = $response->getInvalidRegistrationIds(); foreach($invalidRegistrationIds as $invalidRegistrationId) { //Remove $invalidRegistrationId from DB //TODO @@ -132,7 +132,7 @@ try { throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } - $invalidRegistrationIds = $GCMresponse->getInvalidRegistrationIds(); + $invalidRegistrationIds = $response->getInvalidRegistrationIds(); foreach($invalidRegistrationIds as $invalidRegistrationId) { //Remove $invalidRegistrationId from DB //TODO From 042ebb0a5bd0bb165074e23e299adfb20fd012f9 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Mon, 9 Jan 2017 23:41:09 -0800 Subject: [PATCH 14/62] Update README.md --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index fd9a046..c1c1b17 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,6 @@ try { case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: - case GCM\Exception::INTERNAL_SERVER_ERROR: //gcm server problem - case GCM\Exception::SERVICE_UNAVAILABLE: //gcm server problem case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification case GCM\Exception::CURL_ERROR: //problem posting to gcm server case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes @@ -150,8 +148,6 @@ try { case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: - case GCM\Exception::INTERNAL_SERVER_ERROR: //gcm server problem - case GCM\Exception::SERVICE_UNAVAILABLE: //gcm server problem case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification case GCM\Exception::CURL_ERROR: //problem posting to gcm server case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes From cc44eb9dac2abe3ebd666d1af3518d2ada9d7712 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Mon, 9 Jan 2017 23:42:27 -0800 Subject: [PATCH 15/62] Respond to pull request remarks --- library/CodeMonkeysRu/GCM/Exception.php | 30 +---- library/CodeMonkeysRu/GCM/Message.php | 21 ---- library/CodeMonkeysRu/GCM/Response.php | 151 ++++++++++-------------- library/CodeMonkeysRu/GCM/Sender.php | 63 +++------- 4 files changed, 83 insertions(+), 182 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Exception.php b/library/CodeMonkeysRu/GCM/Exception.php index 67e2962..4c7e71e 100644 --- a/library/CodeMonkeysRu/GCM/Exception.php +++ b/library/CodeMonkeysRu/GCM/Exception.php @@ -9,31 +9,7 @@ class Exception extends \Exception const MALFORMED_REQUEST = 3; const UNKNOWN_ERROR = 4; const MALFORMED_RESPONSE = 5; - const INTERNAL_SERVER_ERROR = 6; - const SERVICE_UNAVAILABLE = 7; - const INVALID_DATA_KEY = 8; - const CURL_ERROR = 9; - const MISMATCH_SENDER_ID = 10; + const INVALID_DATA_KEY = 6; + const CURL_ERROR = 7; + const MISMATCH_SENDER_ID = 8; } - -/* -Copyright (c) 2014 Vladimir Savenkov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ diff --git a/library/CodeMonkeysRu/GCM/Message.php b/library/CodeMonkeysRu/GCM/Message.php index c237b06..65d897e 100644 --- a/library/CodeMonkeysRu/GCM/Message.php +++ b/library/CodeMonkeysRu/GCM/Message.php @@ -223,24 +223,3 @@ public function setContentAvailable($contentAvailable) return $this; } } -/* -Copyright (c) 2014 Vladimir Savenkov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 750cd1f..5f0e039 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -37,21 +37,36 @@ class Response * * @var string[] */ - private $responseHeaders = null; + private $responseHeaders = []; /** * Did Google demand that we try again. * * @var boolean */ - private $mustRetry = null; + private $mustRetry = false; /** * Number of seconds to wait. * * @var integer */ - private $waitSeconds = null; + private $waitSeconds = null; + + /** + * Did you use a reserved data key? + * + * @var boolean + */ + private $existsInvalidDataKey = false; + + /** + * Did one of your clients register with the wrong senderId? + * If one of them did, then presumably they all did. + * + * @var boolean + */ + private $existsMismatchSenderId = false; /** * Array of objects representing the status of the messages processed. @@ -63,7 +78,7 @@ class Response * registration ID for that device, so sender should replace the IDs on future requests * (otherwise they might be rejected). This field is never set if there is an error in the request. * error: String describing an error that occurred while processing the message for that recipient. - * The possible values are the same as documented in the above table. Note in particular "Unavailable" + * The possible values are the same as documented in the above table, plus "Unavailable" * (meaning GCM servers were busy and could not process the message for that particular recipient, * so it could be retried). * @@ -75,15 +90,15 @@ public function __construct(Message $message, $responseBody, $responseHeaders) { $this->responseHeaders = $responseHeaders; - $this->mustRetry = false; + $this->mustRetry = false; - foreach($responseHeaders as $header) { + foreach($responseHeaders as $header) { if (strpos($header, 'Retry-After') !== false) { - $this->mustRetry = true; + $this->mustRetry = true; $this->waitSeconds = (int) explode(" ", $header)[1]; - break; - } - } + break; + } + } $data = \json_decode($responseBody, true); if ($data === null) { @@ -93,14 +108,30 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $this->failure = $data['failure']; $this->success = $data['success']; $this->canonicalIds = $data['canonical_ids']; + $this->existsInvalidDataKey = false; + $this->existsMismatchSenderId = false; $this->results = array(); foreach ($message->getRegistrationIds() as $key => $registrationId) { - $this->results[$registrationId] = $data['results'][$key]; + $result = $data['results'][$key]; + if (isset($result['error'])) { + switch ($result['error']) { + case "InvalidDataKey": + $this->existsInvalidDataKey = true; + break; + case "MismatchSenderId": + $this->existsMismatchSenderId = true; + break; + default: + break; + } + } + $this->results[$registrationId] = $result; } + $result = null; } - public function getResponseHeadersArray() { + public function getResponseHeaders() { return $this->responseHeaders; } @@ -124,45 +155,31 @@ public function getSuccessCount() return $this->success; } - public function getTotallyNormalCount() - { - return($this->success - $this->canonicalIds); - } - public function getFailureCount() //both implementation errors and server errors are included here. { return $this->failure; } + + public function getExistsInvalidDataKey() + { + return $this->existsInvalidDataKey; + } + + public function getExistsMismatchSenderId() + { + return $this->existsMismatchSenderId; + } public function getNewRegistrationIdsCount() { return $this->canonicalIds; } - public function isTotallyNormal() - { - return (($this->getNewRegistrationIdsCount() == 0) && ($this->getFailureCount() == 0)); - } - public function getResults() { return $this->results; } - - /** - * Return a numeric array of registration ids which worked without any error or need to update. - */ - - public function getAsWrittenIds() - { - $filteredResults = array_filter($this->results, - function($result) { - return isset($result['message_id']) && !isset($result['registration_id']); - }); - - return array_keys($filteredResults); - } - + /** * Return an array of expired registration ids linked to new id * All old registration ids must be updated to new ones in DB @@ -185,12 +202,6 @@ function($result) { return $data; } - - public function someIdsNew() - { - $bool = (count($this->getNewRegistrationIds()) != 0); - return $bool; - } /** * Returns an array containing invalid registration ids @@ -212,8 +223,6 @@ function($result) { ($result['error'] == "NotRegistered") || ($result['error'] == "InvalidRegistration") - || - ($result['error'] == "DeviceMessageRateExceeded") ) ); }); @@ -221,11 +230,6 @@ function($result) { return array_keys($filteredResults); } - public function someIdsInvalid() - { - $bool = (count($this->getInvalidRegistrationIds()) != 0); - return $bool; - } /** * Returns an array of registration ids for which you must resend a message (?), @@ -249,44 +253,21 @@ function($result) { ($result['error'] == "Unavailable") || ($result['error'] == "InternalServerError") + || + ($result['error'] == "DeviceMessageRateExceeded") ) ); }); return array_keys($filteredResults); } - - public function someIdsUnavailable() { - $bool = (count($this->getUnavailableRegistrationIds()) != 0); - return $bool; - } - - //invalid data key - - public function getInvalidDataKeysIds() { - if ($this->getFailureCount() == 0) { - return array(); - } - $filteredResults = array_filter($this->results, - function($result) { - return ( - isset($result['error']) - && - ($result['error'] == "InvalidDataKey") - ); - }); - - return array_keys($filteredResults); - - } - - public function existsInvalidDataKey() { - $bool = (count($this->getInvalidDataKeysIds()) != 0); - return $bool; - } - - //mismatch sender id - + + /** + * Returns an array of registration ids who registered + * for pushes using the wrong senderId. + * + * @return array + */ public function getMismatchSenderIdIds() { if ($this->getFailureCount() == 0) { return array(); @@ -302,12 +283,6 @@ function($result) { return array_keys($filteredResults); } - - public function existsMismatchSenderId() { - $bool = (count($this->getMismatchSenderIdIds()) != 0); - return $bool; - } - } /* diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index f0bad27..e81d3cf 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -125,32 +125,25 @@ public function send(Message $message) curl_close($ch); - if ($resultHttpCode == "200") { - ;//check for errors wrt individual devices later with the Response object. + switch ($resultHttpCode) { + case "200": + //All fine. Continue response processing. + break; + + case "400": + throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); + break; + + case "401": + throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); + break; + + default: + //TODO: Retry-after + throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); + break; } - elseif ($resultHttpCode == "400") { - throw new Exception('Malformed request. '. $resultBody, Exception::MALFORMED_REQUEST); - } - - elseif ($resultHttpCode == "401") { - throw new Exception('Authentication Error. '. $resultBody, Exception::AUTHENTICATION_ERROR); - } - - elseif ($resultHttpCode == "500") { - throw new Exception('Internal Server Error. ' . $resultBody, Exception::INTERNAL_SERVER_ERROR); - } - - elseif ((600 > (int) $resultHttpCode) && ((int) $resultHttpCode > 500)) { - throw new Exception('Service Unavailable. ' . $resultBody, Exception::SERVICE_UNAVAILABLE); - } - - else { - throw new Exception("Unknown error. ". $resultBody, Exception::UNKNOWN_ERROR); - } - - - return new Response($message, $resultBody, $responseHeaders); } @@ -207,25 +200,3 @@ private function validatePayloadSize(array $rawData, $fieldName, $maxSize) } } } - -/* -Copyright (c) 2014 Vladimir Savenkov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ From 4b27d4eb42d6503674af0e0c74739db4dde11f67 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:14:41 -0800 Subject: [PATCH 16/62] Indentation --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c1c1b17..e128127 100644 --- a/README.md +++ b/README.md @@ -49,13 +49,14 @@ try { if ($response->getExistsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->getExistsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); + $error_msg = 'Mismatch senderId. Problem clients are ' + . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } @@ -126,7 +127,8 @@ try { if ($response->getExistsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); + $error_msg = 'Mismatch senderId. Problem clients are ' + . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } From 712ea7c92ed08c5387a145c7cc6cf31d1809fe56 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:16:38 -0800 Subject: [PATCH 17/62] Text editor problems ... --- README.md | 50 ++------------------------------------------------ 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index e128127..a49741b 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,6 @@ $message try { $response = $sender->send($message); - if ($response->getMustRetry() { - $waitSeconds = $response->getWaitSeconds(); - //Try again after that many seconds, and use exponential backoff subsequently, as needed. - //TODO - } - if ($response->getNewRegistrationIdsCount() > 0) { $newRegistrationIds = $response->getNewRegistrationIds(); foreach ($newRegistrationIds as $oldRegistrationId => $newRegistrationId){ @@ -46,21 +40,7 @@ try { } if ($response->getFailureCount() > 0) { - - if ($response->getExistsInvalidDataKey()) { - //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); - throw new Exception($error_msg, Exception::INVALID_DATA_KEY); - } - - if ($response->getExistsMismatchSenderId()) { - //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' - . json_encode($response->getMismatchSenderIdIds()); - throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); - } - - $invalidRegistrationIds = $response->getInvalidRegistrationIds(); + $invalidRegistrationIds = $GCMresponse->getInvalidRegistrationIds(); foreach($invalidRegistrationIds as $invalidRegistrationId) { //Remove $invalidRegistrationId from DB //TODO @@ -78,9 +58,6 @@ try { case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: - case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification - case GCM\Exception::CURL_ERROR: //problem posting to gcm server - case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes //Deal with it break; } @@ -103,12 +80,6 @@ try { "collapse_key" ); - if ($response->getMustRetry() { - $waitSeconds = $response->getWaitSeconds(); - //Try again after that many seconds, and use exponential backoff subsequently, as needed. - //TODO - } - if ($response->getNewRegistrationIdsCount() > 0) { $newRegistrationIds = $response->getNewRegistrationIds(); foreach ($newRegistrationIds as $oldRegistrationId => $newRegistrationId){ @@ -118,21 +89,7 @@ try { } if ($response->getFailureCount() > 0) { - - if ($response->getExistsInvalidDataKey()) { - //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); - throw new Exception($error_msg, Exception::INVALID_DATA_KEY); - } - - if ($response->getExistsMismatchSenderId()) { - //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' - . json_encode($response->getMismatchSenderIdIds()); - throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); - } - - $invalidRegistrationIds = $response->getInvalidRegistrationIds(); + $invalidRegistrationIds = $GCMresponse->getInvalidRegistrationIds(); foreach($invalidRegistrationIds as $invalidRegistrationId) { //Remove $invalidRegistrationId from DB //TODO @@ -150,9 +107,6 @@ try { case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: - case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification - case GCM\Exception::CURL_ERROR: //problem posting to gcm server - case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes //Deal with it break; } From 235a667c46379240115994764caaaa0c3a84d0f0 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:18:31 -0800 Subject: [PATCH 18/62] Add files via upload --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a49741b..bf34f1a 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,12 @@ $message try { $response = $sender->send($message); + if ($response->getMustRetry() { + $waitSeconds = $response->getWaitSeconds(); + //Try again after that many seconds, and use exponential backoff subsequently, as needed. + //TODO + } + if ($response->getNewRegistrationIdsCount() > 0) { $newRegistrationIds = $response->getNewRegistrationIds(); foreach ($newRegistrationIds as $oldRegistrationId => $newRegistrationId){ @@ -40,7 +46,21 @@ try { } if ($response->getFailureCount() > 0) { - $invalidRegistrationIds = $GCMresponse->getInvalidRegistrationIds(); + + if ($response->getExistsInvalidDataKey()) { + //You used a reserved data key + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + throw new Exception($error_msg, Exception::INVALID_DATA_KEY); + } + + if ($response->getExistsMismatchSenderId()) { + //A client sent the wrong senderId when it registered for pushes + $error_msg = 'Mismatch senderId. Problem clients are ' + . json_encode($response->getMismatchSenderIdIds()); + throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); + } + + $invalidRegistrationIds = $response->getInvalidRegistrationIds(); foreach($invalidRegistrationIds as $invalidRegistrationId) { //Remove $invalidRegistrationId from DB //TODO @@ -58,6 +78,9 @@ try { case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: + case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification + case GCM\Exception::CURL_ERROR: //problem posting to gcm server + case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes //Deal with it break; } @@ -80,6 +103,12 @@ try { "collapse_key" ); + if ($response->getMustRetry() { + $waitSeconds = $response->getWaitSeconds(); + //Try again after that many seconds, and use exponential backoff subsequently, as needed. + //TODO + } + if ($response->getNewRegistrationIdsCount() > 0) { $newRegistrationIds = $response->getNewRegistrationIds(); foreach ($newRegistrationIds as $oldRegistrationId => $newRegistrationId){ @@ -89,7 +118,21 @@ try { } if ($response->getFailureCount() > 0) { - $invalidRegistrationIds = $GCMresponse->getInvalidRegistrationIds(); + + if ($response->getExistsInvalidDataKey()) { + //You used a reserved data key + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + throw new Exception($error_msg, Exception::INVALID_DATA_KEY); + } + + if ($response->getExistsMismatchSenderId()) { + //A client sent the wrong senderId when it registered for pushes + $error_msg = 'Mismatch senderId. Problem clients are ' + . json_encode($response->getMismatchSenderIdIds()); + throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); + } + + $invalidRegistrationIds = $response->getInvalidRegistrationIds(); foreach($invalidRegistrationIds as $invalidRegistrationId) { //Remove $invalidRegistrationId from DB //TODO @@ -107,6 +150,9 @@ try { case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: + case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification + case GCM\Exception::CURL_ERROR: //problem posting to gcm server + case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes //Deal with it break; } From 8c4f38109fd6d4f8583fd60c0e832622375f39ec Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:20:45 -0800 Subject: [PATCH 19/62] Update Exception.php --- library/CodeMonkeysRu/GCM/Exception.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Exception.php b/library/CodeMonkeysRu/GCM/Exception.php index 4c7e71e..baa71fb 100644 --- a/library/CodeMonkeysRu/GCM/Exception.php +++ b/library/CodeMonkeysRu/GCM/Exception.php @@ -11,5 +11,5 @@ class Exception extends \Exception const MALFORMED_RESPONSE = 5; const INVALID_DATA_KEY = 6; const CURL_ERROR = 7; - const MISMATCH_SENDER_ID = 8; + const MISMATCH_SENDER_ID = 8; } From 48d6ab32d96b2538cb11e50792dbb6e5b31f6fbb Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:25:22 -0800 Subject: [PATCH 20/62] Indentation gremlins --- library/CodeMonkeysRu/GCM/Response.php | 82 ++++++++++---------------- 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 5f0e039..da0743f 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -44,21 +44,21 @@ class Response * * @var boolean */ - private $mustRetry = false; + private $mustRetry = false; /** * Number of seconds to wait. * * @var integer */ - private $waitSeconds = null; + private $waitSeconds = null; /** * Did you use a reserved data key? * * @var boolean */ - private $existsInvalidDataKey = false; + private $existsInvalidDataKey = false; /** * Did one of your clients register with the wrong senderId? @@ -66,7 +66,7 @@ class Response * * @var boolean */ - private $existsMismatchSenderId = false; + private $existsMismatchSenderId = false; /** * Array of objects representing the status of the messages processed. @@ -90,15 +90,15 @@ public function __construct(Message $message, $responseBody, $responseHeaders) { $this->responseHeaders = $responseHeaders; - $this->mustRetry = false; + $this->mustRetry = false; - foreach($responseHeaders as $header) { + foreach($responseHeaders as $header) { if (strpos($header, 'Retry-After') !== false) { - $this->mustRetry = true; - $this->waitSeconds = (int) explode(" ", $header)[1]; - break; - } - } + $this->mustRetry = true; + $this->waitSeconds = (int) explode(" ", $header)[1]; + break; + } + } $data = \json_decode($responseBody, true); if ($data === null) { @@ -108,27 +108,27 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $this->failure = $data['failure']; $this->success = $data['success']; $this->canonicalIds = $data['canonical_ids']; - $this->existsInvalidDataKey = false; - $this->existsMismatchSenderId = false; + $this->existsInvalidDataKey = false; + $this->existsMismatchSenderId = false; $this->results = array(); foreach ($message->getRegistrationIds() as $key => $registrationId) { - $result = $data['results'][$key]; - if (isset($result['error'])) { - switch ($result['error']) { - case "InvalidDataKey": - $this->existsInvalidDataKey = true; - break; - case "MismatchSenderId": - $this->existsMismatchSenderId = true; - break; - default: - break; - } - } - $this->results[$registrationId] = $result; + $result = $data['results'][$key]; + if (isset($result['error'])) { + switch ($result['error']) { + case "InvalidDataKey": + $this->existsInvalidDataKey = true; + break; + case "MismatchSenderId": + $this->existsMismatchSenderId = true; + break; + default: + break; + } + } + $this->results[$registrationId] = $result; } - $result = null; + $result = null; } public function getResponseHeaders() { @@ -161,12 +161,12 @@ public function getFailureCount() //both implementation errors and server errors } public function getExistsInvalidDataKey() - { + { return $this->existsInvalidDataKey; } public function getExistsMismatchSenderId() - { + { return $this->existsMismatchSenderId; } @@ -284,25 +284,3 @@ function($result) { return array_keys($filteredResults); } } - -/* -Copyright (c) 2014 Vladimir Savenkov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ From 7e85a44d1e226cb130eb30f40290a5b5d03e842d Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:26:41 -0800 Subject: [PATCH 21/62] Update Response.php --- library/CodeMonkeysRu/GCM/Response.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index da0743f..c99241d 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -155,7 +155,12 @@ public function getSuccessCount() return $this->success; } - public function getFailureCount() //both implementation errors and server errors are included here. + /** + * Both implementation errors and server errors are included here. + * + * @var integer + */ + public function getFailureCount() { return $this->failure; } From ca976f3210fc6a8309ff7490d299801c1c202743 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:28:21 -0800 Subject: [PATCH 22/62] Update Response.php --- library/CodeMonkeysRu/GCM/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index c99241d..fb34160 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -158,7 +158,7 @@ public function getSuccessCount() /** * Both implementation errors and server errors are included here. * - * @var integer + * @return integer */ public function getFailureCount() { From 93a27a282534cbd549b2c88f4865fbf42c5a7be4 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:31:54 -0800 Subject: [PATCH 23/62] Update Sender.php --- library/CodeMonkeysRu/GCM/Sender.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index e81d3cf..fcab0b1 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -163,7 +163,7 @@ private function formMessageData(Message $message) 'registration_ids' => 'getRegistrationIds', 'collapse_key' => 'getCollapseKey', 'data' => 'getData', - 'notification' => 'getNotification', + 'notification' => 'getNotification', 'delay_while_idle' => 'getDelayWhileIdle', 'time_to_live' => 'getTtl', 'restricted_package_name' => 'getRestrictedPackageName', From 7e68f27692cfdbd925311358a2eae0b3e25b9dbb Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:36:56 -0800 Subject: [PATCH 24/62] Update Message.php --- library/CodeMonkeysRu/GCM/Message.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Message.php b/library/CodeMonkeysRu/GCM/Message.php index 65d897e..4df132f 100644 --- a/library/CodeMonkeysRu/GCM/Message.php +++ b/library/CodeMonkeysRu/GCM/Message.php @@ -54,7 +54,7 @@ class Message * @var array|null */ private $notification = null; - + /** * Indicates that the message should not be sent immediately if the device is idle. * The server will wait for the device to become active, and then only the last message @@ -156,7 +156,7 @@ public function setData($data) $this->data = $data; return $this; } - + public function getNotification() { return $this->notification; From e4281541fa7bc63cac8374c919982d41bcba2bdc Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:38:14 -0800 Subject: [PATCH 25/62] Update Message.php --- library/CodeMonkeysRu/GCM/Message.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Message.php b/library/CodeMonkeysRu/GCM/Message.php index 4df132f..f116005 100644 --- a/library/CodeMonkeysRu/GCM/Message.php +++ b/library/CodeMonkeysRu/GCM/Message.php @@ -54,7 +54,7 @@ class Message * @var array|null */ private $notification = null; - + /** * Indicates that the message should not be sent immediately if the device is idle. * The server will wait for the device to become active, and then only the last message @@ -156,7 +156,7 @@ public function setData($data) $this->data = $data; return $this; } - + public function getNotification() { return $this->notification; From 17619174422ef01d42c2267f4ae02421536afe13 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:41:17 -0800 Subject: [PATCH 26/62] Update Response.php --- library/CodeMonkeysRu/GCM/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index fb34160..b25a2d1 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -114,7 +114,7 @@ public function __construct(Message $message, $responseBody, $responseHeaders) foreach ($message->getRegistrationIds() as $key => $registrationId) { $result = $data['results'][$key]; - if (isset($result['error'])) { + if (isset($result['error'])) { switch ($result['error']) { case "InvalidDataKey": $this->existsInvalidDataKey = true; From 3bbc5ed97c40632b03a6f3fc8d72222bef3bbb2d Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:45:11 -0800 Subject: [PATCH 27/62] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bf34f1a..45ac8cd 100644 --- a/README.md +++ b/README.md @@ -49,13 +49,13 @@ try { if ($response->getExistsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->getExistsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } @@ -121,14 +121,14 @@ try { if ($response->getExistsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->getExistsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes $error_msg = 'Mismatch senderId. Problem clients are ' - . json_encode($response->getMismatchSenderIdIds()); + . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } From 2868047d1586e57cfb968f3bfa0705f7be6846fb Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:48:27 -0800 Subject: [PATCH 28/62] Indentation ... --- library/CodeMonkeysRu/GCM/Response.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index b25a2d1..d8aa607 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -179,12 +179,12 @@ public function getNewRegistrationIdsCount() { return $this->canonicalIds; } - + public function getResults() { return $this->results; } - + /** * Return an array of expired registration ids linked to new id * All old registration ids must be updated to new ones in DB @@ -227,7 +227,7 @@ function($result) { ( ($result['error'] == "NotRegistered") || - ($result['error'] == "InvalidRegistration") + ($result['error'] == "InvalidRegistration") ) ); }); From 418efd3bb36928392e2942d873b2a416c195665c Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:51:02 -0800 Subject: [PATCH 29/62] Indentation --- library/CodeMonkeysRu/GCM/Sender.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index fcab0b1..1c02d4e 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -76,7 +76,7 @@ public function send(Message $message) if (count($message->getRegistrationIds()) > 1000) { throw new Exception("Malformed request: Registration Ids exceed the GCM imposed limit of 1000", Exception::MALFORMED_REQUEST); } - + $rawData = $this->formMessageData($message); $this->validatePayloadSize($rawData, 'data', 4096); $this->validatePayloadSize($rawData, 'notification', 2048); @@ -124,7 +124,7 @@ public function send(Message $message) $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); - + switch ($resultHttpCode) { case "200": //All fine. Continue response processing. @@ -143,7 +143,7 @@ public function send(Message $message) throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); break; } - + return new Response($message, $resultBody, $responseHeaders); } @@ -179,7 +179,7 @@ private function formMessageData(Message $message) return $data; } - + /** * Validate size of json representation of passed payload * From ec55ec99275767a39fefc59278e3f5578d754e84 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:53:40 -0800 Subject: [PATCH 30/62] Indentation --- library/CodeMonkeysRu/GCM/Sender.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index 1c02d4e..2a332be 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -163,7 +163,7 @@ private function formMessageData(Message $message) 'registration_ids' => 'getRegistrationIds', 'collapse_key' => 'getCollapseKey', 'data' => 'getData', - 'notification' => 'getNotification', + 'notification' => 'getNotification', 'delay_while_idle' => 'getDelayWhileIdle', 'time_to_live' => 'getTtl', 'restricted_package_name' => 'getRestrictedPackageName', From ea3a22297cf341010806aa04ff3829717749e2b7 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 00:55:18 -0800 Subject: [PATCH 31/62] Update Response.php --- library/CodeMonkeysRu/GCM/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index d8aa607..203b41e 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -102,7 +102,7 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $data = \json_decode($responseBody, true); if ($data === null) { - throw new Exception("Malformed reponse body. ". $responseBody, Exception::MALFORMED_RESPONSE); + throw new Exception("Malformed reponse body. ".$responseBody, Exception::MALFORMED_RESPONSE); } $this->multicastId = $data['multicast_id']; $this->failure = $data['failure']; From 1635a892619c05a99a045c18ed5e8c1356a4665e Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 01:01:35 -0800 Subject: [PATCH 32/62] Indentation --- library/CodeMonkeysRu/GCM/Sender.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index 2a332be..f811e8b 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -90,37 +90,32 @@ public function send(Message $message) $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->gcmUrl); - curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HEADER, 1); // return HTTP headers with response - - + if ($this->caInfoPath !== false) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_CAINFO, $this->caInfoPath); } else { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - - + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $resp = curl_exec($ch); if ($resp === FALSE) { throw new Exception('cURL error: '. curl_error($ch), Exception::CURL_ERROR); - } - + list($responseHeaders, $resultBody) = explode("\r\n\r\n", $resp, 2); // $headers now has a string of the HTTP headers // $resultBody is the body of the HTTP response $responseHeaders = explode("\n", $responseHeaders); - + $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); From 2e763b3e80df25fe8899dc94fbb3bf17b6ed7ff3 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 22:59:49 -0800 Subject: [PATCH 33/62] Respond to comments Got rid of CURL_ERROR exception, removed newlines, etc --- Exception.php | 14 +++ Message.php | 225 ++++++++++++++++++++++++++++++++++++++ README.md | 8 +- Response.php | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++ Sender.php | 202 ++++++++++++++++++++++++++++++++++ 5 files changed, 738 insertions(+), 5 deletions(-) create mode 100644 Exception.php create mode 100644 Message.php create mode 100644 Response.php create mode 100644 Sender.php diff --git a/Exception.php b/Exception.php new file mode 100644 index 0000000..9f97648 --- /dev/null +++ b/Exception.php @@ -0,0 +1,14 @@ + + */ +class Message +{ + + /** + * A string array with the list of devices (registration IDs) receiving the message. + * It must contain at least 1 and at most 1000 registration IDs. + * + * Required. + * + * @var array + */ + private $registrationIds = array(); + + /** + * An arbitrary string (such as "Updates Available") that is used to collapse a group of like messages + * when the device is offline, so that only the last message gets sent to the client. + * This is intended to avoid sending too many messages to the phone when it comes back online. + * Note that since there is no guarantee of the order in which messages get sent, the "last" message + * may not actually be the last message sent by the application server. + * + * Optional. + * + * @var string|null + */ + private $collapseKey = null; + + /** + * Message payload data. + * If present, the payload data it will be included in the Intent as application data, + * with the key being the extra's name. + * + * Optional. + * + * @var array|null + */ + private $data = null; + + /** + * Notification payload. + * This parameter specifies the key-value pairs of the notification payload. + * See Notification payload support for more information + * (https://developers.google.com/cloud-messaging/server-ref#notification-payload-support). + * + * Optional. + * + * @var array|null + */ + private $notification = null; + + /** + * Indicates that the message should not be sent immediately if the device is idle. + * The server will wait for the device to become active, and then only the last message + * for each collapse_key value will be sent. + * + * Optional. + * + * @var boolean + */ + private $delayWhileIdle = false; + + /** + * How long (in seconds) the message should be kept on GCM storage if the device is offline. + * + * Optional (default time-to-live is 4 weeks). + * + * @var int + */ + private $ttl = null; + + /** + * A string containing the package name of your application. + * When set, messages will only be sent to registration IDs that match the package name. + * + * Optional. + * + * @var string|null + */ + private $restrictedPackageName = null; + + /** + * On iOS, use this field to represent content-available in the APNS payload. When a + * notification or message is sent and this is set to true, an inactive client app is + * awoken. On Android, data messages wake the app by default. + * + * Optional. + * + * @var bool + */ + private $contentAvailable = true; + + /** + * Allows developers to test their request without actually sending a message. + * + * Optional. + * + * @var boolean + */ + private $dryRun = false; + + public function __construct($registrationIds = null, $data = null, $collapseKey = null) + { + $this->bulkSet($registrationIds, $data, $collapseKey); + } + + /** + * Set multiple fields at once. + * + * @param string[] $registrationIds + * @param array|null $data + * @param string|null $collapseKey + */ + public function bulkSet($registrationIds = array(), $data = null, $collapseKey = null) + { + $this->setRegistrationIds($registrationIds); + $this->setData($data); + $this->setCollapseKey($collapseKey); + } + + public function getRegistrationIds() + { + return $this->registrationIds; + } + + public function setRegistrationIds($registrationIds) + { + $this->registrationIds = $registrationIds; + return $this; + } + + public function getCollapseKey() + { + return $this->collapseKey; + } + + public function setCollapseKey($collapseKey) + { + $this->collapseKey = $collapseKey; + return $this; + } + + public function getData() + { + return $this->data; + } + + public function setData($data) + { + $this->data = $data; + return $this; + } + + public function getNotification() + { + return $this->notification; + } + + public function setNotification($notification) + { + $this->notification = $notification; + return $this; + } + + public function getDelayWhileIdle() + { + return $this->delayWhileIdle; + } + + public function setDelayWhileIdle($delayWhileIdle) + { + $this->delayWhileIdle = $delayWhileIdle; + return $this; + } + + public function getTtl() + { + return $this->ttl; + } + + public function setTtl($ttl) + { + $this->ttl = $ttl; + return $this; + } + + public function getRestrictedPackageName() + { + return $this->restrictedPackageName; + } + + public function setRestrictedPackageName($restrictedPackageName) + { + $this->restrictedPackageName = $restrictedPackageName; + return $this; + } + + public function getDryRun() + { + return $this->dryRun; + } + + public function setDryRun($dryRun) + { + $this->dryRun = $dryRun; + return $this; + } + + public function getContentAvailable() + { + return $this->contentAvailable; + } + + public function setContentAvailable($contentAvailable) + { + $this->contentAvailable = $contentAvailable; + return $this; + } +} diff --git a/README.md b/README.md index 45ac8cd..1e2ace8 100644 --- a/README.md +++ b/README.md @@ -49,13 +49,13 @@ try { if ($response->getExistsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->getExistsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } @@ -79,7 +79,6 @@ try { case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification - case GCM\Exception::CURL_ERROR: //problem posting to gcm server case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes //Deal with it break; @@ -121,7 +120,7 @@ try { if ($response->getExistsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } @@ -151,7 +150,6 @@ try { case GCM\Exception::UNKNOWN_ERROR: case GCM\Exception::MALFORMED_RESPONSE: case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification - case GCM\Exception::CURL_ERROR: //problem posting to gcm server case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes //Deal with it break; diff --git a/Response.php b/Response.php new file mode 100644 index 0000000..38204de --- /dev/null +++ b/Response.php @@ -0,0 +1,294 @@ +responseHeaders = $responseHeaders; + $this->mustRetry = false; + + foreach ($responseHeaders as $header) { + if (strpos($header, 'Retry-After') !== false) { + $this->mustRetry = true; + $this->waitSeconds = (int) explode(" ", $header)[1]; + break; + } + } + + $data = \json_decode($responseBody, true); + if ($data === null) { + throw new Exception("Malformed reponse body. ". $responseBody, Exception::MALFORMED_RESPONSE); + } + $this->multicastId = $data['multicast_id']; + $this->failure = $data['failure']; + $this->success = $data['success']; + $this->canonicalIds = $data['canonical_ids']; + $this->existsInvalidDataKey = false; + $this->existsMismatchSenderId = false; + $this->results = array(); + + foreach ($message->getRegistrationIds() as $key => $registrationId) { + $result = $data['results'][$key]; + if (isset($result['error'])) { + switch ($result['error']) { + case "InvalidDataKey": + $this->existsInvalidDataKey = true; + break; + case "MismatchSenderId": + $this->existsMismatchSenderId = true; + break; + } + } + $this->results[$registrationId] = $result; + } + $result = null; + } + + public function getResponseHeaders() + { + return $this->responseHeaders; + } + + public function getMulticastId() + { + return $this->multicastId; + } + + public function getMustRetry() + { + return $this->mustRetry; + } + + public function getWaitSeconds() + { + return $this->waitSeconds; + } + + public function getSuccessCount() + { + return $this->success; + } + + public function getFailureCount() //both implementation errors and server errors are included here. + { + return $this->failure; + } + + public function getExistsInvalidDataKey() + { + return $this->existsInvalidDataKey; + } + + public function getExistsMismatchSenderId() + { + return $this->existsMismatchSenderId; + } + + public function getNewRegistrationIdsCount() + { + return $this->canonicalIds; + } + + public function getResults() + { + return $this->results; + } + + /** + * Return an array of expired registration ids linked to new id + * All old registration ids must be updated to new ones in DB + * + * @return array oldRegistrationId => newRegistrationId + */ + public function getNewRegistrationIds() + { + if ($this->getNewRegistrationIdsCount() == 0) { + return array(); + } + $filteredResults = array_filter( + $this->results, + function ($result) { + return isset($result['registration_id']); + } + ); + + $data = array_map(function ($result) { + return $result['registration_id']; + }, $filteredResults); + + return $data; + } + + /** + * Returns an array containing invalid registration ids + * They must be removed from DB because the application was uninstalled from the device. + * + * @return array + */ + public function getInvalidRegistrationIds() + { + if ($this->getFailureCount() == 0) { + return array(); + } + $filteredResults = array_filter( + $this->results, + function ($result) { + return ( + isset($result['error']) + && + ( + ($result['error'] == "NotRegistered") + || + ($result['error'] == "InvalidRegistration") + ) + ); + } + ); + + return array_keys($filteredResults); + } + + + /** + * Returns an array of registration ids for which you must resend a message (?), + * cause devices aren't available now. + * + * @TODO: check if it be auto sended later + * + * @return array + */ + public function getUnavailableRegistrationIds() + { + if ($this->getFailureCount() == 0) { + return array(); + } + $filteredResults = array_filter( + $this->results, + function ($result) { + return ( + isset($result['error']) + && + ( + ($result['error'] == "Unavailable") + || + ($result['error'] == "InternalServerError") + || + ($result['error'] == "DeviceMessageRateExceeded") + ) + ); + } + ); + + return array_keys($filteredResults); + } + + /** + * Returns an array of registration ids who registered + * for pushes using the wrong senderId. + * + * @return array + */ + public function getMismatchSenderIdIds() + { + if ($this->getFailureCount() == 0) { + return array(); + } + $filteredResults = array_filter( + $this->results, + function ($result) { + return ( + isset($result['error']) + && + ($result['error'] == "MismatchSenderId") + ); + } + ); + + return array_keys($filteredResults); + } +} diff --git a/Sender.php b/Sender.php new file mode 100644 index 0000000..727b6db --- /dev/null +++ b/Sender.php @@ -0,0 +1,202 @@ + + */ +class Sender +{ + + /** + * GCM endpoint + * + * @var string + */ + private $gcmUrl = 'https://android.googleapis.com/gcm/send'; + + /** + * Path to CA file (due to cURL 7.10 changes; you can get it from here: http://curl.haxx.se/docs/caextract.html) + * + * @var string + */ + private $caInfoPath = false; + + /** + * An API key that gives the application server authorized access to Google services. + * + * @var string + */ + private $serverApiKey = false; + + public function __construct($serverApiKey, $gcmUrl = false, $caInfoPath = false) + { + $this->serverApiKey = $serverApiKey; + if ($gcmUrl) { + $this->gcmUrl = $gcmUrl; + } + if ($caInfoPath) { + $this->caInfoPath = $caInfoPath; + } + } + + /** + * Send message to GCM without explicitly created message + * + * @param string[] $registrationIds + * @param array|null $data + * @param string|null $collapseKey + * + * @throws \CodeMonkeysRu\GCM\Exception + * @return \CodeMonkeysRu\GCM\Response + */ + public function sendMessage() + { + $message = new \CodeMonkeysRu\GCM\Message(); + call_user_func_array(array($message, 'bulkSet'), func_get_args()); + return $this->send($message); + } + + /** + * Send message to GCM + * + * @param \CodeMonkeysRu\GCM\Message $message + * @throws \CodeMonkeysRu\GCM\Exception + * @return \CodeMonkeysRu\GCM\Response + */ + public function send(Message $message) + { + + if (!$this->serverApiKey) { + throw new Exception("Server API Key not set", Exception::ILLEGAL_API_KEY); + } + + //GCM response: Number of messages on bulk (1001) exceeds maximum allowed (1000) + if (count($message->getRegistrationIds()) > 1000) { + throw new Exception( + "Malformed request: Registration Ids exceed the GCM imposed limit of 1000", + Exception::MALFORMED_REQUEST + ); + } + + $rawData = $this->formMessageData($message); + $this->validatePayloadSize($rawData, 'data', 4096); + $this->validatePayloadSize($rawData, 'notification', 2048); + $data = json_encode($rawData); + + $headers = array( + 'Authorization: key='.$this->serverApiKey, + 'Content-Type: application/json' + ); + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $this->gcmUrl); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, 1); // return HTTP headers with response + + if ($this->caInfoPath !== false) { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_CAINFO, $this->caInfoPath); + } else { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + } + + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + + $resp = curl_exec($ch); + + if ($resp === false) { + throw new Exception('Error connecting to GCM endpoint: '.curl_error($ch), Exception::UNKNOWN_ERROR); + } + + list($responseHeaders, $resultBody) = explode("\r\n\r\n", $resp, 2); + // $headers now has a string of the HTTP headers + // $resultBody is the body of the HTTP response + + $responseHeaders = explode("\n", $responseHeaders); + + $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + curl_close($ch); + + switch ($resultHttpCode) { + case "200": + //All fine. Continue response processing. + break; + + case "400": + throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); + break; + + case "401": + throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); + break; + + default: + //TODO: Retry-after + throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); + break; + } + + return new Response($message, $resultBody, $responseHeaders); + } + + /** + * Form raw message data for sending to GCM + * + * @param \CodeMonkeysRu\GCM\Message $message + * @return array + */ + private function formMessageData(Message $message) + { + $data = array( + 'registration_ids' => $message->getRegistrationIds(), + ); + + $dataFields = array( + 'registration_ids' => 'getRegistrationIds', + 'collapse_key' => 'getCollapseKey', + 'data' => 'getData', + 'notification' => 'getNotification', + 'delay_while_idle' => 'getDelayWhileIdle', + 'time_to_live' => 'getTtl', + 'restricted_package_name' => 'getRestrictedPackageName', + 'dry_run' => 'getDryRun', + 'content_available' => 'getContentAvailable' + ); + + foreach ($dataFields as $fieldName => $getter) { + if ($message->$getter() != null) { + $data[$fieldName] = $message->$getter(); + } + } + + return $data; + } + + /** + * Validate size of json representation of passed payload + * + * @param array $rawData + * @param string $fieldName + * @param int $maxSize + * @throws \CodeMonkeysRu\GCM\Exception + * @return void + */ + private function validatePayloadSize(array $rawData, $fieldName, $maxSize) + { + if (!isset($rawData[$fieldName])) { + return; + } + if (strlen(json_encode($rawData[$fieldName])) > $maxSize) { + throw new Exception( + ucfirst($fieldName)." payload is to big (max {$maxSize} bytes)", + Exception::MALFORMED_REQUEST + ); + } + } +} From 90c63abb6615c5d655aeb6a1ee09003dc480ab85 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 23:00:44 -0800 Subject: [PATCH 34/62] Delete Exception.php --- Exception.php | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 Exception.php diff --git a/Exception.php b/Exception.php deleted file mode 100644 index 9f97648..0000000 --- a/Exception.php +++ /dev/null @@ -1,14 +0,0 @@ - Date: Tue, 10 Jan 2017 23:01:03 -0800 Subject: [PATCH 35/62] Delete Message.php --- Message.php | 225 ---------------------------------------------------- 1 file changed, 225 deletions(-) delete mode 100644 Message.php diff --git a/Message.php b/Message.php deleted file mode 100644 index 4df132f..0000000 --- a/Message.php +++ /dev/null @@ -1,225 +0,0 @@ - - */ -class Message -{ - - /** - * A string array with the list of devices (registration IDs) receiving the message. - * It must contain at least 1 and at most 1000 registration IDs. - * - * Required. - * - * @var array - */ - private $registrationIds = array(); - - /** - * An arbitrary string (such as "Updates Available") that is used to collapse a group of like messages - * when the device is offline, so that only the last message gets sent to the client. - * This is intended to avoid sending too many messages to the phone when it comes back online. - * Note that since there is no guarantee of the order in which messages get sent, the "last" message - * may not actually be the last message sent by the application server. - * - * Optional. - * - * @var string|null - */ - private $collapseKey = null; - - /** - * Message payload data. - * If present, the payload data it will be included in the Intent as application data, - * with the key being the extra's name. - * - * Optional. - * - * @var array|null - */ - private $data = null; - - /** - * Notification payload. - * This parameter specifies the key-value pairs of the notification payload. - * See Notification payload support for more information - * (https://developers.google.com/cloud-messaging/server-ref#notification-payload-support). - * - * Optional. - * - * @var array|null - */ - private $notification = null; - - /** - * Indicates that the message should not be sent immediately if the device is idle. - * The server will wait for the device to become active, and then only the last message - * for each collapse_key value will be sent. - * - * Optional. - * - * @var boolean - */ - private $delayWhileIdle = false; - - /** - * How long (in seconds) the message should be kept on GCM storage if the device is offline. - * - * Optional (default time-to-live is 4 weeks). - * - * @var int - */ - private $ttl = null; - - /** - * A string containing the package name of your application. - * When set, messages will only be sent to registration IDs that match the package name. - * - * Optional. - * - * @var string|null - */ - private $restrictedPackageName = null; - - /** - * On iOS, use this field to represent content-available in the APNS payload. When a - * notification or message is sent and this is set to true, an inactive client app is - * awoken. On Android, data messages wake the app by default. - * - * Optional. - * - * @var bool - */ - private $contentAvailable = true; - - /** - * Allows developers to test their request without actually sending a message. - * - * Optional. - * - * @var boolean - */ - private $dryRun = false; - - public function __construct($registrationIds = null, $data = null, $collapseKey = null) - { - $this->bulkSet($registrationIds, $data, $collapseKey); - } - - /** - * Set multiple fields at once. - * - * @param string[] $registrationIds - * @param array|null $data - * @param string|null $collapseKey - */ - public function bulkSet($registrationIds = array(), $data = null, $collapseKey = null) - { - $this->setRegistrationIds($registrationIds); - $this->setData($data); - $this->setCollapseKey($collapseKey); - } - - public function getRegistrationIds() - { - return $this->registrationIds; - } - - public function setRegistrationIds($registrationIds) - { - $this->registrationIds = $registrationIds; - return $this; - } - - public function getCollapseKey() - { - return $this->collapseKey; - } - - public function setCollapseKey($collapseKey) - { - $this->collapseKey = $collapseKey; - return $this; - } - - public function getData() - { - return $this->data; - } - - public function setData($data) - { - $this->data = $data; - return $this; - } - - public function getNotification() - { - return $this->notification; - } - - public function setNotification($notification) - { - $this->notification = $notification; - return $this; - } - - public function getDelayWhileIdle() - { - return $this->delayWhileIdle; - } - - public function setDelayWhileIdle($delayWhileIdle) - { - $this->delayWhileIdle = $delayWhileIdle; - return $this; - } - - public function getTtl() - { - return $this->ttl; - } - - public function setTtl($ttl) - { - $this->ttl = $ttl; - return $this; - } - - public function getRestrictedPackageName() - { - return $this->restrictedPackageName; - } - - public function setRestrictedPackageName($restrictedPackageName) - { - $this->restrictedPackageName = $restrictedPackageName; - return $this; - } - - public function getDryRun() - { - return $this->dryRun; - } - - public function setDryRun($dryRun) - { - $this->dryRun = $dryRun; - return $this; - } - - public function getContentAvailable() - { - return $this->contentAvailable; - } - - public function setContentAvailable($contentAvailable) - { - $this->contentAvailable = $contentAvailable; - return $this; - } -} From 79cf163a60daa6ffc82370ba281db6cb44c758fc Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 23:01:14 -0800 Subject: [PATCH 36/62] Delete Response.php --- Response.php | 294 --------------------------------------------------- 1 file changed, 294 deletions(-) delete mode 100644 Response.php diff --git a/Response.php b/Response.php deleted file mode 100644 index 38204de..0000000 --- a/Response.php +++ /dev/null @@ -1,294 +0,0 @@ -responseHeaders = $responseHeaders; - $this->mustRetry = false; - - foreach ($responseHeaders as $header) { - if (strpos($header, 'Retry-After') !== false) { - $this->mustRetry = true; - $this->waitSeconds = (int) explode(" ", $header)[1]; - break; - } - } - - $data = \json_decode($responseBody, true); - if ($data === null) { - throw new Exception("Malformed reponse body. ". $responseBody, Exception::MALFORMED_RESPONSE); - } - $this->multicastId = $data['multicast_id']; - $this->failure = $data['failure']; - $this->success = $data['success']; - $this->canonicalIds = $data['canonical_ids']; - $this->existsInvalidDataKey = false; - $this->existsMismatchSenderId = false; - $this->results = array(); - - foreach ($message->getRegistrationIds() as $key => $registrationId) { - $result = $data['results'][$key]; - if (isset($result['error'])) { - switch ($result['error']) { - case "InvalidDataKey": - $this->existsInvalidDataKey = true; - break; - case "MismatchSenderId": - $this->existsMismatchSenderId = true; - break; - } - } - $this->results[$registrationId] = $result; - } - $result = null; - } - - public function getResponseHeaders() - { - return $this->responseHeaders; - } - - public function getMulticastId() - { - return $this->multicastId; - } - - public function getMustRetry() - { - return $this->mustRetry; - } - - public function getWaitSeconds() - { - return $this->waitSeconds; - } - - public function getSuccessCount() - { - return $this->success; - } - - public function getFailureCount() //both implementation errors and server errors are included here. - { - return $this->failure; - } - - public function getExistsInvalidDataKey() - { - return $this->existsInvalidDataKey; - } - - public function getExistsMismatchSenderId() - { - return $this->existsMismatchSenderId; - } - - public function getNewRegistrationIdsCount() - { - return $this->canonicalIds; - } - - public function getResults() - { - return $this->results; - } - - /** - * Return an array of expired registration ids linked to new id - * All old registration ids must be updated to new ones in DB - * - * @return array oldRegistrationId => newRegistrationId - */ - public function getNewRegistrationIds() - { - if ($this->getNewRegistrationIdsCount() == 0) { - return array(); - } - $filteredResults = array_filter( - $this->results, - function ($result) { - return isset($result['registration_id']); - } - ); - - $data = array_map(function ($result) { - return $result['registration_id']; - }, $filteredResults); - - return $data; - } - - /** - * Returns an array containing invalid registration ids - * They must be removed from DB because the application was uninstalled from the device. - * - * @return array - */ - public function getInvalidRegistrationIds() - { - if ($this->getFailureCount() == 0) { - return array(); - } - $filteredResults = array_filter( - $this->results, - function ($result) { - return ( - isset($result['error']) - && - ( - ($result['error'] == "NotRegistered") - || - ($result['error'] == "InvalidRegistration") - ) - ); - } - ); - - return array_keys($filteredResults); - } - - - /** - * Returns an array of registration ids for which you must resend a message (?), - * cause devices aren't available now. - * - * @TODO: check if it be auto sended later - * - * @return array - */ - public function getUnavailableRegistrationIds() - { - if ($this->getFailureCount() == 0) { - return array(); - } - $filteredResults = array_filter( - $this->results, - function ($result) { - return ( - isset($result['error']) - && - ( - ($result['error'] == "Unavailable") - || - ($result['error'] == "InternalServerError") - || - ($result['error'] == "DeviceMessageRateExceeded") - ) - ); - } - ); - - return array_keys($filteredResults); - } - - /** - * Returns an array of registration ids who registered - * for pushes using the wrong senderId. - * - * @return array - */ - public function getMismatchSenderIdIds() - { - if ($this->getFailureCount() == 0) { - return array(); - } - $filteredResults = array_filter( - $this->results, - function ($result) { - return ( - isset($result['error']) - && - ($result['error'] == "MismatchSenderId") - ); - } - ); - - return array_keys($filteredResults); - } -} From a5cdd5ee21d330d06a53946bc1782bb17e482aac Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 23:01:25 -0800 Subject: [PATCH 37/62] Delete Sender.php --- Sender.php | 202 ----------------------------------------------------- 1 file changed, 202 deletions(-) delete mode 100644 Sender.php diff --git a/Sender.php b/Sender.php deleted file mode 100644 index 727b6db..0000000 --- a/Sender.php +++ /dev/null @@ -1,202 +0,0 @@ - - */ -class Sender -{ - - /** - * GCM endpoint - * - * @var string - */ - private $gcmUrl = 'https://android.googleapis.com/gcm/send'; - - /** - * Path to CA file (due to cURL 7.10 changes; you can get it from here: http://curl.haxx.se/docs/caextract.html) - * - * @var string - */ - private $caInfoPath = false; - - /** - * An API key that gives the application server authorized access to Google services. - * - * @var string - */ - private $serverApiKey = false; - - public function __construct($serverApiKey, $gcmUrl = false, $caInfoPath = false) - { - $this->serverApiKey = $serverApiKey; - if ($gcmUrl) { - $this->gcmUrl = $gcmUrl; - } - if ($caInfoPath) { - $this->caInfoPath = $caInfoPath; - } - } - - /** - * Send message to GCM without explicitly created message - * - * @param string[] $registrationIds - * @param array|null $data - * @param string|null $collapseKey - * - * @throws \CodeMonkeysRu\GCM\Exception - * @return \CodeMonkeysRu\GCM\Response - */ - public function sendMessage() - { - $message = new \CodeMonkeysRu\GCM\Message(); - call_user_func_array(array($message, 'bulkSet'), func_get_args()); - return $this->send($message); - } - - /** - * Send message to GCM - * - * @param \CodeMonkeysRu\GCM\Message $message - * @throws \CodeMonkeysRu\GCM\Exception - * @return \CodeMonkeysRu\GCM\Response - */ - public function send(Message $message) - { - - if (!$this->serverApiKey) { - throw new Exception("Server API Key not set", Exception::ILLEGAL_API_KEY); - } - - //GCM response: Number of messages on bulk (1001) exceeds maximum allowed (1000) - if (count($message->getRegistrationIds()) > 1000) { - throw new Exception( - "Malformed request: Registration Ids exceed the GCM imposed limit of 1000", - Exception::MALFORMED_REQUEST - ); - } - - $rawData = $this->formMessageData($message); - $this->validatePayloadSize($rawData, 'data', 4096); - $this->validatePayloadSize($rawData, 'notification', 2048); - $data = json_encode($rawData); - - $headers = array( - 'Authorization: key='.$this->serverApiKey, - 'Content-Type: application/json' - ); - - $ch = curl_init(); - - curl_setopt($ch, CURLOPT_URL, $this->gcmUrl); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HEADER, 1); // return HTTP headers with response - - if ($this->caInfoPath !== false) { - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); - curl_setopt($ch, CURLOPT_CAINFO, $this->caInfoPath); - } else { - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - } - - curl_setopt($ch, CURLOPT_POSTFIELDS, $data); - - $resp = curl_exec($ch); - - if ($resp === false) { - throw new Exception('Error connecting to GCM endpoint: '.curl_error($ch), Exception::UNKNOWN_ERROR); - } - - list($responseHeaders, $resultBody) = explode("\r\n\r\n", $resp, 2); - // $headers now has a string of the HTTP headers - // $resultBody is the body of the HTTP response - - $responseHeaders = explode("\n", $responseHeaders); - - $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - - curl_close($ch); - - switch ($resultHttpCode) { - case "200": - //All fine. Continue response processing. - break; - - case "400": - throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); - break; - - case "401": - throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); - break; - - default: - //TODO: Retry-after - throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); - break; - } - - return new Response($message, $resultBody, $responseHeaders); - } - - /** - * Form raw message data for sending to GCM - * - * @param \CodeMonkeysRu\GCM\Message $message - * @return array - */ - private function formMessageData(Message $message) - { - $data = array( - 'registration_ids' => $message->getRegistrationIds(), - ); - - $dataFields = array( - 'registration_ids' => 'getRegistrationIds', - 'collapse_key' => 'getCollapseKey', - 'data' => 'getData', - 'notification' => 'getNotification', - 'delay_while_idle' => 'getDelayWhileIdle', - 'time_to_live' => 'getTtl', - 'restricted_package_name' => 'getRestrictedPackageName', - 'dry_run' => 'getDryRun', - 'content_available' => 'getContentAvailable' - ); - - foreach ($dataFields as $fieldName => $getter) { - if ($message->$getter() != null) { - $data[$fieldName] = $message->$getter(); - } - } - - return $data; - } - - /** - * Validate size of json representation of passed payload - * - * @param array $rawData - * @param string $fieldName - * @param int $maxSize - * @throws \CodeMonkeysRu\GCM\Exception - * @return void - */ - private function validatePayloadSize(array $rawData, $fieldName, $maxSize) - { - if (!isset($rawData[$fieldName])) { - return; - } - if (strlen(json_encode($rawData[$fieldName])) > $maxSize) { - throw new Exception( - ucfirst($fieldName)." payload is to big (max {$maxSize} bytes)", - Exception::MALFORMED_REQUEST - ); - } - } -} From 5470a0c2dc3cd40b301eb14ba2967975ab23ee5c Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 23:02:05 -0800 Subject: [PATCH 38/62] Respond to comments --- library/CodeMonkeysRu/GCM/Exception.php | 3 +- library/CodeMonkeysRu/GCM/Message.php | 4 +- library/CodeMonkeysRu/GCM/Response.php | 119 ++++++++++++------------ library/CodeMonkeysRu/GCM/Sender.php | 31 +++--- 4 files changed, 82 insertions(+), 75 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Exception.php b/library/CodeMonkeysRu/GCM/Exception.php index baa71fb..9f97648 100644 --- a/library/CodeMonkeysRu/GCM/Exception.php +++ b/library/CodeMonkeysRu/GCM/Exception.php @@ -10,6 +10,5 @@ class Exception extends \Exception const UNKNOWN_ERROR = 4; const MALFORMED_RESPONSE = 5; const INVALID_DATA_KEY = 6; - const CURL_ERROR = 7; - const MISMATCH_SENDER_ID = 8; + const MISMATCH_SENDER_ID = 7; } diff --git a/library/CodeMonkeysRu/GCM/Message.php b/library/CodeMonkeysRu/GCM/Message.php index f116005..4df132f 100644 --- a/library/CodeMonkeysRu/GCM/Message.php +++ b/library/CodeMonkeysRu/GCM/Message.php @@ -54,7 +54,7 @@ class Message * @var array|null */ private $notification = null; - + /** * Indicates that the message should not be sent immediately if the device is idle. * The server will wait for the device to become active, and then only the last message @@ -156,7 +156,7 @@ public function setData($data) $this->data = $data; return $this; } - + public function getNotification() { return $this->notification; diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 203b41e..38204de 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -38,32 +38,32 @@ class Response * @var string[] */ private $responseHeaders = []; - + /** * Did Google demand that we try again. * * @var boolean */ private $mustRetry = false; - + /** * Number of seconds to wait. * * @var integer */ private $waitSeconds = null; - + /** * Did you use a reserved data key? * * @var boolean */ private $existsInvalidDataKey = false; - + /** * Did one of your clients register with the wrong senderId? * If one of them did, then presumably they all did. - * + * * @var boolean */ private $existsMismatchSenderId = false; @@ -76,11 +76,12 @@ class Response * message_id: String representing the message when it was successfully processed. * registration_id: If set, means that GCM processed the message but it has another canonical * registration ID for that device, so sender should replace the IDs on future requests - * (otherwise they might be rejected). This field is never set if there is an error in the request. + * (otherwise they might be rejected). This field is never set if + * there is an error in the request. * error: String describing an error that occurred while processing the message for that recipient. * The possible values are the same as documented in the above table, plus "Unavailable" * (meaning GCM servers were busy and could not process the message for that particular recipient, - * so it could be retried). + * so it could be retried, or the device rate is exceeded and you should wait a bit). * * @var array */ @@ -89,20 +90,19 @@ class Response public function __construct(Message $message, $responseBody, $responseHeaders) { $this->responseHeaders = $responseHeaders; - - $this->mustRetry = false; - - foreach($responseHeaders as $header) { + $this->mustRetry = false; + + foreach ($responseHeaders as $header) { if (strpos($header, 'Retry-After') !== false) { $this->mustRetry = true; - $this->waitSeconds = (int) explode(" ", $header)[1]; - break; - } - } - + $this->waitSeconds = (int) explode(" ", $header)[1]; + break; + } + } + $data = \json_decode($responseBody, true); if ($data === null) { - throw new Exception("Malformed reponse body. ".$responseBody, Exception::MALFORMED_RESPONSE); + throw new Exception("Malformed reponse body. ". $responseBody, Exception::MALFORMED_RESPONSE); } $this->multicastId = $data['multicast_id']; $this->failure = $data['failure']; @@ -115,23 +115,22 @@ public function __construct(Message $message, $responseBody, $responseHeaders) foreach ($message->getRegistrationIds() as $key => $registrationId) { $result = $data['results'][$key]; if (isset($result['error'])) { - switch ($result['error']) { - case "InvalidDataKey": - $this->existsInvalidDataKey = true; - break; - case "MismatchSenderId": - $this->existsMismatchSenderId = true; - break; - default: - break; - } - } - $this->results[$registrationId] = $result; + switch ($result['error']) { + case "InvalidDataKey": + $this->existsInvalidDataKey = true; + break; + case "MismatchSenderId": + $this->existsMismatchSenderId = true; + break; + } + } + $this->results[$registrationId] = $result; } $result = null; } - public function getResponseHeaders() { + public function getResponseHeaders() + { return $this->responseHeaders; } @@ -139,12 +138,12 @@ public function getMulticastId() { return $this->multicastId; } - + public function getMustRetry() { return $this->mustRetry; } - + public function getWaitSeconds() { return $this->waitSeconds; @@ -155,21 +154,16 @@ public function getSuccessCount() return $this->success; } - /** - * Both implementation errors and server errors are included here. - * - * @return integer - */ - public function getFailureCount() + public function getFailureCount() //both implementation errors and server errors are included here. { return $this->failure; } - + public function getExistsInvalidDataKey() { return $this->existsInvalidDataKey; } - + public function getExistsMismatchSenderId() { return $this->existsMismatchSenderId; @@ -179,12 +173,12 @@ public function getNewRegistrationIdsCount() { return $this->canonicalIds; } - + public function getResults() { return $this->results; } - + /** * Return an array of expired registration ids linked to new id * All old registration ids must be updated to new ones in DB @@ -196,14 +190,16 @@ public function getNewRegistrationIds() if ($this->getNewRegistrationIdsCount() == 0) { return array(); } - $filteredResults = array_filter($this->results, - function($result) { + $filteredResults = array_filter( + $this->results, + function ($result) { return isset($result['registration_id']); - }); + } + ); - $data = array_map(function($result) { + $data = array_map(function ($result) { return $result['registration_id']; - }, $filteredResults); + }, $filteredResults); return $data; } @@ -219,8 +215,9 @@ public function getInvalidRegistrationIds() if ($this->getFailureCount() == 0) { return array(); } - $filteredResults = array_filter($this->results, - function($result) { + $filteredResults = array_filter( + $this->results, + function ($result) { return ( isset($result['error']) && @@ -230,7 +227,8 @@ function($result) { ($result['error'] == "InvalidRegistration") ) ); - }); + } + ); return array_keys($filteredResults); } @@ -249,8 +247,9 @@ public function getUnavailableRegistrationIds() if ($this->getFailureCount() == 0) { return array(); } - $filteredResults = array_filter($this->results, - function($result) { + $filteredResults = array_filter( + $this->results, + function ($result) { return ( isset($result['error']) && @@ -262,29 +261,33 @@ function($result) { ($result['error'] == "DeviceMessageRateExceeded") ) ); - }); + } + ); return array_keys($filteredResults); } - + /** * Returns an array of registration ids who registered * for pushes using the wrong senderId. * * @return array */ - public function getMismatchSenderIdIds() { + public function getMismatchSenderIdIds() + { if ($this->getFailureCount() == 0) { return array(); } - $filteredResults = array_filter($this->results, - function($result) { + $filteredResults = array_filter( + $this->results, + function ($result) { return ( isset($result['error']) && ($result['error'] == "MismatchSenderId") ); - }); + } + ); return array_keys($filteredResults); } diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index f811e8b..727b6db 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -18,7 +18,7 @@ class Sender /** * Path to CA file (due to cURL 7.10 changes; you can get it from here: http://curl.haxx.se/docs/caextract.html) - * + * * @var string */ private $caInfoPath = false; @@ -74,9 +74,12 @@ public function send(Message $message) //GCM response: Number of messages on bulk (1001) exceeds maximum allowed (1000) if (count($message->getRegistrationIds()) > 1000) { - throw new Exception("Malformed request: Registration Ids exceed the GCM imposed limit of 1000", Exception::MALFORMED_REQUEST); + throw new Exception( + "Malformed request: Registration Ids exceed the GCM imposed limit of 1000", + Exception::MALFORMED_REQUEST + ); } - + $rawData = $this->formMessageData($message); $this->validatePayloadSize($rawData, 'data', 4096); $this->validatePayloadSize($rawData, 'notification', 2048); @@ -94,32 +97,32 @@ public function send(Message $message) curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, 1); // return HTTP headers with response - + if ($this->caInfoPath !== false) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_CAINFO, $this->caInfoPath); } else { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $resp = curl_exec($ch); - if ($resp === FALSE) { - throw new Exception('cURL error: '. curl_error($ch), Exception::CURL_ERROR); + if ($resp === false) { + throw new Exception('Error connecting to GCM endpoint: '.curl_error($ch), Exception::UNKNOWN_ERROR); } - + list($responseHeaders, $resultBody) = explode("\r\n\r\n", $resp, 2); // $headers now has a string of the HTTP headers // $resultBody is the body of the HTTP response $responseHeaders = explode("\n", $responseHeaders); - + $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); - + switch ($resultHttpCode) { case "200": //All fine. Continue response processing. @@ -138,7 +141,7 @@ public function send(Message $message) throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); break; } - + return new Response($message, $resultBody, $responseHeaders); } @@ -174,7 +177,7 @@ private function formMessageData(Message $message) return $data; } - + /** * Validate size of json representation of passed payload * @@ -186,7 +189,9 @@ private function formMessageData(Message $message) */ private function validatePayloadSize(array $rawData, $fieldName, $maxSize) { - if (!isset($rawData[$fieldName])) return; + if (!isset($rawData[$fieldName])) { + return; + } if (strlen(json_encode($rawData[$fieldName])) > $maxSize) { throw new Exception( ucfirst($fieldName)." payload is to big (max {$maxSize} bytes)", From c8fb0004ae40167d489308826a857004f5ddf41c Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 23:10:34 -0800 Subject: [PATCH 39/62] Add files via upload --- library/CodeMonkeysRu/GCM/Message.php | 4 ++-- library/CodeMonkeysRu/GCM/Response.php | 9 ++++++--- library/CodeMonkeysRu/GCM/Sender.php | 10 +++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Message.php b/library/CodeMonkeysRu/GCM/Message.php index 4df132f..f116005 100644 --- a/library/CodeMonkeysRu/GCM/Message.php +++ b/library/CodeMonkeysRu/GCM/Message.php @@ -54,7 +54,7 @@ class Message * @var array|null */ private $notification = null; - + /** * Indicates that the message should not be sent immediately if the device is idle. * The server will wait for the device to become active, and then only the last message @@ -156,7 +156,7 @@ public function setData($data) $this->data = $data; return $this; } - + public function getNotification() { return $this->notification; diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 38204de..e893477 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -1,6 +1,9 @@ +*/ class Response { @@ -153,7 +156,7 @@ public function getSuccessCount() { return $this->success; } - + public function getFailureCount() //both implementation errors and server errors are included here. { return $this->failure; @@ -173,12 +176,12 @@ public function getNewRegistrationIdsCount() { return $this->canonicalIds; } - + public function getResults() { return $this->results; } - + /** * Return an array of expired registration ids linked to new id * All old registration ids must be updated to new ones in DB diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index 727b6db..d43463a 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -79,7 +79,7 @@ public function send(Message $message) Exception::MALFORMED_REQUEST ); } - + $rawData = $this->formMessageData($message); $this->validatePayloadSize($rawData, 'data', 4096); $this->validatePayloadSize($rawData, 'notification', 2048); @@ -104,7 +104,7 @@ public function send(Message $message) } else { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $resp = curl_exec($ch); @@ -118,7 +118,7 @@ public function send(Message $message) // $resultBody is the body of the HTTP response $responseHeaders = explode("\n", $responseHeaders); - + $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); @@ -141,7 +141,7 @@ public function send(Message $message) throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); break; } - + return new Response($message, $resultBody, $responseHeaders); } @@ -177,7 +177,7 @@ private function formMessageData(Message $message) return $data; } - + /** * Validate size of json representation of passed payload * From 3190ea4a2af1e5606780e183050a8cc9c76c7998 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 23:13:01 -0800 Subject: [PATCH 40/62] Add files via upload --- library/CodeMonkeysRu/GCM/Response.php | 4 ++-- library/CodeMonkeysRu/GCM/Sender.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index e893477..f0dcaa4 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -2,8 +2,8 @@ namespace CodeMonkeysRu\GCM; /** -* @author Vladimir Savenkov -*/ + * @author Vladimir Savenkov + */ class Response { diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index d43463a..220ae87 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -122,7 +122,7 @@ public function send(Message $message) $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); - + switch ($resultHttpCode) { case "200": //All fine. Continue response processing. From 268de47e1eaf2e22973923cbb95e8eeab82c76c9 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Tue, 10 Jan 2017 23:17:20 -0800 Subject: [PATCH 41/62] Add files via upload --- library/CodeMonkeysRu/GCM/Response.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index f0dcaa4..4a0da66 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -157,7 +157,12 @@ public function getSuccessCount() return $this->success; } - public function getFailureCount() //both implementation errors and server errors are included here. + /** + * Both implementation errors and server errors are included here. + * + * @return integer + */ + public function getFailureCount() { return $this->failure; } From 68eea46ecb743d43c91279c9f35940dcfccbf258 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Fri, 13 Jan 2017 21:35:02 -0800 Subject: [PATCH 42/62] Strip out "\r" from headers too --- library/CodeMonkeysRu/GCM/Sender.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index 220ae87..4f0df9b 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -117,7 +117,7 @@ public function send(Message $message) // $headers now has a string of the HTTP headers // $resultBody is the body of the HTTP response - $responseHeaders = explode("\n", $responseHeaders); + $responseHeaders = explode("\r\n", $responseHeaders); $resultHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); From bcb07c953d5adee83e530997321111759e206abe Mon Sep 17 00:00:00 2001 From: dommccarty Date: Fri, 13 Jan 2017 22:06:51 -0800 Subject: [PATCH 43/62] Includes colon now. --- library/CodeMonkeysRu/GCM/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 4a0da66..f358d46 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -96,7 +96,7 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $this->mustRetry = false; foreach ($responseHeaders as $header) { - if (strpos($header, 'Retry-After') !== false) { + if (strpos($header, 'Retry-After:') !== false) { $this->mustRetry = true; $this->waitSeconds = (int) explode(" ", $header)[1]; break; From 8fecb9908a1be682be8630dd8027e96b18399b1d Mon Sep 17 00:00:00 2001 From: dommccarty Date: Fri, 13 Jan 2017 22:18:09 -0800 Subject: [PATCH 44/62] change ->notification to ->setNotification --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e2ace8..3b77b2d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ $message = new GCM\Message( ); $message - ->notification(array("title" => "foo", "body" => "bar")) + ->setNotification(array("title" => "foo", "body" => "bar")) ->setCollapseKey("collapse_key") ->setDelayWhileIdle(true) ->setTtl(123) From 4b334530ebc610b57c9c163b0e33a5e0ea9ee2ae Mon Sep 17 00:00:00 2001 From: dommccarty Date: Fri, 13 Jan 2017 23:47:31 -0800 Subject: [PATCH 45/62] Add files via upload --- README.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3b77b2d..7da99ab 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,6 @@ $message try { $response = $sender->send($message); - if ($response->getMustRetry() { - $waitSeconds = $response->getWaitSeconds(); - //Try again after that many seconds, and use exponential backoff subsequently, as needed. - //TODO - } - if ($response->getNewRegistrationIdsCount() > 0) { $newRegistrationIds = $response->getNewRegistrationIds(); foreach ($newRegistrationIds as $oldRegistrationId => $newRegistrationId){ @@ -73,10 +67,17 @@ try { } catch (GCM\Exception $e) { switch ($e->getCode()) { + + case GCM\Exception::UNKNOWN_ERROR: + if ($e->getMustRetry()) { + $waitSeconds = $e->getWaitSeconds(); + //retry in that many seconds, and use exponential back-off subsequently. + //TODO + break; + } case GCM\Exception::ILLEGAL_API_KEY: case GCM\Exception::AUTHENTICATION_ERROR: - case GCM\Exception::MALFORMED_REQUEST: - case GCM\Exception::UNKNOWN_ERROR: + case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::MALFORMED_RESPONSE: case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes @@ -102,12 +103,6 @@ try { "collapse_key" ); - if ($response->getMustRetry() { - $waitSeconds = $response->getWaitSeconds(); - //Try again after that many seconds, and use exponential backoff subsequently, as needed. - //TODO - } - if ($response->getNewRegistrationIdsCount() > 0) { $newRegistrationIds = $response->getNewRegistrationIds(); foreach ($newRegistrationIds as $oldRegistrationId => $newRegistrationId){ @@ -144,10 +139,17 @@ try { } catch (GCM\Exception $e) { switch ($e->getCode()) { + + case GCM\Exception::UNKNOWN_ERROR: + if ($e->getMustRetry()) { + $waitSeconds = $e->getWaitSeconds(); + //retry in that many seconds, and use exponential back-off subsequently. + //TODO + break; + } case GCM\Exception::ILLEGAL_API_KEY: case GCM\Exception::AUTHENTICATION_ERROR: - case GCM\Exception::MALFORMED_REQUEST: - case GCM\Exception::UNKNOWN_ERROR: + case GCM\Exception::MALFORMED_REQUEST: case GCM\Exception::MALFORMED_RESPONSE: case GCM\Exception::INVALID_DATA_KEY: //you used a forbidden key in the notification case GCM\Exception::MISMATCH_SENDER_ID; //a client sent the wrong senderId when it registered for pushes From d05d88f21667918a2a050cde4e2edca39a07aa0d Mon Sep 17 00:00:00 2001 From: dommccarty Date: Fri, 13 Jan 2017 23:50:47 -0800 Subject: [PATCH 46/62] Add files via upload --- tests/ExceptionTest.php | 34 ++++++++++++++++ tests/ResponseTest.php | 90 +++++++++++++++++++++++++++++++++++------ tests/SenderTest.php | 9 +++-- tests/bootstrap.php | 6 +-- 4 files changed, 118 insertions(+), 21 deletions(-) create mode 100644 tests/ExceptionTest.php diff --git a/tests/ExceptionTest.php b/tests/ExceptionTest.php new file mode 100644 index 0000000..3edc14e --- /dev/null +++ b/tests/ExceptionTest.php @@ -0,0 +1,34 @@ +setMustRetry(true); + $exception->setWaitSeconds(120); + + $this->exception = $exception; + } + + public function testGetMustRetry() + { + $this->assertEquals(true, $this->exception->getMustRetry()); + } + + public function testGetWaitSeconds() + { + $this->assertEquals(120, $this->exception->getWaitSeconds(); + } +} diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index c3ea557..3b1570a 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -1,20 +1,44 @@ responseHeadersOK = $responseHeadersOK; + $this->responseOK = new \CodeMonkeysRu\GCM\Response($messageOK, $responseBodyOK, $responseHeadersOK); + + $messageInvalidDataKey = new \CodeMonkeysRu\GCM\Message(array(1, 2)); + $responseBodyInvalidDataKey = '{ "multicast_id": 216, + "success": 0, + "failure": 2, + "canonical_ids": 0, + "results": [ + { "error": "InvalidDataKey" }, + { "error": "InvalidDataKey" } + ] + }'; + + $this->responseInvalidDataKey = new \CodeMonkeysRu\GCM\Response($messageInvalidDataKey, $responseBodyInvalidDataKey, $responseHeadersOK); + } - $this->response = new \CodeMonkeysRu\GCM\Response($message, $responseBody); + public function testGetResponseHeaders() + { + $this->assertEquals($this->responseHeadersOK, $this->responseOK->getResponseHeaders()); } public function testGetNewRegistrationIds() { - $this->assertEquals(array(5 => 32), $this->response->getNewRegistrationIds()); + $this->assertEquals(array(5 => 32), $this->responseOK->getNewRegistrationIds()); } public function testGetInvalidRegistrationIds() { - $this->assertEquals(array(3, 6), $this->response->getInvalidRegistrationIds()); + $this->assertEquals(array(3, 6), $this->responseOK->getInvalidRegistrationIds()); } public function testGetUnavailableRegistrationIds() { - $this->assertEquals(array(2), $this->response->getUnavailableRegistrationIds()); + $this->assertEquals(array(2), $this->responseOK->getUnavailableRegistrationIds()); } - -} \ No newline at end of file + + public function testGetExistsMismatchSenderIdYes() + { + $this->assertEquals(true, $this->responseOK->getExistsMismatchSenderId()); + } + public function testGetExistsMismatchSenderIdNo() + { + $this->assertEquals(false, $this->responseInvalidDataKey->getExistsMismatchSenderId()); + } + public function testGetMismatchSenderIdIds() + { + $this->assertEquals(array(7), $this->responseOK->getMismatchSenderIdIds()); + } + public function testGetExistsInvalidDataKeyYes() + { + $this->assertEquals(true, $this->responseInvalidDataKey->getExistsInvalidDataKey()); + } + public function testGetExistsInvalidDataKeyNo() + { + $this->assertEquals(false, $this->responseOK->getExistsInvalidDataKey()); + } +} diff --git a/tests/SenderTest.php b/tests/SenderTest.php index f3a0649..b5c6ea1 100644 --- a/tests/SenderTest.php +++ b/tests/SenderTest.php @@ -1,6 +1,10 @@ setNotification($notification); $sender->send($message); } - -} \ No newline at end of file +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 2657061..51bede3 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,6 +1,2 @@ Date: Fri, 13 Jan 2017 23:51:57 -0800 Subject: [PATCH 47/62] Slimming down --- library/CodeMonkeysRu/GCM/Exception.php | 20 +++++++++ library/CodeMonkeysRu/GCM/Message.php | 4 +- library/CodeMonkeysRu/GCM/Response.php | 55 ++++++------------------- library/CodeMonkeysRu/GCM/Sender.php | 34 +++++++-------- 4 files changed, 51 insertions(+), 62 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Exception.php b/library/CodeMonkeysRu/GCM/Exception.php index 9f97648..d274ee9 100644 --- a/library/CodeMonkeysRu/GCM/Exception.php +++ b/library/CodeMonkeysRu/GCM/Exception.php @@ -11,4 +11,24 @@ class Exception extends \Exception const MALFORMED_RESPONSE = 5; const INVALID_DATA_KEY = 6; const MISMATCH_SENDER_ID = 7; + + private $mustRetry = false; + private $waitSeconds = null; + + public function setMustRetry($bool) + { + $this->mustRetry = $bool; + } + public function getMustRetry() + { + return $this->mustRetry; + } + public function setWaitSeconds($int) + { + $this->waitSeconds = $int; + } + public function getWaitSeconds() + { + return $this->waitSeconds; + } } diff --git a/library/CodeMonkeysRu/GCM/Message.php b/library/CodeMonkeysRu/GCM/Message.php index f116005..c7c3815 100644 --- a/library/CodeMonkeysRu/GCM/Message.php +++ b/library/CodeMonkeysRu/GCM/Message.php @@ -113,8 +113,8 @@ public function __construct($registrationIds = null, $data = null, $collapseKey /** * Set multiple fields at once. * - * @param string[] $registrationIds - * @param array|null $data + * @param string[] $registrationIds + * @param array|null $data * @param string|null $collapseKey */ public function bulkSet($registrationIds = array(), $data = null, $collapseKey = null) diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index f358d46..1a34d1c 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -42,20 +42,6 @@ class Response */ private $responseHeaders = []; - /** - * Did Google demand that we try again. - * - * @var boolean - */ - private $mustRetry = false; - - /** - * Number of seconds to wait. - * - * @var integer - */ - private $waitSeconds = null; - /** * Did you use a reserved data key? * @@ -93,19 +79,10 @@ class Response public function __construct(Message $message, $responseBody, $responseHeaders) { $this->responseHeaders = $responseHeaders; - $this->mustRetry = false; - - foreach ($responseHeaders as $header) { - if (strpos($header, 'Retry-After:') !== false) { - $this->mustRetry = true; - $this->waitSeconds = (int) explode(" ", $header)[1]; - break; - } - } $data = \json_decode($responseBody, true); if ($data === null) { - throw new Exception("Malformed reponse body. ". $responseBody, Exception::MALFORMED_RESPONSE); + throw new Exception("Malformed reponse body. ".json_encode($responseHeaders).$responseBody, Exception::MALFORMED_RESPONSE); } $this->multicastId = $data['multicast_id']; $this->failure = $data['failure']; @@ -114,17 +91,17 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $this->existsInvalidDataKey = false; $this->existsMismatchSenderId = false; $this->results = array(); - + foreach ($message->getRegistrationIds() as $key => $registrationId) { $result = $data['results'][$key]; if (isset($result['error'])) { switch ($result['error']) { - case "InvalidDataKey": - $this->existsInvalidDataKey = true; - break; - case "MismatchSenderId": - $this->existsMismatchSenderId = true; - break; + case "InvalidDataKey": + $this->existsInvalidDataKey = true; + break; + case "MismatchSenderId": + $this->existsMismatchSenderId = true; + break; } } $this->results[$registrationId] = $result; @@ -141,16 +118,6 @@ public function getMulticastId() { return $this->multicastId; } - - public function getMustRetry() - { - return $this->mustRetry; - } - - public function getWaitSeconds() - { - return $this->waitSeconds; - } public function getSuccessCount() { @@ -205,9 +172,11 @@ function ($result) { } ); - $data = array_map(function ($result) { + $data = array_map( + function ($result) { return $result['registration_id']; - }, $filteredResults); + }, $filteredResults + ); return $data; } diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index 4f0df9b..95b97b6 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -44,8 +44,8 @@ public function __construct($serverApiKey, $gcmUrl = false, $caInfoPath = false) /** * Send message to GCM without explicitly created message * - * @param string[] $registrationIds - * @param array|null $data + * @param string[] $registrationIds + * @param array|null $data * @param string|null $collapseKey * * @throws \CodeMonkeysRu\GCM\Exception @@ -61,7 +61,7 @@ public function sendMessage() /** * Send message to GCM * - * @param \CodeMonkeysRu\GCM\Message $message + * @param \CodeMonkeysRu\GCM\Message $message * @throws \CodeMonkeysRu\GCM\Exception * @return \CodeMonkeysRu\GCM\Response */ @@ -124,21 +124,21 @@ public function send(Message $message) curl_close($ch); switch ($resultHttpCode) { - case "200": - //All fine. Continue response processing. - break; + case "200": + //All fine. Continue response processing. + break; - case "400": - throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); + case "400": + throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); break; - case "401": - throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); + case "401": + throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); break; - default: - //TODO: Retry-after - throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); + default: + //TODO: Retry-after + throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); break; } @@ -148,7 +148,7 @@ public function send(Message $message) /** * Form raw message data for sending to GCM * - * @param \CodeMonkeysRu\GCM\Message $message + * @param \CodeMonkeysRu\GCM\Message $message * @return array */ private function formMessageData(Message $message) @@ -181,9 +181,9 @@ private function formMessageData(Message $message) /** * Validate size of json representation of passed payload * - * @param array $rawData - * @param string $fieldName - * @param int $maxSize + * @param array $rawData + * @param string $fieldName + * @param int $maxSize * @throws \CodeMonkeysRu\GCM\Exception * @return void */ From 019602e559c3ec4fe003bbafb809f4062e0cc9cd Mon Sep 17 00:00:00 2001 From: dommccarty Date: Fri, 13 Jan 2017 23:59:39 -0800 Subject: [PATCH 48/62] Add files via upload --- library/CodeMonkeysRu/GCM/Sender.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index 95b97b6..94ae453 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -130,16 +130,26 @@ public function send(Message $message) case "400": throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); - break; + break; case "401": throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); - break; + break; default: - //TODO: Retry-after - throw new Exception("Unknown error. ".$resultBody, Exception::UNKNOWN_ERROR); - break; + $E = new Exception("Unknown error. ".json_encode($responseHeaders)."\n".$resultBody, Exception::UNKNOWN_ERROR); + + foreach ($responseHeaders as $header) { + if (strpos($header, 'Retry-After:') !== false) { + $E->setMustRetry(true); + $E->setWaitSeconds((int) explode(" ", $header)[1]); + break; + } + } + + throw $E; + //TODO: Retry-after + break; } return new Response($message, $resultBody, $responseHeaders); From b978100eccbaa57e566dead14ad5d3748ef7f339 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 00:04:48 -0800 Subject: [PATCH 49/62] Add files via upload --- tests/ResponseTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index 3b1570a..d5d62a4 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -47,7 +47,7 @@ protected function setUp() { "message_id": "1:1516" }, { "message_id": "1:2342", "registration_id": "32" }, { "error": "NotRegistered"}, - { "error": "MismatchSenderId"} + { "error": "MismatchSenderId"} ] }'; From 03db6b7d149af857c02a0eb5e5849541425dbd94 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 00:09:34 -0800 Subject: [PATCH 50/62] Add files via upload --- library/CodeMonkeysRu/GCM/Sender.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index 94ae453..f259558 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -130,11 +130,11 @@ public function send(Message $message) case "400": throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); - break; + break; case "401": throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); - break; + break; default: $E = new Exception("Unknown error. ".json_encode($responseHeaders)."\n".$resultBody, Exception::UNKNOWN_ERROR); @@ -148,8 +148,8 @@ public function send(Message $message) } throw $E; - //TODO: Retry-after - break; + //TODO: Retry-after + break; } return new Response($message, $resultBody, $responseHeaders); From 13a0bc220f2360527f99d75985b18c81fbc0a7c5 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 00:10:29 -0800 Subject: [PATCH 51/62] Add files via upload --- tests/bootstrap.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 51bede3..d3f5068 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,2 +1,5 @@ Date: Sat, 14 Jan 2017 00:17:13 -0800 Subject: [PATCH 52/62] Add files via upload --- tests/ResponseTest.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index d5d62a4..fb73352 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -12,12 +12,7 @@ class ResponseTest extends \PHPUnit_Framework_TestCase */ private $responseOK; private $responseHeadersOK; - - private $responseMustRetry; - private $responseHeadersMustRetry; - private $responseInvalidDataKey; - private $responseHeadersInvalidDataKey; protected function setUp() { From 033a9cc7f161dd6e957ca99f7e97750b74b2e9e9 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 00:19:29 -0800 Subject: [PATCH 53/62] Add files via upload --- tests/bootstrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index d3f5068..c3a2ad6 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -2,4 +2,4 @@ require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Exception.php'; require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Message.php'; require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Response.php'; -require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Sender.php'; \ No newline at end of file +require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Sender.php'; \ No newline at end of file From 45eb6ed7e7dfdf5783cfb547480bde72d1543883 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 00:21:35 -0800 Subject: [PATCH 54/62] Add files via upload --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7da99ab..fcfe817 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ try { $waitSeconds = $e->getWaitSeconds(); //retry in that many seconds, and use exponential back-off subsequently. //TODO - break; + break; } case GCM\Exception::ILLEGAL_API_KEY: case GCM\Exception::AUTHENTICATION_ERROR: @@ -145,7 +145,7 @@ try { $waitSeconds = $e->getWaitSeconds(); //retry in that many seconds, and use exponential back-off subsequently. //TODO - break; + break; } case GCM\Exception::ILLEGAL_API_KEY: case GCM\Exception::AUTHENTICATION_ERROR: From 1d942c8252a0bd12c6177b634a623f6c502099f5 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 20:35:18 -0800 Subject: [PATCH 55/62] Add files via upload --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fcfe817..6b8631f 100644 --- a/README.md +++ b/README.md @@ -43,13 +43,13 @@ try { if ($response->getExistsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } if ($response->getExistsMismatchSenderId()) { //A client sent the wrong senderId when it registered for pushes - $error_msg = 'Mismatch senderId. Problem clients are ' + $error_msg = 'Mismatch senderId. Problem clients are ' . json_encode($response->getMismatchSenderIdIds()); throw new Exception($error_msg, Exception::MISMATCH_SENDER_ID); } @@ -115,7 +115,7 @@ try { if ($response->getExistsInvalidDataKey()) { //You used a reserved data key - $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); + $error_msg = 'Invalid data key in payload. ' . json_encode($message->getNotification()); throw new Exception($error_msg, Exception::INVALID_DATA_KEY); } From 9e9dc81916672ec628f24ddb224ecde79e1815b0 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 21:53:34 -0800 Subject: [PATCH 56/62] Add files via upload --- travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 travis.yml diff --git a/travis.yml b/travis.yml new file mode 100644 index 0000000..58ff06c --- /dev/null +++ b/travis.yml @@ -0,0 +1,9 @@ +language: php +php: + - "5.6" + - "7.0" + - "7.1" +install: composer install +script: + - vendor/bin/phpunit + - vendor/bin/phpcs --standard=PSR2 library/ tests/ \ No newline at end of file From 2fa1df9d2e65c76c1ea3b64eff7c4a52b4f1d8ec Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 21:54:32 -0800 Subject: [PATCH 57/62] Rename travis.yml to .travis.yml --- travis.yml => .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename travis.yml => .travis.yml (66%) diff --git a/travis.yml b/.travis.yml similarity index 66% rename from travis.yml rename to .travis.yml index 58ff06c..e9fa033 100644 --- a/travis.yml +++ b/.travis.yml @@ -6,4 +6,4 @@ php: install: composer install script: - vendor/bin/phpunit - - vendor/bin/phpcs --standard=PSR2 library/ tests/ \ No newline at end of file + - vendor/bin/phpcs --standard=PSR2 library/ tests/ From 4c2b90a57128b27c90df511bc2d16bf554639000 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 22:17:46 -0800 Subject: [PATCH 58/62] Add files via upload --- composer.json | 52 +++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/composer.json b/composer.json index 235ffbb..bfa44b8 100644 --- a/composer.json +++ b/composer.json @@ -1,24 +1,32 @@ { - "name": "codemonkeys-ru/gcm-message", - "type": "library", - "description": "Google Cloud Messaging (GCM) PHP Server Library", - "keywords": ["GCM", "push message", "android"], - "authors": [ - { - "name": "Vladimir Savenkov", - "email": "ivariable@gmail.com", - "homepage": "http://ivariable.ru", - "role": "Developer" - } - ], - "license": "MIT", - "require": { - "php": ">=5.3.2" - }, - "minimum-stability": "dev", - "autoload": { - "psr-0": { - "CodeMonkeysRu\\GCM": "library/" - } - } + "name": "codemonkeys-ru/gcm-message", + "minimum-stability": "stable", + "type": "library", + "description": "Google Cloud Messaging (GCM) PHP Server Library", + "keywords": [ + "GCM", + "push message", + "android" + ], + "authors": [ + { + "name": "Vladimir Savenkov", + "email": "ivariable@gmail.com", + "homepage": "https://github.com/iVariable", + "role": "Maintainer" + } + ], + "license": "MIT", + "autoload": { + "psr-0": { + "CodeMonkeysRu\\GCM": "library/" + } + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "squizlabs/php_codesniffer": "2.*", + "phpunit/phpunit": "5.7.*" + } } From daa3bd4196d958943b9a387b7b304516838b4616 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 22:32:18 -0800 Subject: [PATCH 59/62] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 6b8631f..d2e2a31 100644 --- a/README.md +++ b/README.md @@ -177,8 +177,6 @@ $sender = new GCM\Sender("YOUR GOOGLE API KEY", false, "/path/to/cacert.crt"); ChangeLog ---------------------- -* v0.3 - Content-available added (https://github.com/CodeMonkeysRu/GCMMessage/pull/11) -* v0.2 - Notifications added -* v0.1 - Initial release + Licensed under MIT license. From c1dce41ab33b3635aae03309bab22accde842358 Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 22:44:09 -0800 Subject: [PATCH 60/62] Add files via upload --- tests/ExceptionTest.php | 2 +- tests/ResponseTest.php | 22 +++++++++++----------- tests/bootstrap.php | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/ExceptionTest.php b/tests/ExceptionTest.php index 3edc14e..5375a30 100644 --- a/tests/ExceptionTest.php +++ b/tests/ExceptionTest.php @@ -29,6 +29,6 @@ public function testGetMustRetry() public function testGetWaitSeconds() { - $this->assertEquals(120, $this->exception->getWaitSeconds(); + $this->assertEquals(120, $this->exception->getWaitSeconds()); } } diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index fb73352..db1c676 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -60,7 +60,11 @@ protected function setUp() ] }'; - $this->responseInvalidDataKey = new \CodeMonkeysRu\GCM\Response($messageInvalidDataKey, $responseBodyInvalidDataKey, $responseHeadersOK); + $this->responseInvalidDataKey = new \CodeMonkeysRu\GCM\Response( + $messageInvalidDataKey, + $responseBodyInvalidDataKey, + $responseHeadersOK + ); } public function testGetResponseHeaders() @@ -83,24 +87,20 @@ public function testGetUnavailableRegistrationIds() $this->assertEquals(array(2), $this->responseOK->getUnavailableRegistrationIds()); } - public function testGetExistsMismatchSenderIdYes() - { - $this->assertEquals(true, $this->responseOK->getExistsMismatchSenderId()); - } - public function testGetExistsMismatchSenderIdNo() + public function testGetExistsMismatchSenderId() { + $this->assertEquals(true, $this->responseOK->getExistsMismatchSenderId()) + && $this->assertEquals(false, $this->responseInvalidDataKey->getExistsMismatchSenderId()); } public function testGetMismatchSenderIdIds() { $this->assertEquals(array(7), $this->responseOK->getMismatchSenderIdIds()); } - public function testGetExistsInvalidDataKeyYes() - { - $this->assertEquals(true, $this->responseInvalidDataKey->getExistsInvalidDataKey()); - } - public function testGetExistsInvalidDataKeyNo() + public function testGetExistsInvalidDataKey() { + $this->assertEquals(true, $this->responseInvalidDataKey->getExistsInvalidDataKey()) + && $this->assertEquals(false, $this->responseOK->getExistsInvalidDataKey()); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c3a2ad6..52d1401 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -2,4 +2,4 @@ require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Exception.php'; require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Message.php'; require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Response.php'; -require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Sender.php'; \ No newline at end of file +require_once __DIR__.'/../library/CodeMonkeysRu/GCM/Sender.php'; From 6caf3212ef620f23fefc5e90f3aac198246f371b Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 22:44:51 -0800 Subject: [PATCH 61/62] Add files via upload --- library/CodeMonkeysRu/GCM/Exception.php | 8 ++-- library/CodeMonkeysRu/GCM/Response.php | 20 ++++++---- library/CodeMonkeysRu/GCM/Sender.php | 49 +++++++++++++------------ 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/library/CodeMonkeysRu/GCM/Exception.php b/library/CodeMonkeysRu/GCM/Exception.php index d274ee9..998af6e 100644 --- a/library/CodeMonkeysRu/GCM/Exception.php +++ b/library/CodeMonkeysRu/GCM/Exception.php @@ -16,19 +16,19 @@ class Exception extends \Exception private $waitSeconds = null; public function setMustRetry($bool) - { + { $this->mustRetry = $bool; } public function getMustRetry() - { + { return $this->mustRetry; } public function setWaitSeconds($int) - { + { $this->waitSeconds = $int; } public function getWaitSeconds() - { + { return $this->waitSeconds; } } diff --git a/library/CodeMonkeysRu/GCM/Response.php b/library/CodeMonkeysRu/GCM/Response.php index 1a34d1c..1e33ee1 100644 --- a/library/CodeMonkeysRu/GCM/Response.php +++ b/library/CodeMonkeysRu/GCM/Response.php @@ -82,7 +82,10 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $data = \json_decode($responseBody, true); if ($data === null) { - throw new Exception("Malformed reponse body. ".json_encode($responseHeaders).$responseBody, Exception::MALFORMED_RESPONSE); + throw new Exception( + "Malformed reponse body. ".json_encode($responseHeaders).$responseBody, + Exception::MALFORMED_RESPONSE + ); } $this->multicastId = $data['multicast_id']; $this->failure = $data['failure']; @@ -96,12 +99,12 @@ public function __construct(Message $message, $responseBody, $responseHeaders) $result = $data['results'][$key]; if (isset($result['error'])) { switch ($result['error']) { - case "InvalidDataKey": - $this->existsInvalidDataKey = true; - break; - case "MismatchSenderId": - $this->existsMismatchSenderId = true; - break; + case "InvalidDataKey": + $this->existsInvalidDataKey = true; + break; + case "MismatchSenderId": + $this->existsMismatchSenderId = true; + break; } } $this->results[$registrationId] = $result; @@ -175,7 +178,8 @@ function ($result) { $data = array_map( function ($result) { return $result['registration_id']; - }, $filteredResults + }, + $filteredResults ); return $data; diff --git a/library/CodeMonkeysRu/GCM/Sender.php b/library/CodeMonkeysRu/GCM/Sender.php index f259558..395f363 100644 --- a/library/CodeMonkeysRu/GCM/Sender.php +++ b/library/CodeMonkeysRu/GCM/Sender.php @@ -124,32 +124,35 @@ public function send(Message $message) curl_close($ch); switch ($resultHttpCode) { - case "200": - //All fine. Continue response processing. - break; - - case "400": - throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); - break; - - case "401": - throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); - break; - - default: - $E = new Exception("Unknown error. ".json_encode($responseHeaders)."\n".$resultBody, Exception::UNKNOWN_ERROR); + case "200": + //All fine. Continue response processing. + break; + + case "400": + throw new Exception('Malformed request. '.$resultBody, Exception::MALFORMED_REQUEST); + break; + + case "401": + throw new Exception('Authentication Error. '.$resultBody, Exception::AUTHENTICATION_ERROR); + break; + + default: + $E = new Exception( + "Unknown error. ".json_encode($responseHeaders)."\n".$resultBody, + Exception::UNKNOWN_ERROR + ); - foreach ($responseHeaders as $header) { - if (strpos($header, 'Retry-After:') !== false) { - $E->setMustRetry(true); - $E->setWaitSeconds((int) explode(" ", $header)[1]); - break; + foreach ($responseHeaders as $header) { + if (strpos($header, 'Retry-After:') !== false) { + $E->setMustRetry(true); + $E->setWaitSeconds((int) explode(" ", $header)[1]); + break; + } } - } - throw $E; - //TODO: Retry-after - break; + throw $E; + //TODO: Retry-after + break; } return new Response($message, $resultBody, $responseHeaders); From bc3723cd90c5900a5eaad763027fd2e215ba53ea Mon Sep 17 00:00:00 2001 From: dommccarty Date: Sat, 14 Jan 2017 22:48:18 -0800 Subject: [PATCH 62/62] Added Travis CI build status icon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d2e2a31..6bbad73 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Google Cloud Messaging (GCM) PHP Server Library -------------------------------------------- -A PHP library for sending messages to devices registered through Google Cloud Messaging. +A PHP library for sending messages to devices registered through Google Cloud Messaging. [![Build Status](https://travis-ci.org/dommccarty/GCMMessage.svg?branch=master)](https://travis-ci.org/dommccarty/GCMMessage) See: http://developer.android.com/guide/google/gcm/index.html