How to attach excel file in Mandrill using php curl - php

I am trying to add an excel file (.xlsx) as an attachment to the email I am sending out through the Mandrill API. I am using CURL in a php file to send the email. The excel file is named Report.xlsx.
Here is a link to Mandrill API to use CURL.
Here is a link an other question going over adding file paths.
I receive the following error message:
PHP Parse error: syntax error, unexpected 'path' (T_STRING) in
/var/www/html/newFolder/EmailAlertSystem/mailchimp-mandrill-api-php/UsageReport.php
(****Which is my directory of my code)
This is my php code to send out the email via Mandrill:
$uri = 'https://mandrillapp.com/api/1.0/messages/send.json';
$api_key = 'APIKEY';
$content = 'all the content I want to add';
$content_text = strip_tags($content);
$from = 'FROM';
$fromName = 'FROMNAME';
$to = 'TO';
$toName = 'TONAME';
$subject = 'SUBJECT';
$fullName = "FIRSTNAME LASTNAME";
$attachment = file_get_contents('Report.xlsx');
$attachment_encoded = base64_encode($attachment);
$postString = '{
"key": "' . $api_key . '",
"message": {
"html": "' . $content . '",
"text": "' . $content_text . '",
"subject": "' . $subject . '",
"from_email": "' . $from . '",
"from_name": "' . $fromName . '",
"to": [
{
"email": "' . $to . '",
"name": "' . $fullName . '"
}
],
"track_opens": true,
"track_clicks": true,
"auto_text": true,
"url_strip_qs": true,
"preserve_recipients": true,
"attachments" : array(
array(
'path' => $attachment_encoded,
'type' => "application/xlsx",
'name' => 'Report.xlsx',
)
)
},
"async": false
}';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
//this is the executable curl statement that will actually send the email
$result = curl_exec($ch);
Any help would be greatly appreciated!!! Please let me know if I was unclear and what I am doing wrong. Thank you in advance!

The error seems to refer to this part
"attachments" : array(
array(
'path' => $attachment_encoded,
'type' => "application/xlsx",
'name' => 'Report.xlsx',
)
)
Right there, the string is terminated before path and then restarted, its a syntax error.
Something like,
"attachments" : array(
array(
\'path\' => $attachment_encoded,
\'type\' => "application/xlsx",
\'name\' => \'Report.xlsx\',
)
)
i.e. having the quotes escaped should fix it, but... the rest of that string looks like JSON. Is the attachments portion supposed to be in PHP-like array format? Might want to double-check.

Related

Gemini API via PHP cURL: InvalidSignature

I converted the following Python code from the official docs(https://docs.sandbox.gemini.com/rest-api/#private-api-invocation) to PHP but I always get InvalidSignature error:
url = "https://api.gemini.com/v1/mytrades"
gemini_api_key = "mykey"
gemini_api_secret = "1234abcd".encode()
t = datetime.datetime.now()
payload_nonce = time.time()
payload = {"request": "/v1/mytrades", "nonce": payload_nonce}
encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
signature = hmac.new(gemini_api_secret, b64, hashlib.sha384).hexdigest()
request_headers = {
'Content-Type': "text/plain",
'Content-Length': "0",
'X-GEMINI-APIKEY': gemini_api_key,
'X-GEMINI-PAYLOAD': b64,
'X-GEMINI-SIGNATURE': signature,
'Cache-Control': "no-cache"
}
response = requests.post(url, headers=request_headers)
My PHP code is this and everything looks correct:
$b64 = base64_encode(utf8_encode(json_encode([ "request" => "/v1/balances", "nonce" => time() ])));
$header = [
'Content-Type: text/plain',
'Content-Length: 0',
'X-GEMINI-APIKEY: master-XXXXXXX',
'X-GEMINI-PAYLOAD: ' . $b64,
'X-GEMINI-SIGNATURE: ' . md5(hash_hmac('sha384', utf8_encode('XXXXXXXXXX'), $b64)),
'Cache-Control: no-cache'
];
$ch = curl_init('https://api.sandbox.gemini.com/v1/balances');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
echo curl_exec($ch);
Error:
{"result":"error","reason":"InvalidSignature","message":"InvalidSignature"}
I don't have any access to the API, but could you please try the following chagnes:
Remove the MD5 function from the signature calculation. The hash_hmac function in PHP already does this by default.
'X-GEMINI-SIGNATURE: ' . hash_hmac('sha384', utf8_encode('XXXXXXXXXX'), $b64),
Switch around the payload and the key in the same line:
'X-GEMINI-SIGNATURE: ' . hash_hmac('sha384', $b64, utf8_encode('XXXXXXXXXX')),

Getting "Invalid Key Character" With generated PHP string on Json Curl

So, i'm trying to communicate with a curl for a project using php, and send data from my database with the POST method.
but i'm getting the "Invalid Key Character" error, and i really don't know what else to do to fix this...
The code:
<?php
require_once('autoload.php');
require_once('vendor/autoload.php');
$conexao = new Conexao();
$produtos = $conexao->select('produto', '*', 'LIMIT 1');
foreach ($produtos as $produto) {
try {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "url");
$headers = array();
$headers[] = "Content-Type: application/json";
$headers[] = "X-Api-Key: key";
$headers[] = "X-App-Key: key";
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($curl, CURLOPT_HEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_POST, TRUE);
$status = 1;
if ($produto['status'] == 1){
$status = 0;
}
$valores = '
{
"product":{
"name":"'. trim($produto['descricao']) .'",
"sku":"'. trim($produto['cod_est']) .'",
"description":"'. trim($produto['obs']) .'",
"price":'. $produto['valor_vend'] .',
"saleprice":'. $produto['vl_promo'] .',
"categories": [
"'. trim($produto['ender3']) .'"
],
"properties": [],
"related_products": [],
"special_options": [],
"slug":"'. str_replace(' ', '-', trim($produto['descricao'])) .'",
"excerpt":"'. trim($produto['descricao']) .'",
"factory_price":'. $produto['ult_custo'] .',
"installments": 1,
"shippable":0,
"fixed_quantity": 999,
"gtin_code":"'. trim($produto['cod_fabr']) .'",
"ncm_code":"'. trim($produto['cod_ncm']). '",
"track_stock": 0,
"enabled":' . $status . ',
"video": "",
"weight":"' . $produto['peso_brut']. '",
"height": "' . $produto['espessura'] . '",
"width": "' . $produto['largura'] . '",
"depth": "' . $produto['compriment'] . '",
"meta": "",
"seo_title": "",
"seo_description":"'. trim($produto['descricao']) . '",
"seo_keywords":"'. str_replace(' ',',',strtolower(trim($produto['descricao']))) .'"
}
}';
curl_setopt($curl, CURLOPT_POSTFIELDS, $valores);
$response = curl_exec($curl);
curl_close($curl);
print_r($response);
}
catch (Exception $e){
echo 'Ocorreu um Erro: ' . $e;
}
}
The error:
HTTP/1.1 200 OK Content-Type: text/html; charset=UTF-8 Content-Length: 263 Connection: keep-alive Cache-Control: max-age=1, public Date: Wed, 27 Dec 2017 19:09:30 GMT Expires: Wed, 27 Dec 2017 19:09:31 GMT Server: Apache Vary: Accept-Encoding X-Cache: Miss from cloudfront Via: 1.1 f2e2a7eca4778c8776461616fad77017.cloudfront.net (CloudFront) X-Amz-Cf-Id: urR4k92zkT2PCfimpCNAf5-uBmUi46nvHM6J-aWVZ8OxDYZUPteEWg== Disallowed Key Characters. "\r\n\t\t{\r\n\t\t\t\"product\":{\r\n\t\t\t\t\"name\":\"PH_CAMISA_GOLA_V_BR_12\",\r\n\t\t\t\t\"sku\":\"2129246\",\r\n\t\t\t\t\"description\":\"\",\r\n\t\t\t\t\"price\":49_000,\r\n\t\t\t\t\"saleprice\":0_000,\r\n\t\t\t\t\"categories\":_"
if i copy the generated json and paste to JSONLint, it shows that the json is valid...
Any Tips on how to solve this?
You just don't build JSON by hand in PHP.
You first build your data structure and THEN you json_encode() the whole thing...
$valores = [
"product" => [
"name" => trim($produto['descricao']),
"sku" => trim($produto['cod_est']),
"description" => trim($produto['obs']),
"price" => $produto['valor_vend'],
"saleprice" => $produto['vl_promo'],
"categories" => [
trim($produto['ender3']) // I'm not so sure here...
],
"properties" => [],
...
...
...
]
];
// $valores is an array containing your data.
$encoded = json_encode($valores);
// $encoded is a string containing encoded JSON.
json_encode() handles everything for you (escaping, etc.). It also has some options - for that see the manual.

