send docx files using curl php - php

i am using the rest api for docusign.
i am sending a document to another user for online signing. What is happening in the code is that the document is being uploaded and the contents of the file is being read using the file_get_contents function and then using curl this content is sent to the other user through docusign.
Here is my code:
$data = "{
\"emailBlurb\":\"\",
\"emailSubject\":\"DocuSign API - Please Sign This Document...\",
\"documents\":[
{
\"documentId\":\"1\",
\"name\":\"agreement.pdf\"
}
],
\"recipients\":{
\"signers\":[
{
\"email\":\"$email\",
\"name\":\"$name\",
\"recipientId\":\"1\",
\"tabs\":{
\"signHereTabs\":[
{
\"xPosition\":\"100\",
\"yPosition\":\"100\",
\"documentId\":\"1\",
\"pageNumber\":\"1\"
}
]
}
}
]
},
\"status\":\"sent\"
}";
$file_contents = file_get_contents("uploads/envelopes/" . $file_name);
$requestBody = "\r\n"
."\r\n"
."--myboundary\r\n"
."Content-Type: application/json\r\n"
."Content-Disposition: form-data\r\n"
."\r\n"
."$data\r\n"
."--myboundary\r\n"
."Content-Type:application/pdf\r\n"
."Content-Disposition: file; filename=\”document.pdf\"; documentid=1 \r\n"
."\r\n"
."$file_contents\r\n"
."--myboundary--\r\n"
."\r\n";
// *** append "/envelopes" to baseUrl and as signature request endpoint
$curl = curl_init($baseUrl . "/envelopes" );
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $requestBody);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-Type: multipart/form-data;boundary=myboundary',
'Content-Length: ' . strlen($requestBody),
"X-DocuSign-Authentication: $header" )
);
$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ( $status != 201 ) {
$msg = 'Error. Please try again';
}
The above code is working fine for pdf files but not for docx files.
For docx files, i have changed the code like this (changed the content type):
$requestBody = "\r\n"
."\r\n"
."--myboundary\r\n"
."Content-Type: application/json\r\n"
."Content-Disposition: form-data\r\n"
."\r\n"
."$data\r\n"
."--myboundary\r\n"
."Content-Type:application/vnd.openxmlformats-officedocument.wordprocessingml.document\r\n"
."Content-Disposition: file; filename=\”document.docx\"; documentid=1 \r\n"
."\r\n"
."$file_contents\r\n"
."--myboundary--\r\n"
."\r\n";
Thanks

DocuSign does support sending .docx files, so file format is not causing your issue. Are you receiving a specific error message when you attempt to send a .docx file? If so, then what's the error?
FWIW, I'm able to send a .docx file via the DocuSign REST API -- I've included my full request below. If possible, I'd suggest that you use Fiddler (or any similar utility) to produce a trace of the full request that you're sending to the server, and compare its contents/structure with the (successful) example request that I've included below. Doing so would hopefully allow you to identify (and resolve) the problem with your request.
POST https://demo.docusign.net/restapi/v2/accounts/ACCOUNT_NUMBER/envelopes HTTP/1.1
X-DocuSign-Authentication: {"Username":"USERNAME","Password":"PASSWORD","IntegratorKey":"INTEGRATOR_KEY"}
Content-Type: multipart/form-data; boundary=MY_BOUNDARY
Accept: application/json
Host: demo.docusign.net
Content-Length: 15384
--MY_BOUNDARY
Content-Type: application/json
Content-Disposition: form-data
{
"status" : "sent",
"emailBlurb":"Test Email Body",
"emailSubject": "-- Test Email Subject --",
"documents": [
{
"name": "CustomerAgreement.docx",
"documentId": 1
}],
"recipients": {
"signers" : [{
"email": "bobsemail#outlook.com",
"name": "Bob Adamson",
"recipientId": "1",
"routingOrder": "1",
"tabs": {
"signHereTabs": [
{
"recipientId": "1",
"tabLabel": "Customer_Signature",
"documentId": "1",
"pageNumber": "1",
"xPosition": "99",
"yPosition": "424"
}]
}
}]
}
}
--MY_BOUNDARY
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Content-Disposition: file; filename="CustomerAgreement.docx"; documentid="1"
<document bytes removed>
--MY_BOUNDARY--

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.

