Dropbox - uploading files from url doesn't work consistently - php

I have a PHP script that uploads files into Dropbox. When I run it from command-line as a standalone script, it works perfectly.
However, when I incorporate my code into the larger project, the file fails to upload, cURL returns "errno" 0 (meaning, no cURL errors), and there's no output from Dropbox's API.
Here is the code that works:
$token = '<token>';
$url = "https://content.dropboxapi.com/2/files/upload";
$post_body = file_get_contents("/other/server/url/test.txt");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $token,
'Content-Type: application/octet-stream',
'Dropbox-API-Arg: {"path": "/Dropbox/path/subfolder/test.txt","mode": "add", "autorename": true, "mute": false}'));
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($data);
.... and here is the broken code:
private function dropbox_uploadFile( $path, $file_source, $file_name = "test1.txt") {
echo "<br /><br />PATH: ". $path . '/' . $file_name . "<br /><br />";
echo "<br /><br />SOURCE: ". $file_source . "<br /><br />";
$token = '<token>';
$url = "https://content.dropboxapi.com/2/files/upload";
$post_body = file_get_contents( $file_source );
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $token,
'Content-Type: application/octet-stream',
'Dropbox-API-Arg: {"path": ' . $path.'/'.$file_name. '","mode": "add", "autorename": true, "mute": false}'));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_body);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false); // to prevent cURL error #60
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = json_decode(curl_exec($ch), true);
if( ! $data ) {
echo "<pre>";
print_r(curl_getinfo($ch));
echo "</pre>";
echo "ERROR: " . curl_errno( $ch ) . "<br /><br />";
}
curl_close($ch);
print_r($data);
}

I broke out the API call itself, like this:
$res = curl_exec($ch);
print_r($res);
$data = json_decode($res, true);
That showed me the actual error from the API:
Error in call to API function "files/upload": HTTP header "Dropbox-API-Arg": could not decode input as JSON
For different types of errors, the API will return either plain text or JSON, with the response Content-Type header telling you which. In your code, you were only handling JSON, and json_decode apparently silently fails when it isn't supplied valid JSON.
Anyway, that error indicates the supplied JSON for the upload arguments is itself invalid. The problem seems to be a missing quote at the beginning of the path value, fixed here:
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $token,
'Content-Type: application/octet-stream',
'Dropbox-API-Arg: {"path": "' . $path.'/'.$file_name. '","mode": "add", "autorename": true, "mute": false}'));

I went here trying some tips, and I ma using SWIFT.
Hope can help OTHERS.
After some (hard) mailing with dropbox support...
Error in my case was due to unescaping special chars in path.
If You want to upload:
let unescapedFileName = "αβγ.jpg"
You have to escape:
let unescapedFileName = "αβγ.jpg"
let escapedFileName = DB_asciiEscape(unescapedFileName)
Here an Unit test:
func testUtf8Decode(){
let unescapedFileName = "αβγ.jpg"
let escapedFileName = DB_asciiEscape(unescapedFileName)
print(escapedFileName)
let contains = escapedFileName.contains("\\u03b1\\u03b2\\u03b3")
XCTAssert(contains, "not escaped")
}
where function is:
func DB_asciiEscape(_ s: String) -> String {
let out = s.unicodeScalars.reduce("", { (partialResult: String, char: UnicodeScalar) -> String in
if !char.isASCII {
return partialResult + String(format:"\\u%04x", char.value)
} else {
if (char == "\u{7F}") {
return partialResult + "\\u007f"
} else {
return partialResult + "\(char)"
}
}
})
return out
}

Related

Workflow Max add job via API

I'm trying to add a job to the Workflow Max API. I seem to be hitting the API but I keep getting the error message:
Message not in expected format. The following required element was missing - Job/ClientID
I'm sure that the client ID is added but something seems to be wrong. This is the code:
function post_job_to_workflow_max($job_data) {
// configure our connection to the api
$api_token = 'API_KEY';
$acc_key = 'ACC_TOKEN';
$url = 'https://api.workflowmax.com/job.api/add?apiKey=' . $api_token . '&accountKey=' . $acc_key;
// Job data must match the format required by WorkflowMax
// currently accepts XML data
// see: https://www.workflowmax.com/api/job-methods#POST%20add
$xml = new SimpleXMLElement("<Job></Job>");
$xml->addChild('Name', $job_data[0]);
$xml->addChild('Description', $job_data[1]);
$xml->addChild('ClientID', 18754031);
// $clientID = $xml->addChild('Client');
// $clientID->addChild('ID', 18754031);
// $clientID->addChild('Name', "TEST CLIENT");
$xml->addChild('State', 'Planned');
$xml->addChild('StartDate', $job_data[2]);
$xml->addChild('DueDate', $job_data[3]);
// print_r($xml);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML());
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: text/xml',
'Content-Length: ' . strlen($xml->asXML()))
);
$output = curl_exec($ch);
curl_close($ch);
$result = simplexml_load_string($output);
print_r($result);
}
If there's anyone with experience of using WFM, would be good to hear how you approached it.
Thanks
So in answer to my own question, I did finally work this out.
The way I did this was to return the ID of the client from the function I used to post a client to WorkFlow Max. See code:
1) post the client
function post_client_to_workflowmax($client_data) {
// configure our connection to the api
$api_token = 'YOUR_TOKEN';
$acc_key = 'YOUR_KEY';
$url = 'https://api.workflowmax.com/client.api/add?apiKey=' . $api_token . '&accountKey=' . $acc_key;
// Client data must match the format required by WorkflowMax
// currently accepts XML data
// These indexes match up with how the data has been stored
// see: https://www.workflowmax.com/api/client-methods#POST%20add
$xml = new SimpleXMLElement("<Client></Client>");
$xml->addChild('Name', htmlspecialchars($client_data[2]));
$xml->addChild('Email', htmlspecialchars($client_data[9]));
$xml->addChild('Phone', htmlspecialchars($client_data[10]));
$xml->addChild('Address', htmlspecialchars($client_data[3]) . ' ' . htmlspecialchars($client_data[4]));
$xml->addChild('City', htmlspecialchars($client_data[5]));
$xml->addChild('Postcode', htmlspecialchars($client_data[7]));
$xml->addChild('Country', htmlspecialchars($client_data[8]));
$xml->addChild('IsProspect', 'No');
$contacts = $xml->addChild('Contacts');
$contact = $contacts->addChild('Contact');
$name = $contact->addChild('Name', htmlspecialchars($client_data[0]) . ' ' . htmlspecialchars($client_data[1]));
// POST request
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML());
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: text/xml',
'Content-Length: ' . strlen($xml->asXML()))
);
$output = curl_exec($ch);
curl_close($ch);
// Create an array from the data that is sent back from the API
$result = simplexml_load_string($output);
$clientID = NULL;
// here we get the ID created for this client and pass it into the variable $clientID
foreach($result->Client as $k => $v) {
$clientID = $v->ID;
}
return $clientID;
}
We then get that ID passed into our job posting function like so:
2) post a job to WFM
function post_job_to_workflow_max($job_data, $clientID) {
// configure our connection to the api
$api_token = 'YOUR_TOKEN';
$acc_key = 'YOUR_KEY';
$url = 'https://api.workflowmax.com/job.api/add?apiKey=' . $api_token . '&accountKey=' . $acc_key;
// Job data must match the format required by WorkflowMax
// currently accepts XML data
// see: https://www.workflowmax.com/api/job-methods#POST%20add
$xml = new SimpleXMLElement("<Job></Job>");
$xml->addChild('ClientID', $clientID);
$xml->addChild('Name', htmlspecialchars($job_data[0]));
$xml->addChild('Description', htmlspecialchars($job_data[1]));
$xml->addChild('State', 'Planned');
$xml->addChild('StartDate', htmlspecialchars($job_data[2]));
$xml->addChild('DueDate', htmlspecialchars($job_data[3]));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML());
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: text/xml',
'Content-Length: ' . strlen($xml->asXML()))
);
$output = curl_exec($ch);
curl_close($ch);
$result = simplexml_load_string($output);
}
And then calling these functions looks something like this:
$id = post_client_to_workflowmax($client);
post_job_to_workflow_max($job, $id);
Where $client must be an array of data. This worked for my case but might not work for your particular case so you may need to edit the fields etc.
Hopefully this helps someone who is stuck with the same problem. Not the most elegant code but it gets the job done.

Issue in Downloading File In Dropbox Version 2 Php Api

