I read the Amazon SES documentation several times and came up with the below PHP code to send an email via Amazon SES using what they called as HTTPS Query API approach to send emails without using the Amazon AWS SDK for PHP. However I am stuck with InvalidSignatureException and am unable to get past it. It seems like I am making a mistake somewhere probably in (1) creating the request signature or in (2) selecting right data to generate the request signature from. Any help to fix my code is greatly appreciated. My code is available below. It is important that I do this approach without including the Amazon AWS SDK into my PHP code. Thank you.
define("EMAIL_TO", <Amazon SES configured & verified from email id>);
define("EMAIL_FROM", <Amazon SES configured & verified from email id>);
define("SMTP_USERNAME", <AWS ACCESS KEY>);
define("SMTP_PASSWORD", <AWS SECRET ACCESS KEY>);
function amazonsesrawmailcurlpost($strToEmailId, $strEmailSubject, $strEmailBody)
{
$strDateRFC2822 = date("r", time());
$strRawEmailData = "From: ".EMAIL_FROM."\n";
$strRawEmailData.= "Subject: $strEmailSubject\n";
$strRawEmailData.= "\n";
$strRawEmailData.= $strEmailBody;
$strRequestContentPart = "Action=SendRawEmail";
$strRequestContentPart.= "&Destinations.member.1=$strToEmailId";
$strRequestContentPart.= "&RawMessage.Data=".base64_encode($strRawEmailData);
$strRequestContentPart = urlencode($strRequestContentPart);
$nRequestContentPartLength = strlen($strRequestContentPart);
$strSignature = base64_encode(hash_hmac(
"sha256",
$strDateRFC2822,
SMTP_PASSWORD,
TRUE
));
$rCurlToMailer = curl_init();
curl_setopt($rCurlToMailer, CURLOPT_URL, "https://email.us-west-2.amazonaws.com/");
curl_setopt($rCurlToMailer, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($rCurlToMailer,
CURLOPT_HTTPHEADER,
array(
"POST / HTTP/1.1",
"Host: email.us-west-2.amazonaws.com",
"Date: $strDateRFC2822",
"Content-Type: application/x-www-form-urlencoded",
"Content-Length: $nRequestContentPartLength",
"X-Amzn-Authorization: AWS3-HTTPS AWSAccessKeyId=".SMTP_USERNAME.", Algorithm=HmacSHA256, Signature=$strSignature"
)
);
curl_setopt($rCurlToMailer, CURLOPT_POST, TRUE);
curl_setopt($rCurlToMailer, CURLOPT_POSTFIELDS, $strRequestContentPart);
$strMailerResponse = curl_exec($rCurlToMailer);
echo $strMailerResponse;
curl_close($rCurlToMailer);
}
amazonsesrawmailcurlpost(EMAIL_TO, "amazonses test mail", date("Y-m-d H:i:s"));
Signature Version 3 with HTTPS, used by SES, is starkly different than V2 or V4 commonly seen with other AWS services, in that the only thing you sign is the date value.
To create the string to sign, calculate an RFC 2104-compliant HMAC hash with the Date header value, your secret access key as the key, and SHA256 or SHA1 as the hash algorithm.
— http://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface-authentication.html
Note also that all the keys and values in a POST with Content-Type: application/x-www-form-urlencoded need to actually be... urlencoded. I don't see this in your code. It isn't going to be related to the error but may cause additional issues later.
Related
I'm trying to create a RecipientView to send through an app to the recipients of envelopes that are created. With DocuSign's newer API, this requires a userName which is entered by the person who creates the document needed to be signed, an email which is just the email of the recipient, and a clientUserId which is a sender generated string value that authenticates the recipient as an embedded signer so that a RecipientView can be generated to host the signing ceremony.
DocuSign documentation references that I need to set clientUserId, but it doesn't mention how to to do this other than when the envelope is created through the API. However, in this scenario, envelopes will be created by DocuSign Admin clients through the templates on the actual web interface, and not through the API.
My code to generate the RecipientView is all set up here:
$url = "https://demo.docusign.net/restapi/v2/accounts/$account_id/envelopes/$envelope_id/views/recipient";
$body = array("returnUrl" => "http://www.docusign.com/devcenter",
"authenticationMethod" => "None",
"email" => "$email",
"userName" => "$name",
"recipientId" => "$recipientId",
"clientUserId" => "1000"
);
$body_string = json_encode($body);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Accept: application/json',
'Content-Type: application/json',
'Content-Length: '.strlen($body_string),
"Authorization: Bearer $access_token"
));
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $body_string);
$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status != 201){
die('Could not connect to end point: '.mysqli_error($conn));
}
$response = json_decode($json_response, true);
$url = $response["url"];
This code does work when the embedded signer is the Admin account, but not when the envelope is sent to an actual recipient. The return JSON from DocuSign after this request should be:
{
"url": "example.example.com"
}
However, the return I get for recipients that are not the Admin of the DocuSign account is:
{
"errorCode": "UNKNOWN_ENVELOPE_RECIPIENT",
"message": "The recipient you have identified is not a valid recipient of the
specified envelope."
}
I believe not setting clientUserId is the reason behind this, since the documentation says I need to set clientUserId and not just create a value when making the call. How do I set a recipient's clientUserId via the REST API?
UPDATE: Within this scenario, I will not be the one creating and sending envelopes. That will be done by the clients I have through my app, and the large majority of them will most likely use the web interface to do this, not the API. I do have access to all information regarding the Admin account for each client, including the Integrator Key, Access Tokens, Envelope IDs, Account IDs, etc.
For Embedded Signing (aka Recipient View) there are two calls you need to make. Well actually 3 calls including the initial Login API but it sounds like you've got that working so I'll focus on the other two.
Step #1: Create an envelope with an embedded recipient. When adding the recipient make sure you set their name, email, recipientId, and clientUserId.
Step #2: Request the Recipient View of the envelope for your signer. To do so you need to call the EnvelopeViews: createRecipient API and you must reference the same exact set of values for the recipient that you set in step 1 (i.e. name, email, recipientId, and clientUserId)
Check out the Signing from Within your App API Recipe for a full code sample.
I am using GCM services to push information from server. If I use browser key it shows the sucess mesaage as : {"multicast_id":4849013215736515938,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1348742583011905%2adac3a0f9fd7ecd"}]}
but i did not get any notifications on device.
And if I use server key it shows Unauthorized Error 401. My code is shown below:
$apiKey = "xxxxx";
$registrationIDs = array("xxxxxxxx");
$message = "testing Process";
$url = 'https://android.googleapis.com/gcm/send';
$fields = array(
'registration_ids' => $registrationIDs,
'data' => array("message"=>$message),
);
$headers = array(
'Authorization: key=' . $apiKey,
'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, 0);
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode($fields) );
$result = curl_exec($ch);
if(curl_errno($ch)){ echo 'Curl error: ' . curl_error($ch); }
curl_close($ch);
echo $result;
Please help me for this issue. Thanks in advance.
Did you whitelist the IP of your server? This is not necessary by default for the browser key, but it is for the server key.
You can check it here:
https://code.google.com/apis/console/#project:[YOUR PROJECT NUMBER]:access
Another answer already suggested whitelisting the IP address, which seems kind of obvious. What fixed it for me was whitelisting my IPv6 address. That was the key! I hope this helps someone else.
I tried everything in this thread, and still no luck.
So I checked enabled APIs (APIs and Auth -> APIs, Enabled APIs), and realised that I had enabled Google Cloud Messaging for Chrome not Google Cloud Messaging for Android. As soon as I enabled the latter, it worked immediately.
Double check you have the right API enabled!
As many people wrote, you have to whitelist your server IPV4 and IPV6. If you want only IPV4, add this to your curl php init:
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
use browser key using option create new browser key and use this key in your code.
https://code.google.com/apis/console/?pli=1#project:42053154xxxx:access
I used to put to the
$apiKey = "xxxxx"
like project number (project id) which i put to Android Client app, but i have been wrong in server have to be appkey from google cloud console, (where you activate Google Cloud Messaging for Android)
ProjectXXX -> APIs & auth -> Registered Apps -> Web App -> Server Key
-> Api key
in my case i had there default project 'Service Account-project' on platform: 'Web' but there was just Hosted Application section and no evidence about any api key.
but when i create new Web Apps called 'My app' which contained 4 sections OAuth 2.0 Client ID, Certificate, Server Key, Browser Key i finaly find the api key;-)
may just me who don't know it but i believe this answer could also helps to some one
for me the problem was that you have to enable the api. Having an API set up is not enough. Check that Google Cloud Messaging for Android appears on the enabled APIs in APIs-> enabled APIs.
If its not click the API library tab in APIS and enable it.
\
If I am not mistake your APIKEY needs to be base64 encoded.
Also try var_dump($results) to see if you get information then.
Looking at the code, I recognise this is from a php-gcm sample posted somewhere online. Its quite nice and I can assure you that both browser keys and whitelisted ip's (not IPV6 or bas64 apikey) work.
The reason why no message is shown is because the send notification function you're using 'data' => array("message"=>$message)
targets a key of "message", this is what you must pass to your pending intent i.e
notification.setLatestEventInfo(context, title, message, intent);
This will enable the intent to read the message contained under this key..the message itself is obtained from the GCMIntentService method pasted below:
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = intent.getExtras().getString("message");
Log.d(TAG, "The intent contains: " + intent.getExtras());
displayMessage(context, message);
// notifies user
generateNotification(context, message);
}
Here is the problem: I was using 2 servers, 1 staging and the other the production server. For my staging server, which was hosted using digital ocean, I entered the inet address in the Key for server applications allowed IP addresses, and it worked just fine.
However, it failed when I changed to my inet address from my production server. Instead, I had to use
inet6 addr: /64 Scope:Global for this to work. To get the value if you encounter the same issue, just enter ifconfig, and find the above entry. Enter that value in the allowed IP addresses and it will work fine.
You must have different project than the default one. Create a project & then create a key. Don't use default project.
Had this trouble, I was using GCM (Google cloud messaging). But after Sep 2016, the server key on the GCM will not work, you have to use FCM (firebase cloud messaging). Create new server keys only in the Firebase Console using the Cloud Messaging tab of the Settings panel. I went over to the firebase console console.firebase.google.com (I had not used it yet) and it asked me to import my project. Suddenly there was this new server key back on the GCM console. If using GCM, use the "legacy key" you see listed there.
Make sure you enabled your API Survery Key!
We are looking for solutions in days. More specifically, add this curl option: curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
I am trying to securely login a user via their Google account.
I am at the stage that I retrieve the userID and oAuthToken using this cordova plugin.
Now I am at the point where I need to send these credentials to my server and then on the server side validate the integrity of the token. Essentially I am trying to perform this part of the process.
I am confused as to which token I should try to verify using the Google client api. Should I use the userID or the oAuthToken ?
The documentation mentions validating the userID but I find this strange. Wouldn't this mean that if anyone gets my user id they can essentially break into my server ? The user id never changes (correct me if I am wrong here) so it seems insecure to validate on this. Wouldn't it make more sense to validate the oAuthToken which is set to expire ? Or does the user ID also expire ?
Any advice would be welcome.
Thanks,
Fido
Edit:
For anyone interested. My confusion arose due to not understanding fully three tokens which the google api can return: userId, oAuthToken, and idToken.
Briefly:The userId is returned with most api calls identifying the user. This appears to be constant. The oAuthToken in my case was returned when I accessed the google api as an Android client. The tokenId is returned when accessing the api as a web client. So those wishing to do server side validation using a mobile retrieved token should access the api as a web client. The token returned can then be validated server side using code similar to the accepted answer below.
you need to validate the IdToken, never send the userId on an open line. the IdToken expires quickly and it is virtually impregnable to brute force impersonation attacks.
this php snippet receives an HTTP request that starts with idtoken=, validates your token serverside and returns either the complete array or user email:
<?php
$inputRaw = file_get_contents('php://input');
$idToken= substr($inputRaw,8);
$fp = fopen('twoStepOutput.txt', 'a');
$url = 'https://www.googleapis.com/oauth2/v3/tokeninfo?id_token='.$idToken;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$json = json_decode($response, true);
curl_close($ch);
$userEmail = $json["email"];
$clientId = $json["azp"];
//fwrite($fp, date("YmdHis")."\r\n$idToken\r\n");
fwrite($fp, date("YmdHis")."\r\n");
fwrite($fp, "email Confirmed by GOOGLE:[$userEmail]\r\n");
//print_r($json); // returns array console readable
print_r($clientId); // returns google client id for verification (without transfering user data)
fclose($fp);
?>
just in case you are in doubts, this is what an IdToken looks like:
eypZCI6OiJSUzI1JhbGciNiIsImtIjk4MzQxMzgyMWJmMzhiNTJlM4OTI2YTllMTc0YTc5MWMwNGMifQ.eyJpc3MiOi3VizExYJhY2NvdW50cy5nb29nbGUuY29tIiwicmEIjoiMTAzNDUyNjAwODM5NzY3MjU2MDE0IiwiYXpwIjoiMTA3OTMxMTEyNTc1OS1lYWJhbWV0b2ZldjIwY28zbGQ5b2o1YWQwMzFuZG9nMC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImVtYWlsIjoidG9ueWdpbGJyQGdtYWlsLmNvbSIsImF0X2hhc2giOiJaSkhxbUZHcnR5Y29kdEhhOGJvMEYWY1NTk2NzUsImV4cCVBIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF1ZCI6IjEwNzkzMTExMjU3NTkt1ldG9mZXYyMGNvM2xkOW9qNWFkMDMxbmRvZzAuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJpYXQiOjE0MzZWFiI6MTQzNjU2MzI3NSwibmFtZSI6IlRvbnkgR2lsIiwicGljdHVyZSI6Imh0dHBzOi8vbGg0Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tQVREckRSbF9UdFEvQUFBQUFBQUFBQUkvQUFBQUFBQUFBRncvOVdDQnZkYlpUTEEvczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IlRvbnkiLCJmYW1pbHlfbmFtZSI6IkdpbCIsImxvY2FsZSI6ImVuIn0.L4peW11TD0bDOlvYKNY60ieZ1sbZfW9gEImcuxVA5f9U_4N49Io1CFXoGKmEPR_ij4q38tF2drPMOKijQePwlrxDui37ubzAdVkuksCJUobzjD1_eccF_8GldP5Y1_XsU8xrZeEnfabfiYpr-VwoLzIeNNUdy9SUbUWjMHNcvf4dGFMzE_SONHr57igjHK3rGkbvLo-UduFngm3e-EL0YR2zOKOVj1Qs8g8_qpWgkn8XABTme1thmuU8OfC-HaF9_B2Zk2UCsnOu4ApiYZk3DPIKgeX6AF11kYnzgvciYheWeddly0foT4G00C7w_wgtd-LSRw0XZltec_MPMa2QSA
I'm trying to add a new Deal with the Pipedrive API.
To do so I've followed this tutorial: http://support.pipedrive.com/customer/portal/articles/1271064-how-to-send-in-deals-using-a-web-form
But there's something I didn't understand:
"Email API gives your company a special email address you can use to
automate lead generation and adding of new contacts and
organizations."
Where can I get this email address, there's no other mention of it at the tutorial?
Since I'm unable to follow the tutorial I'm trying to add a new deal with cURL, this is the code:
<?php
$deal = array("item_type" => "deal","stage_id" => 1,"title" => "Atendimento Web Site","organization" => "Company","owner" => "johndoe#company.com.br","visible_to" => 2,"person" => array("name" => $nome,"email" => $email,"organization" => $empresa,"phone" => $tel));
$deal_string = json_encode($deal);
$ch = curl_init('https://api.pipedrive.com/v1/deals?api_token=TOKEN');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $deal_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json, charset=UTF-8',
'Content-Length: ' .strlen($deal_string))
);
echo $deal_string;
echo curl_exec($ch);
?>
And this is what I get:
iten sent -> {"item_type":"deal","stage_id":1,"title":"Atendimento","organization":"Company","owner":"owner#mail.com.br","visible_to":2,"person":{"name":"Jo\u00e3o Neto","email":"mail#mail.com.br","organization":"Company 2","phone":"7112345678"}}
return from api -> {"success":false,"error":"Deal title must be given.","data":null,"additional_data":null}
Where's the error?
About the email support it's true that you are mixing two thing, although it was also happened to me the first time. I admit it would seem strange, an API in which you can use emails.
Anyway, I was working on a simple integration between Pipedrive and another platform and I used the full REST API.
I noticed every time you have an error creating a Deal or you make a mistake in the Json (even if title is ok), you always get the same answer "error":"Deal title must be given.". Of courses it won't help you too much.
So, I recommend you to use some tools like RESTClient for Firefox to simplify the problem at the beginning or even Firebug to sniff it from https://developers.pipedrive.com/v1 making use of their tools to understand the request a little bit better. After that, you can do it more complex.
I am putting you a screenshot in which you can see the simplest example. I hope it will be useful for anyone
I'd receive an email from Pipedrive Support with a full anwser.
*Hi,
Thanks for reaching out!
I'm sorry to hear about the trouble!
So you're mixing up two completely separate things. You're sending in the JSON object needed for the Email API into the REST API.
You have 2 options.
You could go full on with the email API. To do this you need to log into your Pipedrive account, navigate to the Settings, Features page and enable the Email API feature. Then click through to the email API page and get the email address you need to send the object to. And then alter your PHP code to send in that object to that email address as a plain text email. No curl or API token needed for that.
You could clean up the data object you're sending in with the REST API. But you need to understand that the REST API works a little different from the Email API. So you can't just send in the person object along with the deal. You would first need to POST in the person with all the details to the persons endpoint and get back the ID. You can then use the person ID in the deals POST.
I hope this helps
Martin Henk | Co-Founder, Head of Customer Support
Pipedrive*
I am using GCM services to push information from server. If I use browser key it shows the sucess mesaage as : {"multicast_id":4849013215736515938,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1348742583011905%2adac3a0f9fd7ecd"}]}
but i did not get any notifications on device.
And if I use server key it shows Unauthorized Error 401. My code is shown below:
$apiKey = "xxxxx";
$registrationIDs = array("xxxxxxxx");
$message = "testing Process";
$url = 'https://android.googleapis.com/gcm/send';
$fields = array(
'registration_ids' => $registrationIDs,
'data' => array("message"=>$message),
);
$headers = array(
'Authorization: key=' . $apiKey,
'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, 0);
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode($fields) );
$result = curl_exec($ch);
if(curl_errno($ch)){ echo 'Curl error: ' . curl_error($ch); }
curl_close($ch);
echo $result;
Please help me for this issue. Thanks in advance.
Did you whitelist the IP of your server? This is not necessary by default for the browser key, but it is for the server key.
You can check it here:
https://code.google.com/apis/console/#project:[YOUR PROJECT NUMBER]:access
Another answer already suggested whitelisting the IP address, which seems kind of obvious. What fixed it for me was whitelisting my IPv6 address. That was the key! I hope this helps someone else.
I tried everything in this thread, and still no luck.
So I checked enabled APIs (APIs and Auth -> APIs, Enabled APIs), and realised that I had enabled Google Cloud Messaging for Chrome not Google Cloud Messaging for Android. As soon as I enabled the latter, it worked immediately.
Double check you have the right API enabled!
As many people wrote, you have to whitelist your server IPV4 and IPV6. If you want only IPV4, add this to your curl php init:
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
use browser key using option create new browser key and use this key in your code.
https://code.google.com/apis/console/?pli=1#project:42053154xxxx:access
I used to put to the
$apiKey = "xxxxx"
like project number (project id) which i put to Android Client app, but i have been wrong in server have to be appkey from google cloud console, (where you activate Google Cloud Messaging for Android)
ProjectXXX -> APIs & auth -> Registered Apps -> Web App -> Server Key
-> Api key
in my case i had there default project 'Service Account-project' on platform: 'Web' but there was just Hosted Application section and no evidence about any api key.
but when i create new Web Apps called 'My app' which contained 4 sections OAuth 2.0 Client ID, Certificate, Server Key, Browser Key i finaly find the api key;-)
may just me who don't know it but i believe this answer could also helps to some one
for me the problem was that you have to enable the api. Having an API set up is not enough. Check that Google Cloud Messaging for Android appears on the enabled APIs in APIs-> enabled APIs.
If its not click the API library tab in APIS and enable it.
\
If I am not mistake your APIKEY needs to be base64 encoded.
Also try var_dump($results) to see if you get information then.
Looking at the code, I recognise this is from a php-gcm sample posted somewhere online. Its quite nice and I can assure you that both browser keys and whitelisted ip's (not IPV6 or bas64 apikey) work.
The reason why no message is shown is because the send notification function you're using 'data' => array("message"=>$message)
targets a key of "message", this is what you must pass to your pending intent i.e
notification.setLatestEventInfo(context, title, message, intent);
This will enable the intent to read the message contained under this key..the message itself is obtained from the GCMIntentService method pasted below:
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = intent.getExtras().getString("message");
Log.d(TAG, "The intent contains: " + intent.getExtras());
displayMessage(context, message);
// notifies user
generateNotification(context, message);
}
Here is the problem: I was using 2 servers, 1 staging and the other the production server. For my staging server, which was hosted using digital ocean, I entered the inet address in the Key for server applications allowed IP addresses, and it worked just fine.
However, it failed when I changed to my inet address from my production server. Instead, I had to use
inet6 addr: /64 Scope:Global for this to work. To get the value if you encounter the same issue, just enter ifconfig, and find the above entry. Enter that value in the allowed IP addresses and it will work fine.
You must have different project than the default one. Create a project & then create a key. Don't use default project.
Had this trouble, I was using GCM (Google cloud messaging). But after Sep 2016, the server key on the GCM will not work, you have to use FCM (firebase cloud messaging). Create new server keys only in the Firebase Console using the Cloud Messaging tab of the Settings panel. I went over to the firebase console console.firebase.google.com (I had not used it yet) and it asked me to import my project. Suddenly there was this new server key back on the GCM console. If using GCM, use the "legacy key" you see listed there.
Make sure you enabled your API Survery Key!
We are looking for solutions in days. More specifically, add this curl option: curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );