I am facing the problem with GCM push notification. I am getting the following error.
{
"multicast_id":4630467710672911593,
"success":0,
"failure":1,
"canonical_ids":0,
"results":[{
"error":"MismatchSenderId"
}]
}
Following is the code. Any help would be really appreciated. Thanks in Advance.
public function gcmPush()
{
$regId = "APA91bHFcgOssQZEqtdUk3EC1ojwC5-LVG3NPV2bMqKyC9rPymR6StmAbz-N7Ss8fnvruZhWWNrR3lmBqpjQItlu00AKHPbltBclUJF-EfC5qG4CF2xiuYYC0NCf8u5rbiYFk8ARhIT4lY2AEPWzGpl1OtTvQEC0gA";
$registatoin_ids = array($regId);
$message = array("msg" => 12345);
$this->send_notification($registatoin_ids, $message);
}
public function send_notification($registatoin_ids, $message)
{
// Set POST variables
$url = 'https://android.googleapis.com/gcm/send';
define('GOOGLE_API_KEY', 'AIzaSyBavsIgQKo1Nf9wKZ5o_fGvE_6MI52LFR0');
$fields = array(
'registration_ids' => $registatoin_ids,
'data' => $message,
);
$headers = array(
'Authorization: key=' . GOOGLE_API_KEY,
'Content-Type: application/json'
);
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Disabling SSL Certificate support temporarly
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
// Execute post
$result = curl_exec($ch)
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
// Close connection
curl_close($ch);
echo $result;
}
"MismatchSenderId" is the obvious problem that we are getting nowadays.
Here are the possible cases that cause this problem.
Case 1: Mismatching Sender ID ->
Please check the Project number which you are using. If it's is correct or not.
Case 2: Wrong API Key ->
Please be sure that you are using the same API_Key or not. And in most of the cases, we need to generate Server_Key instead of Android_Key.
Case 3: Wrong Device's ID ->
Most of the time the problem is due to the wrong Device ID(Registration ID generated by GCM).
Please be ensure that that Whenever you generate new API key, the device id's of your device gets changed. Then it will take almost 5 five minutes to get an effect.
Note : Your device id is bound with the API KEY.
So....
--New Key created.
--GCM for Android Turned "on" in Google Dev. Console.
--Device registered with backend fine (Android Project is doing its job). Device key on the server.
--Send to device. Fail! The same message is returned from GCM everytime.
To Recap. This is NOT an Android Studio, Android OS, or Device issue. The GCM servers are not even trying to send the message to the device. My server sends to GCM, it returns the message...
{"multicast_id":6047824495557336291,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MismatchSenderId"}]}
to the server. As far as I can tell this means the Device's ID (the one returned to the device when it registered for a push, and the one saved on the backend (in the control panel) does not match, or is somehow not associated with the API Key used when sending the message.
Sending, of course, starts on my server, goes to GCM, then goes to the device.
This is what's not happening. The message goes from my server to GCM and back to my server - with the error.
Super frustrating as all of you can imagine - we've all been through this nightmarish stuff before :-)
Reference : https://www.buzztouch.com/forum/thread.php?tid=C3CED924C86828C2172E924
Hope it will solve your problem.
Related
I am working with an API that is documented here: https://cutt.ly/BygHsPV
The documentation is a bit thin, but I am trying to understand it the best I can. There will not be a developer from the creator of the API available before the middle of next week, and I was hoping to get stuff done before that.
Basically what I am trying to do is update the consent of the customer. As far as I can understand from the documentation under API -> Customer I need to send info through PUT to /customers/{customerId}. That object has an array called "communicationChoices".
Going into Objects -> CustomerUpdate I find "communicationChoices" which is specified as "Type: list of CommunicationChoiceRequest". That object looks like this:
{
"choice": true,
"typeCode": ""
}
Doing my best do understand this, I have made this function:
function update_customer_consent() {
global $userPhone, $username, $password;
// Use phone number to get correct user
$url = 'https://apiurlredacted.com/api/v1/customers/' . $userPhone .'?customeridtype=MOBILE';
// Initiate cURL.
$ch = curl_init( $url );
// Specify the username and password using the CURLOPT_USERPWD option.
curl_setopt( $ch, CURLOPT_USERPWD, $username . ":" . $password );
// Tell cURL to return the output as a string instead
// of dumping it to the browser.
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
// Data to send
$data = [
"communicationChoices" => [
"communicationChoiceRequest" => [
"choice" => true,
"typeCode" => "SMS"
]
]
];
$json_payload = json_encode($data);
print_r($json_payload);
// Set other options
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Content-Length: ' . strlen($json_payload)));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_payload);
// Execute the cURL request
$response = curl_exec($ch);
// Check for errors.
if( curl_errno( $ch ) ) :
// If an error occured, throw an Exception.
throw new Exception( curl_error( $ch ) );
endif;
if (!$response)
{
return false;
} else {
// Decode JSON
$obj = json_decode( $response );
}
print_r($response);
}
I understand that this is very hard to debug without knowing what is going on within the API and with limited documentation, but I figured asking here was worth a shot anyway.
Basically, $json_payload seems to be a perfectly fine JSON object. The response from the API however, is an error code that means unknown error. So I must be doing something wrong. Maybe someone has more experience with APIs and such documentation and can see what I should really be sending and how.
Any help or guidance will be highly appreciated!
before you test your code, you can use the form provided on the API Documentation.
when you navigate to API > Customers > /customers/{customerId} (GET), you will see a form on the right side of the page (scroll up). you need to provide the required values on the form then hit Submit button. you will surely get a valid data for communicationChoices based on the result from the Response Text section below the Submit button.
now, follow the data structure of communicationChoices object that you get from the result and try the same on API > Customers > /customers/{customerId} (PUT) form.
using the API forms, you may be able to instantly see a success or error from your input (data structure), then translate it to your code.
I'm setting two virtual hosts on my local pc, the first domain is http://dev.local and the other one handles the api request http://api.server.local/. The idea is simple, but not sure how to implement this kind of setup. So here's the actual process. The dev.local will send some important parameters and values which the API server read it first and validate the data sent from dev.local.
For example I have the API key provided from API server and being stored in the database together with the domain that can only use that API. So the most important thing is that I want to make sure that only dev.local can do the request. Here is some illustration.
[illustration] https://i.imgur.com/OKu34TM.png
I already tried cURL functions but for some reasons, the data can be access by anyone if they have a copy of the api key. So I want to make sure where the request come from or the origin of the request.
This is the script I have for my dev.local in order to get access to my api.server.local
<?php
$__apiServer = 'http://api.server.local';
$__apiVersion = '1.0';
$__apikey = '7c4a8d09ca3762af61e59520943dc26494f8941b'; // API Key
$__apiEmail = 'johnsmith99#gmail.com'; // Registered Email Address
$__apiUser = 'johnsmith'; // Username
$__curlURL = "";
$__curlURL = "{$__curlURL}{$__apiServer}/v{$__apiVersion}";
$__curlURL = "{$__curlURL}/bin.php?user={$__apiUser}";
$__curlURL = "{$__curlURL}&email={$__apiEmail}";
$__curlURL = "{$__curlURL}&key=$__apikey";
$__curlURL = "{$__curlURL}&domain=$_SERVER[SERVER_NAME]";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $__curlURL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
if(curl_exec($ch) === FALSE) {
echo "Failed to load resource files from the API Server: $__apiServer";
} else {
$__curlURL = curl_exec($ch);
if($err != 1){
eval(' ?>' . $__curlURL);
}
}
curl_close($ch);
I expect that the value can only be return if the required data are valid. For now the ouput can be read as expected but can be accessible by anyone if they have the copy of api key and other credentials.
I figure it out. I used cURL POST method and it is more secure than using GET. And parse array variables to validate the main parameters.
I want to send FCM push notifications in specific android users only using their token saved in mysql database as identification. here's my current progress
PHP Script Snippet Code: Report_Status.php (File 1)
//Gets the token of every user and sends it to Push_User_Notification.php
while ($User_Row = mysqli_fetch_array($Retrieve_User, MYSQLI_ASSOC)){
$User_Token = $User_Row['User_Token'];
include "../Android_Scripts/Notifications/Push_User_Notification.php";
$message = "Your Report has been approved! Please wait for the fire fighters to respond!";
send_notification($User_Token, $message);
}
PHP code for File 2: Push_User_Notification.php
<?php //Send FCM push notifications process
include_once("../../System_Connector.php");
function send_notification ($tokens, $message)
{
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids' => $tokens,
'data' => $message
);
$headers = array(
'Authorization:key = API_ACCESS_KEY',
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
}
?>
Problem:
The page is always stuck in Report_Status.php every time I ran the
script. It is supposed to go in Push_User_Notification and return to Report_Status once the process is done. Am I wrong in the implementation of calling the
Push_User_Notification.php or the receiving parameters to
Push_User_Notification.php?
P.S.
Here's my full source code of Report_Status.php in case anyone wants to check it: Report_Status.php
I think the problem you may be having is that you are sending a lot of notifications to several devices in short amount of time. I think it might be being picked up as spaming. My suggestion is sending one notification to multiple devices.
Try changing your code in report_status.php to this.
include "../Android_Scripts/Notifications/Push_User_Notification.php";
$message = "Your Report has been approved! Please wait for the fire fighters to respond!";
while ($User_Row = mysqli_fetch_array($Retrieve_User, MYSQLI_ASSOC)){
$User_Token[] = $User_Row['User_Token'];
}
$tokens = implode(",", $User_Token);
send_notification($tokens, $message);
the idea is that you will collect the user tokens in $User_Token[] array. Then you would comma seperate the tokens and send the message once to all the devices that associate to the tokens. FCM allows you to send to multiple tokens in one go.
updated
$User_Token needs to be an array. so remove the implode. That was my mistake.
Secondly the $message needs to be in the following format.
$message = array(
'title' => 'This is a title.',
'body' => 'Here is a message.'
);
Also another thing to note is that there are 2 types of messages you can send using FCM. Notification Messages or Data Messages. Read more here: https://firebase.google.com/docs/cloud-messaging/concept-options
I dont know if your app is handling the receipt of messages (i dont know if you have implemented onMessageRecieve method) so i would probably suggest making a small change to the $fields array in send_notification function. Adding the notification field allows android to handle notifications automatically if your app is in the background. So make sure you app is in the background when testing. https://firebase.google.com/docs/cloud-messaging/android/receive
$fields = array(
'registration_ids' => $tokens,
'data' => $message,
'notification' => $message
);
So try the code below. I have tried and tested. It works for me. If it does not work. In send_notification function echo $result to get the error message. echo $result = curl_exec($ch); Then we can work from there to see what is wrong. You can see what the errors mean here: https://firebase.google.com/docs/cloud-messaging/http-server-ref#error-codes
include "../Android_Scripts/Notifications/Push_User_Notification.php";
$message = array(
'title' => 'Report Approved',
'body' => 'Your Report has been approved! Please wait for the fire fighters to respond!'
);
while ($User_Row = mysqli_fetch_array($Retrieve_User, MYSQLI_ASSOC)){
$User_Token[] = $User_Row['User_Token'];
}
send_notification($User_Token, $message);
Wink API is currently on version 2.
My Question: How can you do a simple "Hello World" with the Wink API V2 via PHP?
Notes:
Wink uses PubNub for subscriptions (devices have an event)
Uses OAuth2 standard
Website/Login is often "hokey": (& will error when you login: "Authentication failed!")
Login here: https://developer.wink.com & use Google account (or whatever)
Then change URL to this: https://developer.wink.com/clients
Sometimes you have to do this a couple times!!
You will need to request an Application API key in order to use the API. I followed up with an email to get it approved swiftly.
Once you are approved, you'll get: Client ID, Client Secret, & URLs to assist
API URL: https://api.wink.com/...
Email support: support#wink.zendesk.com (Get Application API key, etc)
OAuth 2:
Wink indicates to use "Authorization Code Grant Type"
Dox & Example: https://developer.byu.edu/docs/consume-api/use-api/choose-grant-type
Related Links:
Wink API: https://winkapiv2.docs.apiary.io/#
Stackoverflow related questions:
How to use Wink API V2 from a non-web app
Issues with Pubnub + Wink Hub and sensors
Wink API Subscriptions Stop Sending Overnight
https://community.home-assistant.io/t/wink-access-token-issue/52197/15
Github Example: https://github.com/cbulock/php-wink (This was last updated 3 years ago; might be on previous API ver)
Information regarding this is extremely limited, so I'll answer my own question hoping to help others. (It took a long time since there wasn't any good info out there.) This example has a user interface (Login required by Wink). I'm hoping someone can post a non-user-interface version (for background scripting, etc).
This will give you raw json output, for you to do with as you wish. This single php page will initially load, take you to Wink's login (you need an account with your devices if this wasn't obvious), after logging it, it will take you back to this same page with a code, call for a token, then use that token to get the device resources.
Create: //[YourServer]/wink_helloworld.php on your http/php server.
wink_helloworld.php:
//Make sure to add this exact URL to your Wink Developer Portal! (https://developer.wink.com/clients)
$redirect_uri = "http://[YourServer]/wink_helloworld.php";
// This is from Wink Developer Portal
$client_id = "abcdefg";
$wink_oauth_url = "https://api.wink.com/oauth2/token";
$client_secret = "hijklmnop";
$devices_url = "https://api.wink.com/users/me/wink_devices";
//need to create a state variable, like a session id. should actually be random tho!!
$randomstring="xyzABC123";
$state = base64_encode($randomstring);
/*_____________________________________________________________________________________________________________________________________ */
echo "<h2>Wink Hello World - Show Devices</h2>";
//If we don't have a code, then send user to login page
if($_GET['code'] == null | $_GET['code'] == ""){
echo "<a href='https://api.wink.com/oauth2/authorize?response_type=code&client_id=".$client_id."&redirect_uri=$redirect_uri&state=".$state."'>Login</a>";
return;
}
$code = $_GET['code'];
//if we dont have a token, lets get one
if($access_token == null | $access_token == ""){
$access_token = getAccessToken();
}
// lets get some data from our devices!
getResource($access_token);
/*_____________________________________________________________________________________________________________________________________ */
// Get token
function getAccessToken() {
global $wink_oauth_url, $code, $client_secret;
echo "<b>getAccessToken()</b> Using Code: $code<br>";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $wink_oauth_url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, "{
\"client_secret\": \"$client_secret\",
\"grant_type\": \"authorization_code\",
\"code\": \"$code\"
}");
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
$response = curl_exec($curl);
//var_dump($response);
formatResults($response); //debug output
curl_close($curl);
return json_decode($response)->access_token;
}
/*_____________________________________________________________________________________________________________________________________ */
// Get Resource(s) with our code & token
function getResource($access_token) {
global $devices_url;
echo "<b>getResource()</b> Using Token: $access_token<p>";
$header = array("Authorization: Bearer {$access_token}");
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $devices_url,
CURLOPT_HTTPHEADER => $header,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true
));
$response = curl_exec($curl);
curl_close($curl);
formatResults($response); //debug output
}
/*_____________________________________________________________________________________________________________________________________ */
//debug formatted output functions
function formatResults($json){
echo "<pre>";
echo json_encode(json_decode($json), JSON_PRETTY_PRINT);
echo "</pre>";
}
?>
API integration description
The API needs a form to be posted to the API URL with some input fields and a customer token. The API processes and then posts response to a callback.php file on my server. I can access the posted vals using $_POST in that file. That's all about the existing method and it works fine.
Requirement
To hide the customer token value from being seen from client side. So I started with sending server side post request.
Problem
I tried with many options but the callback is not happening -
1) CURL method
$ch = curl_init(API_URL);
$encoded = '';
$_postArray['customer_token'] = API_CUSTOMER_TOKEN;
foreach($_postArray as $name => $value)
{
$encoded .= urlencode($name).'='.urlencode($value).'&';
}
// chop off last ampersand
$encoded = substr($encoded, 0, strlen($encoded)-1);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded);
$resp = curl_exec($ch);
curl_close($ch);
echo $resp;
$resp echoes 1 if the line curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); is removed but the callback does not happen. I am setting a session variable in the callback script to verify.Is it needed that the API be synchronous in order to use curl method, so that curl_exec returns the response?
2) without CURL as given in Posting parameters to a url using the POST method without using a form
But the callback is not happening.
I tried with the following code too, but looks like my pecl is not installed properly because the HttpRequest() is not defined.
$req = new HttpRequest($apiUrl, HttpRequest::METH_POST);
$req->addQueryData($params);
try
{
$r->send();
if ($r->getResponseCode() == 200)
{
echo "success";
// success!
}
else
{
echo "failure";
// got to the API, the API returned perhaps a RESTful response code like 404
}
}
catch (HttpException $ex)
{
// couldn't get to the API (probably)
}
Please help me out! I just need to easily send a server side post request and get the response in the callback file.
Try to debug your request using the curl_get_info() function:
$header = curl_getinfo($ch);
print_r($header);
Your request might be OK but it my result in an error 404.
EDIT: If you want to perform a post request, add this to your code:
curl_setopt($ch, CURLOPT_POST, true);
EDIT: Something else I mentioned at your code: You used a '1' at the 'CURLOPT_RETURNTRANSFER' but is should be 'true':
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
At least this is how I usually do it, and you never know if the function will also understand a '1' as 'true';
EDIT: The real problem: I copy-pasted your source and used it on one of my pages getting this error:
Warning: urlencode() expects parameter 1 to be string, array given in C:\xampp\htdocs\phptests\test.php on line 8
The error is in this line:
foreach($_postArray as $name => $value)
$_postArray is an array with one value holding the other values and you need either another foreach or you simple use this:
foreach($_postArray['customer_token'] as $name => $value)
As discussed in the previous question, the callback is an entirely separate thing from your request. The callback also will not have your session variables, because the remote API is acting as the client to the callback script and has its own session.
You should really show some API documentation here. Maybe we're misunderstanding each other but as far as I can see, what you are trying to do (get the callback value in the initial CURL request) is futile, and doesn't become any less futile by asking twice.