Hy Everyone,
I am using this code to download file from Dropbox Version 2 Php Api.But I don't get success yet in File downloading.Lets have a look on the script which i am using
function dbx_get_file($token, $in_filepath, $out_filepath)
{
$out_fp = fopen($out_filepath, 'w+');
if ($out_fp === FALSE)
{
echo "fopen error; can't open $out_filepath\n";
return (NULL);
}
$url = 'https://content.dropboxapi.com/2/files/download';
$header_array = array(
'Authorization: Bearer ' . $token,
'Content-Type:',
'Dropbox-API-Arg: {"path":"' . $in_filepath . '"}'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header_array);
curl_setopt($ch, CURLOPT_FILE, $out_fp);
$metadata = null;
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$metadata)
{
$prefix = 'dropbox-api-result:';
if (strtolower(substr($header, 0, strlen($prefix))) === $prefix)
{
$metadata = json_decode(substr($header, strlen($prefix)), true);
}
return strlen($header);
}
);
$output = curl_exec($ch);
if ($output === FALSE)
{
echo "curl error: " . curl_error($ch);
}
curl_close($ch);
fclose($out_fp);
return($metadata);
} // dbx_get_file()
Calling this Function Here.
dbx_get_file("<Access-token>", '/Screenshot_1.png', 'Screenshot_1.png');
I also replaced this "Access-token" with my Dropbox O-auth 2 Access Token.
Please suggest me the answer what i am doing wrong?Or is there any other way to download File from Dropbox using DropBox Version 2 PHP Api.
Thanks
I have done it using Requests Library https://github.com/rmccue/Requests/
Here is my Code
include('Requests-master/library/Requests.php');
Requests::register_autoloader();
$token="Your Access Token is here";
$response =
Requests::post("https://content.dropboxapi.com/2/files/download", array(
'Authorization' => "Bearer ".$token,
'Dropbox-Api-Arg' => json_encode(array('path' => '/Screenshot_1.png')),
));
$fileContent = $response->body;
/*Download the file using file_put_contents method*/
file_put_contents("Screenshot_1.png",$fileContent);
$metadata = json_decode($response->headers['Dropbox-Api-Result'], true);
echo "File " . $metadata["name"] . " has the rev " . $metadata["rev"] . ".\n";
File is downloading Successfully... :)

Get JSON generated by a webhook hosted online