Http request with PHP Bad Request Error

I try to access an API for a web app which will return the data in json format. The idea is to configure the header for the request to be read properly. An example request provided would be:
GET /links/{linkKey}/response HTTP/1.1
Access: *MY SECRET KEY*
Account: *MY ACCOUNT KEY*
Accept: application/json
Accept-Encoding: gzip
Host: localhost
User-Agent: YourApp/1.0
This example request should return this example response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: gzip
Transfer-Encoding: chunked
Vary: Accept-Encoding
{
"headers": [
"column_a",
"column_b",
"column_c"
],
"rows": [
[
"text 1",
143.22,
true
],
[
"text 2",
98,
false
],
[
"text 3",
24.9,
false
],
[
"value 4",
242,
false
],
[
"value 5",
32,
true
]
],
"totalRows": 5
}
Based on this, I wrote the following code:
<?php
// Set header
header('Content-type: application/json');
// See https://app.example.com/#/api
$endpoint = "https://api.example.com/"; // The URL for API access
$api_key = "*MY API_KEY*";
$account_id = "*MY ACCOUNT KEY*";
$access_key = md5($account_id . $api_key);
$link_key = '*MY LINK KEY*'; //Edit your runs inside the app to get their ID
$curl_h = curl_init($endpoint);
curl_setopt($curl_h, CURLOPT_HTTPHEADER,
array(
"GET /links/" . $link_key . "/latest/result HTTP/1.1\r\n",
"Access:" . $access_key . "\r\n",
"Account:" . $account_id . "\r\n",
"Accept: application/json\r\n",
"Accept-Encoding: gzip\r\n",
"Host: localhost\r\n",
"User-Agent: CS-PHP-CLIENT/1.0\r\n",
"Content-Type: application/json\r\n"
)
);
// Store to variable
curl_setopt($curl_h, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl_h);
curl_close($curl_h);
var_dump($response);
This outputs a 400 Bad Request error in the browser:
string(298) "<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.4.7 (Ubuntu) Server at example.com Port 80</address>
</body></html>
"
As you can see from above, the regulation of the provider is that the access_key must be encrypted using md5(). Given that at least string(298) appears, I alter the code to var_dump($curl_h), instead of var_dump($response). This eventually outputs an unknown response:
resource(2) of type (Unknown)
I rewrote the code into something different:
<?php
// See https://app.example.com/#/api
$endpoint = "https://api.example.com/"; // The URL for API access
$api_key = "*MY API_KEY*";
$account_id = "*MY ACCOUNT KEY*";
$access_key = md5($account_id . $api_key);
$link_key = '*MY LINK KEY*'; //Edit your runs inside the app to get their ID
// Create a stream
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"GET /links/" . $link_key . "/latest/result HTTP/1.1\r\n" .
"Access:" . $access_key . "\r\n" .
"Account:" . $account_id . "\r\n" .
"Accept: application/json\r\n" .
"Accept-Encoding: gzip\r\n" .
"Host: localhost\r\n" .
"User-Agent: CS-PHP-CLIENT/1.0\r\n" .
"Content-Type: application/json\r\n"
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents($endpoint, false, $context);
var_dump($file);
The following response appears in the browser when I run this code:
bool(false)
I don't know why this doesn't work.
NB: I'm using a localhost on my pc which loads other php files and their respective code correctly.
API Endpoint: https://api.example.com/
Text Encoding: All requests must be encoded in UTF-8 - and all responses are UTF-8 encoded.

Setting up GET cURL Request (PHP)