Using curl to post request handle JSON data

I recently work with kraken.io API and I'm trying to integrate this API wuth my PHP CodeIgniter framework. So I followed the documentation but I got stuck when I used curl
This is my source code below ..
require_once(APPPATH.'libraries/kraken-php-master/Kraken.php');
$kraken = new Kraken("SOME_KEY", "SOME_SECRET");
$params = array(
"file" => base_url()."include/".$dataIn['logo'],
"wait" => true
);
$dataj='{"auth":{"api_key": "SOME_KEY", "api_secret": "SOME_SECRET"},"file":'.base_url()."include/".$dataIn['logo'].',wait":true}';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.kraken.io/v1/upload");
curl_setopt($ch, CURLOPT_HTTPHEADER,array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $dataj);
$response = curl_exec($ch);
curl_close($ch);
$data = $kraken->upload($params);
print_r($response);exit();
And I got this result
"{"success":false,"message":"Incoming request body does not contain a valid JSON object"}1"
So can anyone please help me,
And thanks in advance,
DONT POST YOUR API_KEY AND API_SECRET
The error message is quite clear, your json object is not valid. For instance this would be a valid JSON object for your request:
{
"auth": {
"api_key": "SOME",
"api_secret": "SECRET"
},
"file": "somefile.txt",
"wait": true
}
In your php code you are setting up a $params array but then you don't use it. Try this:
$dataj='{"auth":{"api_key": "SOME_KEY", "api_secret": "SOME_SECRET"},"file":"' . $params["file"]. '", "wait":true}';
You can validate your JSON HERE
You should use json_encode function to generate your JSON data
$dataj = json_encode([
"auth" => [
"api_key" => "API_KEY",
"api_secret" => "API_SECRET"
],
"file" => base_url() . "include/" . $dataIn['logo'],
"wait" => true
]);
EDIT:
Here is an example from https://kraken.io/docs/upload-url so you don't need to use curl
require_once("Kraken.php");
$kraken = new Kraken("your-api-key", "your-api-secret");
$params = array(
"file" => "/path/to/image/file.jpg",
"wait" => true
);
$data = $kraken->upload($params);
if ($data["success"]) {
echo "Success. Optimized image URL: " . $data["kraked_url"];
} else {
echo "Fail. Error message: " . $data["message"];
}

How to programatically HTTP POST a CSV file directly from an array in PHP?