I am making a card payment and then it communicates to the server of the company via webhook, the response is then recorded in RequestBin, which generates a JSON response in their website, how do I extract the information from the website to my PHP code?
The webpage looks like this:
my requestb.in online webhook
What I need is to get that raw JSON.
You could try using CURL to retrieve the JSON object. Are you using CURL to send the payment payload out to the processor, etc? Below is an example (Obviously you would need to fill in the appropriate PHP variables where applicable).
$reqbody = json_encode($_REQUEST);
$serviceURL = "http://www.url.com/payment_processor";
$curl = curl_init($serviceURL);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $reqbody);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_VERBOSE, true);
$headers = array(
'Content-type: application/json',
"Authorization: ".$hmac_enc,
"apikey: ".$apikey,
"token: ".$token,
"timestamp: ".$timestamp,
"nonce: ".$nonce,
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ( $status != 201 ) {
die("Error: call to URL $serviceURL failed with status $status, response $json_response, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
}
curl_close($curl);
$response = json_decode($json_response, true);
echo "<hr/><br/><strong>PROCESSOR RESPONSE:</strong><br/>";
echo "<pre>";
print_r($response);
echo "</pre>";
You could get the json from requestbin and resend it to your localhost using a request client like Postman.
if (!empty($_POST)) {
$data = json_decode($_POST);
}
I found the solution, first you download HTML dom and then you just change the fields. The reason the for loop goes from 0-19 is because requestb.in saves 20 entries, for the rest just substitute the variables.
include('../simple_html_dom.php');
// get DOM from URL or file
// asegurese de incluir el ?inspect en el URL
$html = file_get_html('https://requestb.in/YOURURL?inspect');
for ($x = 0; $x <= 19; $x++) {
$result = $html->find('pre[class=body prettyprint]', $x)->plaintext;
if($result){
$json_a = str_replace('"', '"', $result);
$object = json_decode($json_a);
if(isset($object->type)) echo $object->type . "<br>";
if(isset($object->transaction->customer_id)) echo $object->transaction->customer_id . "<br>";
}
}

mailchimp http error: you must specify a apikey

I'm the using MailChimp 2.0 api and trying to post a lists/subscribe call using php. The call is returning an error "You must specify a apikey value".
Here's the code that makes the post:
function json_post ($url, $params)
{
print '<p>url = ' . $url . '</p>';
$data = json_encode ($params);
print '<p>data = ' . $data . '</p>';
$handle = curl_init ($url);
curl_setopt ($handle, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt ($handle, CURLOPT_POST_FIELDS, $data);
curl_setopt ($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($handle, CURLOPT_HTTPHEADER, array ('Content-Type: application/json',
'Content-Length: ' . strlen($data_string)));
$result = curl_exec ($handle);
print '<p>curl_error: ' . curl_errno ($handle) . '</p>';
return $result;
}
The print statements show:
url = https://us10.api.mailchimp.com/2.0/lists/subscribe.json
data = {"apikey":"...","id":"...","email":{"email":"test1#abc.com"},"merge_vars":{"groupings":{"name":"test"}}}
curl_error: 0
{"status":"error","code":-100,"name":"ValidationError","error":"You must specify a apikey value"}
I presume there's something wrong with the syntax. The api key is cut & pasted from my mailchimp account page. I've tried it with and without the -us10 suffix. Any ideas?
To subscribe:
$email='';
$apikey='';
$listId='';
$data = array(
'email_address'=>$email,
'apikey'=>$apikey,
'merge_vars' => array(),
'id' => $listId,
'double_optin' => false,
'update_existing' => true,
'replace_interests' => false,
'send_welcome' => false,
'email_type' => 'html'
);
$submit_url = "http://us6.api.mailchimp.com/1.3/?method=listSubscribe";
$payload = json_encode($data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $submit_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, urlencode($payload));
$result = curl_exec($ch);
curl_close ($ch);
$data = json_decode($result);
if (isset($data->error) and $data->error){
//Error
} else {
//Ok
}
Cases where you get "API Key Missing" but the API Key is definitely there usually comes from JSON Syntax errors, which MailChimp doesn't catch specifically. You'll want to make sure that JSON isn't getting double-encoded or anything like that.
In this case, it is probably CURLOPT_POST_FIELDS -- the actual PHP Constant you're looking for is CURLOPT_POSTFIELDS.
You should use Guzzle or another HTTP library to ensure you're not double-encoding your JSON or otherwise getting tripped up by the Curl library's verbosity.

Urban Airship push: Response: Got negative response from server: 0

I am trying to send push notification to my Android app from my server. But it is throwing error Payload: {"audience":"all","notification":{"android":{"alert":"PHP script test "}},"device_types":["android"]} Response: Got negative response from server: 0.
Below is the source code
<?php
define('APPKEY','**************Mw'); // Your App Key
define('PUSHSECRET','**********Low'); // Your Master Secret
define('PUSHURL', 'https://go.urbanairship.com/api/push/');
$contents = array();
$contents['alert'] = "PHP script test";
$notification = array();
$notification['android'] = $contents;
$platform = array();
array_push($platform, "android");
$push = array("audience"=>"all", "notification"=>$notification, "device_types"=>$platform);
$json = json_encode($push);
echo "Payload: " . $json . "\n"; //show the payload
$session = curl_init(PUSHURL);
curl_setopt($session, CURLOPT_USERPWD, APPKEY . ':' . PUSHSECRET);
curl_setopt($session, CURLOPT_POST, True);
curl_setopt($session, CURLOPT_POSTFIELDS, $json);
curl_setopt($session, CURLOPT_HEADER, False);
curl_setopt($session, CURLOPT_RETURNTRANSFER, True);
curl_setopt($session, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Accept: application/vnd.urbanairship+json; version=3;'));
$content = curl_exec($session);
echo "Response: " . $content . "\n";
// Check if any error occured
$response = curl_getinfo($session);
if($response['http_code'] != 202) {
echo "Got negative response from server: " . $response['http_code'] . "\n";
} else {
echo "Wow, it worked!\n";
}
curl_close($session);
?>
I am trying to run this php script from my browser. Push notification from urban airship server is working properly.
Thanks advance for any kind of help.
<?php
// DEVELOPMENT PUSH DETAILS
define('APPKEY','XXXXXXXXXXXXXXXXXXX');
define('PUSHSECRET', 'XXXXXXXXXXXXXXXXXXX'); // Master Secret
define('PUSHURL', 'https://go.urbanairship.com/api/push/');
/*
// PRODUCTION PUSH DETAILS
define('APPKEY','XXXXXXXXXXXXXXXXXXX');
define('PUSHSECRET', 'XXXXXXXXXXXXXXXXXXX'); // Master Secret
define('PUSHURL', 'https://go.urbanairship.com/api/push/');
*/
$push = array();
$push['aliases'] = $aliases; // Using alias that is set from the javascript after the device has registered to urban airship
$push['aps'] = array("badge"=>"+1", "alert" => $message); // for iphone
$push['android'] = array("alert"=>$message); // for android
$json = json_encode($push);
echo "Payload: " . $json . "\n"; //show the payload
$session = curl_init(PUSHURL);
curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($session, CURLOPT_USERPWD, APPKEY . ':' . PUSHSECRET);
curl_setopt($session, CURLOPT_POST, True);
curl_setopt($session, CURLOPT_POSTFIELDS, $json);
curl_setopt($session, CURLOPT_HEADER, False);
curl_setopt($session, CURLOPT_RETURNTRANSFER, True);
curl_setopt($session, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
$content = curl_exec($session); // $content has all the data that came back from urban airship..check its contents to see if successful or not.
// Check if any error occured
$response = curl_getinfo($session);
if($response['http_code'] != 200) {
$status = $response['http_code'];
echo "Got negative response from server: " . $response['http_code'] . "\n";
} else {
$status = 'ok';
}
curl_close($session);
?>
Here, $aliases is array type. It is list of aliases. $message is notification which you want to push. Assign value properly in this two variable. It will work..
According to the HTTP standards, you should include a space between "Content-Type:" and "application/json". Probably the Google server is not interpreting your content-type correctly making it an incorrect request ( It could even be it is rejected due to the Accept: values on the server side ).
Correct your content-type header and try again

Categories