I'm a little confused on how to set up a cURL request to an API I'm working with. To be specific, it's for a fulfillment center called ShipStation (http://api.shipstation.com). I've done many cURL requests in the past but now I'm trying to figure out how to set up a 'MERGE' cURL request as opposed to a 'GET' cURL request, etc. You can see on here the 'GET' header to pull info from the API:
http://api.shipstation.com/Order-Resource.ashx#Reading_an_Order_5
And then to update/merge data:
http://api.shipstation.com/Order-Resource.ashx#Updating_an_Order_6
Every time I try to send a request though, I get curl_setopt(): supplied argument is not a valid cURL handle resource errors on several lines. I tried initially by copying the data and trying to send it as a header:
$header .= "GET https://data.shipstation.com/1.3/Orders(128714) HTTP/1.1";
$header .= "User-Agent: Microsoft ADO.NET Data Services";
$header .= "Accept-Charset: UTF-8";
$header .= "DataServiceVersion: 1.0;NetFx";
$header .= "MaxDataServiceVersion: 2.0;NetFx";
$header .= "Accept: application/atom+xml,application/xml";
$header .= "Host: data.shipstation.com";
//Send request
$curlConn = curl_init();
curl_setopt($curlConn,CURLOPT_USERPWD,'myusername:mypassword');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $header);
curl_setopt($curlConn,CURLOPT_RETURNTRANSFER,1);
$ret = curl_exec($curlConn);
curl_close($curlConn);
I do update the username and password to my credentials since you need that to log into this API. I basically copied the header as it was and it doesn't work. I also updated 'CURLOPT_CUSTOMREQUEST' to 'CURLOPT_HTTPHEADER' but both gave errors.
I'm not understanding where I'm going wrong and I also don't know how (if it's possible) to return more detailed error messages so I can get to the bottom of the problem with the code since I just get the supplied argument error.
Thanks for your help!
EDIT
Perhaps I'm approaching this wrong? How would I send a 'MERGE' request as evidenced in the documentation in the links above. I don't know how to take that info that they've given (the header info) and translate it into a request to the API.
Try in this way:
$end = "\r\n";
$header .= "GET https://data.shipstation.com/1.3/Orders(128714) HTTP/1.1" . $end;
$header .= "User-Agent: Microsoft ADO.NET Data Services" . $end;
$header .= "Accept-Charset: UTF-8" . $end;
$header .= "DataServiceVersion: 1.0;NetFx" . $end;
$header .= "MaxDataServiceVersion: 2.0;NetFx" . $end;
$header .= "Accept: application/atom+xml,application/xml" . $end;
$header .= "Host: data.shipstation.com" . $end;
//Send request
$curlConn = curl_init();
curl_setopt($curlConn,CURLOPT_USERPWD,'myusername:mypassword');
curl_setopt($curlConn, CURLOPT_CUSTOMREQUEST, $header);
curl_setopt($curlConn,CURLOPT_RETURNTRANSFER,1);
$ret = curl_exec($curlConn);
curl_close($curlConn);
Please try this:
$username = "YOUR API KEY";
$password = "YOUR API SECRET";
$endpoint = "https://ssapi.shipstation.com";
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_HTTPHEADER, array ("
Content-Type: application/json"
));
create_order($ch, $endpoint);
function create_order($ch, $endpoint) {
curl_setopt($ch, CURLOPT_URL, $endpoint . "/orders/createorder");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{
\"orderNumber\": \"ABC124\",
\"orderKey\": \"0f6aec18-3e89-4771-83aa-f392d84f4c74\",
\"orderDate\": \"2015-01-31T17:46:27.0000000\",
\"paymentDate\": \"2015-01-31T17:46:27.0000000\",
\"orderStatus\": \"awaiting_shipment\",
\"customerUsername\": \"headhoncho#whitehouse.gov\",
\"customerEmail\": \"headhoncho#whitehouse.gov\",
\"billTo\": {
\"name\": \"The President\",
\"company\": \"US Govt\",
\"street1\": \"1600 Pennsylvania Ave\",
\"street2\": \"Oval Office\",
\"street3\": null,
\"city\": \"Washington\",
\"state\": \"DC\",
\"postalCode\": \"20500\",
\"country\": \"US\",
\"phone\": null,
\"residential\": true
},
\"shipTo\": {
\"name\": \"The President\",
\"company\": \"US Govt\",
\"street1\": \"1600 Pennsylvania Ave\",
\"street2\": \"Oval Office\",
\"street3\": null,
\"city\": \"Washington\",
\"state\": \"DC\",
\"postalCode\": \"20500\",
\"country\": \"US\",
\"phone\": null,
\"residential\": true
},
\"items\": [
{
\"lineItemKey\": null,
\"sku\": \"ABC123\",
\"name\": \"Test item #1\",
\"imageUrl\": null,
\"weight\": {
\"value\": 24,
\"units\": \"ounces\"
},
\"quantity\": 2,
\"unitPrice\": 99.99,
\"warehouseLocation\": \"Aisle 1, Bin 7\",
\"options\": []
},
{
\"lineItemKey\": null,
\"sku\": \"DEF456\",
\"name\": \"Test item #2\",
\"imageUrl\": null,
\"weight\": {
\"value\": 0.01,
\"units\": \"ounces\"
},
\"quantity\": 3,
\"unitPrice\": 1.25,
\"warehouseLocation\": \"Aisle 7, Bin 34\",
\"options\": []
}
],
\"amountPaid\": 218.73,
\"taxAmount\": 5,
\"shippingAmount\": 10,
\"customerNotes\": null,
\"internalNotes\": \"This order was created via the ShipStation API\",
\"gift\": false,
\"giftMessage\": null,
\"requestedShippingService\": \"Priority Mail\",
\"paymentMethod\": null,
\"carrierCode\": \"fedex\",
\"serviceCode\": \"fedex_2day\",
\"packageCode\": \"package\",
\"confirmation\": \"delivery\",
\"shipDate\": \"2014-04-08\",
\"weight\": {
\"value\": 0,
\"units\": \"ounces\"
},
\"dimensions\": {
\"units\": \"inches\",
\"length\": 7,
\"width\": 5,
\"height\": 6
},
\"insuranceOptions\": {
\"provider\": null,
\"insureShipment\": false,
\"insuredValue\": 0
},
\"internationalOptions\": {
\"contents\": null,
\"customsItems\": null
},
\"advancedOptions\": {
\"warehouseId\": 34369,
\"nonMachinable\": false,
\"saturdayDelivery\": false,
\"containsAlcohol\": false,
\"storeId\": 42756,
\"customField1\": \"Some custom data\",
\"customField2\": null,
\"customField3\": null,
\"source\": null
}
}");
$response = curl_exec($ch);
curl_close($ch);
print_r($response);
}