I'm contributing data to the opencellid.org website. They have several API options to submit data but the only bulk method requires an HTTP POST file upload with the API key as a POST field. Formats acceptable are CSV, JSON and CLF3. I store the data in an SQL database for internal use and periodically submit data to opencellid.
At the moment the script that I use to submit the data to opencellid queries the SQL DB for the most recent measurements and then saves it as a CSV file on the server and then immediately uploads it via HTTP POST. In my eyes this is inelegant.
So my question is, can you POST upload a CSV file directly from an array without first having to actually create a CSV file on the server?
Here's the code snippet we currently use.
//Create and save CSV
$output = fopen("opencellid.csv","w") or die();
fputcsv($output, array_keys($celldata[0]));
foreach($celldata as $cell) {
fputcsv($output, $cell);
}
fclose($output) or die();
//Upload CSV
$target_url = 'http://opencellid.org/measure/uploadCsv';
$file_name_with_full_path = realpath('./opencellid.csv');
$post = array('key' => 'opencellidapikey',
'datafile'=>'#'.$file_name_with_full_path.";type=text/plain");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$target_url);
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
$postresult = curl_exec ($ch);
Can anyone suggest a way to directly upload a CSV from an array?
I managed to capture the csv data in to a variable using fputcsv to php://output with output buffering. Since the service only allows multipart format for the submission, you need to construct the payload like this.
<?php
//Construct your csv data
$celldata = array(
array(
"heading1",
"heading2",
"heading3",
),
array(
1,
2,
3,
),
array(
4,
5,
6,
)
);
//Output to php://output
ob_start();
$outstream = fopen("php://output", 'w');
foreach($celldata as $cell) {
fputcsv($outstream, $cell);
}
fclose($outstream) or die();
$csv_data = ob_get_clean();
$url = 'http://opencellid.org/measure/uploadCsv';
// Taken from http://stackoverflow.com/questions/3085990/post-a-file-string-using-curl-in-php
// form field separator
$delimiter = '-------------' . uniqid();
// file upload fields: name => array(type=>'mime/type',content=>'raw data')
$fileFields = array(
'datafile' => array(
'type' => 'text/plain',
'content' => $csv_data,
),
);
// all other fields (not file upload): name => value
$postFields = array(
'key' => 'opencellidapikey', //Put your api key here
);
$data = '';
// populate normal fields first (simpler)
foreach ($postFields as $name => $content) {
$data .= "--" . $delimiter . "\r\n";
$data .= 'Content-Disposition: form-data; name="' . $name . '"';
$data .= "\r\n\r\n";
$data .= $content;
$data .= "\r\n";
}
// populate file fields
foreach ($fileFields as $name => $file) {
$data .= "--" . $delimiter . "\r\n";
$data .= 'Content-Disposition: form-data; name="' . $name . '";' .
' filename="' . $name . '"' . "\r\n";
$data .= 'Content-Type: ' . $file['type'] . "\r\n";
$data .= "\r\n";
$data .= $file['content'] . "\r\n";
}
$data .= "--" . $delimiter . "--\r\n";
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_POST, true);
curl_setopt($handle, CURLOPT_HTTPHEADER , array(
'Content-Type: multipart/form-data; boundary=' . $delimiter,
'Content-Length: ' . strlen($data)));
curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
curl_setopt($handle, CURLOPT_RETURNTRANSFER,1);
$result = curl_exec($handle);
var_dump($result);
I get API key error, but it should work.
Intreesting question. The only thing I can think of is that you echo the "csv data" with headers of a post and that it's a csv file. That should not create a file on the server afaik. Not sure fully how to approach it, but if you run set apache headers or whichever server system you're using. Give it a shot and let me know if it works.

OAuth2 integration with ExactOnline

