I'm working with the Urban Airship (v3) API to push out messages to Android/iPhone/Blackberry and hopefully soon Windows phones. I'm not responsible for that; instead, I'm setting up the backend to allow users to send out a broadcast.
Another guy built the original backend, but I chose to rebuilt it from the bottom up to add in some additional functionality. Everything works in it, except the whole pushing of the broadcast part. Well, it sort of works; let me explain:
When a form is submitted, the data goes into the database via MYSQL and then with mysql_fetch_id() I get the new id and toss that id into a PHP function called sentBroadcast. It looks like the following:
function sentBroadcast($id){
$alertinfo = getAlertInfo($id);//this just gets all the data matching the id
$alert = mysql_fetch_assoc($alertinfo);
//these just get extra values
$organization = getOrganizationById($alert['broadcast_organization_id']);
$cityinfo = getCityInfo($organization['organization_city_id']);
$city = mysql_fetch_assoc($cityinfo);
// Create Airship object
$airship = new Airship(APP_KEY, APP_MASTER_SECRET);
$apiurl = "https://go.urbanairship.com/api/location/?q=".str_replace(" ","",strtolower($city['city_name']));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiurl);
curl_setopt($ch, CURLOPT_USERPWD, APP_KEY.":".APP_MASTER_SECRET);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close ($ch);
$json = json_decode($output);
$locationid = "all";
if(count($json->features) > 0){
$locationid = $json->features[0]->id;
}
//send the message
$broadcasttype = "";
if($alert['broadcast_broadcasttypeother'] != ""){
$broadcasttype = $alert['broadcast_broadcasttypeother'];
}
else {
//this just gets data, nothing to see here
$broadcasttype = getCategoryInfo($alert['broadcast_broadcasttype_id'],'broadcasttype_name');
}
$message = html_entity_decode($broadcasttype)."\r\n".html_entity_decode($organization['organization_name'])."\r\n". html_entity_decode($alert['broadcast_subject']);
$blackberry_message = html_entity_decode($organization['organization_name'])."\r\n". html_entity_decode($alert['broadcast_subject']);
//calc as UTC
$timestamp = strtotime($alert['broadcast_sentdatetime']) + strtotime("+1 minute"); //add an hour
$offset = new DateTime(date("Y-m-d H:i:s T",$timestamp));
$offset->setTimezone(new DateTimeZone('UTC'));
$minutes_to_add = 10;
$time = new DateTime($alert['broadcast_sentdatetime']);
$time->add(new DateInterval('PT' . $minutes_to_add . 'S'));
$stamp = $time->format('Y-m-d H:i:s');
//echo $stamp;
$broadcast_message = array(
'schedule' => array("scheduled_time" => $stamp),
'push' => array("audience" => "all",
"notification" => array("alert" => $message),
"device_types" => array()
),
);
$device_types = array();
$device_types[] = "ios";
$device_types[] = "android";
$device_types[] = "blackberry";
$broadcast_message["push"]["device_types"] = $device_types;
if(in_array("ios", $device_types)){
$broadcast_message["push"]["notification"]["ios"] = array("sound" => "police.mp3", "extra" => array("id"=>$alert['broadcast_id']), "badge" => "+1");
}
if(in_array("android", $device_types)){
$broadcast_message["push"]["notification"]["android"] = array("extra"=>array("id"=>$alert['broadcast_id']));
}
if(in_array("blackberry", $device_types)){
$broadcast_message["push"]["notification"]["blackberry"] = array("content-type"=>"text/plain","body"=> json_encode(array("id"=>$alert['broadcast_id'], "body"=>$blackberry_message, "type"=>$broadcasttype)));
}
$data_string = json_encode($broadcast_message);
$apiurl = "https://go.urbanairship.com/api/schedules/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiurl);
curl_setopt($ch, CURLOPT_USERPWD, APP_KEY.":".APP_MASTER_SECRET);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: application/vnd.urbanairship+json; version=3;',
'Content-Length: ' . strlen($data_string)
));
$json = curl_exec($ch);
$output = json_decode($json, true);
if(!is_array($output) || empty($output["ok"])){
echo "<h1>ERROR: (".(isset($output["error"]) ? $output["error"] : "An unknown error has occurred while trying to send your message.").")</h1>";
echo $data_string;
print_r($output);
$error = true;
}
curl_close ($ch);
$debug = false;
if($debug || $error){
if($error) echo "<!--";
var_dump($broadcast_message);
echo "<hr><br>";
echo $json."<hr><br>";
echo "<pre>";
print_r($output);
echo "</pre>";
if(!empty($output['ok'])){
//maybe we should save the status, or the json in the db.
echo 'yay it sent';
}
if($error) echo "-->";
}
if($error){
exit;
}
}//end sendBroadcast
When I do this query, I get hit by an error "Could not parse body request body". That wasn't very helpful, so I printed the response (look under "if(!is_array($output) || empty($output["ok"])){"). I get the following error message:
Array ( [ok] => [error] => Could not parse request body. [error_code] => 40700 [details] => Array ( [error] => Cannot schedule for the past 2013-10-12T06:46:00.000Z ) [operation_id] => 6fde4fa0-4b64-11e3-8903-90e2ba0253a0 )
The error I'm getting is "Cannot schedule for the past", however at the time of submitting this, it was the future. I began doing some research and read that I had to set it to UTC time. That being said, whatever my time is now, it will always be 6 hours into the past in UTC, so I have to convert it up to UTC.
So, I did that and the message went out and the phones received it and all went well. Except when we went to read the message: we then got an error that said the message was deleted.
We didn't delete it, so I think maybe (it hasn't been 6 hours yet) the users phone will get the new broadcast in the future, but they got informed of the alert now. That alert isn't visible yet, so it throws an error. At least that's what I think; it hasn't been 6 hours yet so I can't prove that.
My problem is this: How do I tell Urban Airship I want an immediate post to go out, without having to add 6 hours to the current time to make it in the "present", as well as actually having the phones get it at the correct time?
I contacted UA but they said to "expect a week delay in responding to you" (No rush, eh?) and I googled the error code (40700) and came up with nothing. I then emailed the guy who built the original and all he said was the "UTC was very important". Thank you for that.
If anybody can help me out I would be very thankful.
Thank you.
Oh, and if anybody is wondering, the json I'm submitting looks like the following:
{"schedule":{"scheduled_time":"2013-10-12 06:46:00"},"push":{"audience":"all","notification":{"alert":"Message\r\nKenton Industries\r\nKenton Test","ios":{"sound":"police.mp3","extra":{"id":"406"},"badge":"+1"},"android":{"extra":{"id":"406"}},"blackberry":{"content-type":"text\/plain","body":"{\"id\":\"406\",\"body\":\"Kenton Industries\\r\\nKenton Test\",\"type\":\"Message\"}"}},"device_types":["ios","android","blackberry"]}}
Thanks :)
I'm not sure I understand the second part of your question of, "having the phones get it at the correct time". In regards to the question of, "How do I tell Urban Airship I want an immediate post to go out, without having to add 6 hours to the current time to make it in the "present"":
If you want your users to receive the message as soon as possible then you shouldn't be scheduling your message. Via their curl examples an immediate push message curl request should look as thus:
curl -v -X POST -u "<AppKey>:<MasterSecret>" -H "Content-type: application/json" -H "Accept: application/vnd.urbanairship+json; version=3;" --data '{"audience" : "all", "device_types" : "all", "notification" : {"alert": "This is a broadcast"} }' https://go.urbanairship.com/api/push/
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 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);
Hi there i am having a strange problem with downloading a remote file. I am using Flurry Data API to download some Reports. Thing is when first time we call the Flurry API it gives us XML/JSON response which contains the path of the Report for Download. It takes like 2 minutes for the report to get ready. I am having Problem with that thing. I wrote a Script which download the remote file if i just paste the link of Report directly to function which is already ready to download. It works like a charm but i have to automate the process of Downloading. So for that i First call the API and get the Report Download Link then i use sleep() function of PHP to stop execution for like 3 Minutes(Tried it with 2 also). Then i call the same function which i uses to download the report successfully doesn't work this time. Here is the File Download Method:
function get_file_and_save($file, $local_path, $newfilename) {
$err_msg = '';
$out = fopen($local_path . $newfilename . ".gz", 'wb');
if ($out == FALSE) {
print "File is not available<br>";
exit;
}
$ch = curl_init();
$headers = array('Content-type: application/x-gzip', 'Connection: Close');
curl_setopt($ch, CURLOPT_FILE, $out);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_URL, $file);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
curl_exec($ch);
echo "<br>Error Occured:" . curl_error($ch);
curl_close($ch);
}
i also have tried giving the CURLOPT_TIMEOUT but it wasn't working either.
The code to Request to the Flurry note that download_path is working properly it just get the report link:
$query_url = 'http://api.flurry.com/rawData/Events?apiAccessCode=' . $ACCESS_CODE . '&apiKey=' . $API_KEY . '&startTime=' . $start_time . '&endTime=' . $end_time;
$response = download_path($query_url);
if ($response) {
$response_obj = json_decode($response, true);
if (isset($response_obj['report']['#reportUri'])) {
$report_link = $response_obj['report']['#reportUri'];
}
if (isset($response_obj['report']['#reportId'])) {
$report_id = $response_obj['report']['#reportId'];
}
if(isset($report_link) && !empty($report_link)){
echo "<br >Report Link: ".$report_link."<br >";
sleep(240);
$config = array(
'http' => array(
'header' => 'Accept: application/json',
'method' => 'GET'
)
);
$stream = stream_context_create($config);
$json= file_get_contents($report_link,false,$stream);
echo "<pre>";
print_r($http_response_header);
echo "</pre>";
if($http_response_header[3] == "Content-Type: application/octet-stream"){
get_file_and_save($report_link, "data-files/gz/", $current_time);
}
}
else{
echo "There was some error in downloading report";
}
} else {
$error = true;
echo "There was some error in genrating report";
}
is there something problem with sleep() or what i am stuck its been 2nd night i am unable to achieve it.
Check if your PHP script is timing out and being killed off. Both the webserver and PHP have max execution limits to prevent runaway scripts, and if your sleep surpasses that limit, it'll never continue beyond that.
http://www.php.net/manual/en/info.configuration.php#ini.max-execution-time
http://php-fpm.org/wiki/Configuration_File - request_terminate_timeout
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_read_timeout
http://httpd.apache.org/docs/2.0/mod/core.html#timeout
So, I'm working with the Instagram API, but I cannot figure out how to create a like (on a photo) for the logged in user.
So my demo app is currently displaying the feed of a user, and it's requesting the permission to like and comment on behalf of that user. I'm using PHP and Curl to make this happen, creds to some guide I found on the internet:
<?php
if($_GET['code']) {
$code = $_GET['code'];
$url = "https://api.instagram.com/oauth/access_token";
$access_token_parameters = array(
'client_id' => '*MY_CLIENT_ID*',
'client_secret' => '*MY_CLIENT_SECRET*',
'grant_type' => 'authorization_code',
'redirect_uri' => '*MY_REDIRECT_URI*',
'code' => $code
);
$curl = curl_init($url); // we init curl by passing the url
curl_setopt($curl,CURLOPT_POST,true); // to send a POST request
curl_setopt($curl,CURLOPT_POSTFIELDS,$access_token_parameters); // indicate the data to send
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly.
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // to stop cURL from verifying the peer's certificate.
$result = curl_exec($curl); // to perform the curl session
curl_close($curl); // to close the curl session
$arr = json_decode($result,true);
$pictureURL = 'https://api.instagram.com/v1/users/self/feed?access_token='.$arr['access_token'];
// to get the user's photos
$curl = curl_init($pictureURL);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$pictures = curl_exec($curl);
curl_close($curl);
$pics = json_decode($pictures,true);
// display the url of the last image in standard resolution
for($i = 0; $i < 17; $i++) {
$id = $pics['data'][$i]['id'];
$lowres_pic = $pics['data'][$i]['images']['low_resolution']['url'];
$username = $pics['data'][$i]['user']['username'];
$profile_pic = $pics['data'][$i]['user']['profile_picture'];
$created_time = $pics['data'][$i]['created_time'];
$created_time = date('d. M - h:i', $created_time);
$insta_header = '<div class="insta_header"><div class="insta_header_pic"><img src="'.$profile_pic.'" height="30px" width="30px"/></div><div class="insta_header_name">'.$username.'</div><div class="insta_header_date">'.$created_time.'</div></div>';
$insta_main = '<div class="insta_main"><img src="'.$lowres_pic.'" /></div>';
$insta_footer = '<div class="insta_footer"><div class="insta_footer_like"><button onClick="insta_like(\''.$id.'\')"> Like </button></div><div class="insta_footer_comment"><form onSubmit="return insta_comment(\''.$id.'\')"><input type="text" id="'.$id.'" value="Comment" /></form></div></div>';
echo '<div class="insta_content">'. $insta_header . $insta_main . $insta_footer .'</div>';
}
}
?>
Now, it might be a stupid question, but how do I make a like on a particular photo on behalf of the user? I'm used to using JavaScript to these kinds of things, therefore I've setup the Like-button with a JS function (which does not exist). But since the Instagram thing have been using Curl and PHP, I'm guessing I have to do the same thing here? I have no experience with Curl, and I do not understand how it works. It would be great if someone could give me a headsup on that as well. But first off, the liking. If it's possible to do it with JS, I'd be very glad. If not, please show me how to do it with PHP and Curl.
Here's a link to the Instagram developers site, which contain the URL you should send a POST request to http://instagram.com/developer/endpoints/likes/.
And if you're not to busy, I'd be really glad if you could show me how to make a comment on behalf of a user as well :)
Thanks in advance.
Aleksander.
I'm trying to convert this PHP cURL function to work with my rails app. The piece of code is from an SMS payment gateway that needs to verify the POST paramters. Since I'm a big PHP noob I have no idea how to handle this problem.
$verify_url = 'http://smsgatewayadress';
$fields = '';
$d = array(
'merchant_ID' => $_POST['merchant_ID'],
'local_ID' => $_POST['local_ID'],
'total' => $_POST['total'],
'ipn_verify' => $_POST['ipn_verify'],
'timeout' => 10,
);
foreach ($d as $k => $v)
{
$fields .= $k . "=" . urlencode($v) . "&";
}
$fields = substr($fields, 0, strlen($fields)-1);
$ch = curl_init($verify_url); //this initiates a HTTP connection to $verify_url, the connection headers will be stored in $ch
curl_setopt($ch, CURLOPT_POST, 1); //sets the delivery method as POST
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); //The data that is being sent via POST. From what I can see the cURL lib sends them as a string that is built in the foreach loop above
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); //This verifies if the target url sends a redirect header and if it does cURL follows that link
curl_setopt($ch, CURLOPT_HEADER, 0); //This ignores the headers from the answer
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //This specifies that the curl_exec function below must return the result to the accesed URL
$result = curl_exec($ch); //It ransfers the data via POST to the URL, it gets read and returns the result
if ($result == true)
{
//confirmed
$can_download = true;
}
else
{
//failed
$can_download = false;
}
}
if (strpos($_SERVER['REQUEST_URI'], 'ipn.php'))
echo $can_download ? '1' : '0'; //we tell the sms sever that we processed the request
I've googled a cURL lib counterpart in Rails and found a ton of options but none that I could understand and use in the same way this script does.
If anyone could give me a hand with converting this script from php to ruby it would be greatly appreciated.
The most direct approach might be to use the Ruby curb library, which is the most straightforward wrapper for cURL. A lot of the options in Curl::Easy map directly to what you have here. A basis might be:
url = "http://smsgatewayadress/"
Curl::Easy.http_post(url,
Curl::PostField.content('merchant_ID', params[:merchant_ID]),
# ...
)