How do I make a cURL post which sends both JSON data and a binary file?

I'm trying to create a PHP script which sends some JSON data together with a zipped file to an API (InMobi) but I can't get it to work. I usually just set the header to application/json and use curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); where $data is a PHP array but how do I attach the file on top of that?
The request should look like this:
Content-Type: multipart/form-data; boundary=AYip2bnLbOw0R2vf8lDZ71pon3CDottfPlckt-E Content-Disposition: form-data; name="payload"
Content-Type: application/json; charset=US-ASCII
Content-Transfer-Encoding: 8bit
{
"campaign": {
"name": "campaign-with-banner-ad",
"dailyBudget": "2000.00",
"startDate": "2012-03-10",
"endDate": "2012-05-31",
"action": "create",
"adGroups": [
{
"countryId": 94,
"name": "First AdGroup",
"bid": "1.89",
"landingURL": "http://test.inmobi.com/sampleapp",
"ctaDetails": {
"id": "1"
},
"action": "create",
"ads": [
{
"type": "banner",
"name": "From Root",
"filePath": "/",
"altText": "3 img add",
"action": "create"
},
{
"type": "banner",
"name": "From ad1",
"filePath": "/ad1/",
"action": "create"
},
{
"type": "banner",
"name": "From ad2",
"filePath": "/ad2/",
"action": "create"
}
]
}
]
}
}
--AYip2bnLbOw0R2vf8lDZ71pon3CDottfPlckt-E
Content-Disposition: form-data; name="zipFile"; filename="banners.zip" Content-Type: application/octet-stream; charset=ISO-8859-1
Content-Transfer-Encoding: binary
<Contents of ZIP File>
In all of the examples I've seen they put the file in CURLOPT_POSTFIELDS but I don't know how to combine that with json_encode and the above request looks like the file is sent in a separate part of the request.
Thanks!
Split the data into two fields:
$postdata = array(
'json' => json_encode($whatever),
'zipfile' => '#/path/to/yourfile.zip'
);
curl_setopt($curl, CURLOPT_POST_FIELDS, $postdata);
Then on the receiving end:
$json = json_decode($_POST['json');
$file = $_FILES['zipfile'];

Categories