I am trying to integrate our app with Exact Online website using OAuth2,or more specifically i am trying to create hour registration which should include "Employee","Project","Hours","Hours type".
function registerTime($access_token_for_data) {
//$dataToFilterAccounts = array('$filter' => 'IsSales eq true');
$dataToRetrieveFromEmployees = array('$select' => 'ID');
// $queryToFilterAccounts = http_build_query($dataToFilterAccounts);
$queryToRetrieveFromEmployees = http_build_query($dataToRetrieveFromEmployees);
// $dataToFilterItems = array('$filter' =>'IsSalesItem eq true');
$dataToRetrieveProjects = array('$select' => 'ID');
//$queryToFilterItems = http_build_query($dataToFilterItems);
$queryToRetrieveProjects = http_build_query($dataToRetrieveProjects);
$urlProjects = 'https://start.exactonline.nl/api/v1/638842/project/Projects';
$urlEmployees = 'https://start.exactonline.nl/api/v1/638842/payroll/Employees';
$curlProjects = curl_init($urlProjects);
$curlEmployees = curl_init($urlEmployees);
$headers = array(
'Authorization: Bearer ' . $access_token_for_data,
'Accept: application/json',
'Content-type: application/json'
);
curl_setopt($curlProjects, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curlProjects, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curlProjects, CURLOPT_URL, $urlProjects . '?' . $queryToRetrieveProjects);
curl_setopt($curlProjects, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($curlEmployees, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curlEmployees, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curlEmployees, CURLOPT_URL, $urlEmployees . '?' . $queryToRetrieveFromEmployees);
curl_setopt($curlEmployees, CURLOPT_CUSTOMREQUEST, 'GET');
$resultProjects = curl_exec($curlProjects);
$resultEmployees = curl_exec($curlEmployees);
$projectsData = json_decode($resultProjects, true);
$projectID = $projectsData["d"]["results"]["0"]["ID"];
$employeesData = json_decode($resultEmployees, true);
$employeeID = $employeesData["d"]["results"]["0"]["ID"];
curl_close($curlProjects);
curl_close($curlEmployees);
$urlTimeTransaction = 'https://start.exactonline.nl/api/v1/638842/project/TimeTransactions';
$curlTimeTransacation = curl_init($urlTimeTransaction);
$content = json_encode(array("Project" => $projectID, "Employee" => $employeeI));
curl_setopt($curlTimeTransacation, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curlTimeTransacation, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curlTimeTransacation, CURLOPT_POST, true);
curl_setopt($curlTimeTransacation, CURLOPT_POSTFIELDS, $content);
$createdTimeTransaction = curl_exec($curlTimeTransacation);
$status = curl_getinfo($curlTimeTransacation, CURLINFO_HTTP_CODE);
if ($status != 201) {
die("Error: call to URL $curlTimeTransacation failed with status $status, response $createdTimeTransaction, curl_error " . curl_error($curlTimeTransacation) . ", curl_errno " . curl_errno($curlTimeTransacation));
}
echo "HTTP status $status creating time registartion<br/><br/>";
curl_close($curlTimeTransacation);
}
And this is the error i get
Error: call to URL Resource id #56 failed with status 500, response { "error": { "code": "", "message": { "lang": "", "value": "Mandatory: Employee\r\nMandatory: Hours\r\nMandatory: Hour type" } } }, curl_error , curl_errno 0
But when i try to include any of these mandatroy fileds i get:
Error: call to URL Resource id #56 failed with status 400, response { "error": { "code": "", "message": { "lang": "", "value": "Error processing request stream. The property name 'Hours' specified for type 'Exact.Web.Api.Models.TimeTransaction' is not valid." } } }, curl_error , curl_errno 0
please note that /api/v1/638842 contains your division ID. You might want to change that into a variable.
Regarding your problem: please note that the error messages contain text to be consumed by humans. The actual technical names can be different. I always do it the other way around: I query the existing data and look at all fields, and then I know what to send. You can use the Query Tool for Exact Online in the app center of Exact to do the query on REST api of Exact Online (but I am biased because involved).
As Guido pointed out correctly, there is no field named Hours in the TimeTransaction on projects, there is a field named Hours on the manufacturing TimeTransaction. This is a little confusing, especially since the error message isn't very clear.
You need to set Quantity on TimeTransactions in order to specify the hours on a project's time transaction.

Categories