PHP Curl array post fields including a file upload - php

I need to do the following using PHP curl:
curl "https://the.url.com/upload"
-F file="#path/to/the/file"
-F colours[]="red"
-F colours[]="yellow"
-F colours[]="blue"
The code I have tried:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'file' => curl_file_create($file),
'colours' = ['red','yellow','blue']
]);
$response = curl_exec($ch);
But I just get an error 'Array to string conversion in... (the colours line)'. If I remove the colours entirely then it works but I need to include them.
I have tried putting the post fields array in http_build_query() but then the server returns '415 Unsupported Media Type'. I'm guessing because it's missing a mime type (the file is a custom binary file).
I have also tried...
'colours[1]' = 'red'
'colours[2]' = 'yellow'
'colours[2]' = 'blue'
But the server returns an error saying colours must be an array. It's as though I need to create an associative array but with duplicate keys... which I know I can't do.
Can anyone help?

From the document of CURLOPT_POSTFIELDS.
This parameter can either be passed as a urlencoded string like 'para1=val1&para2=val2&...' or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data.
The function http_build_query() will make the value becomes 'para1=val1&para2=val2&...'.
So, I use this as post fields value as array and it work.
$postFields['hidden-input[0]'] = 'hidden value (from cURL).';
In your case, it should be.
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'file' => curl_file_create($file),
'colours[0]' => 'red',
'colours[1]' => 'yellow',
'colours[2]' => 'blue',
]);
Related answered: 1.
The manual array (name[0]) copied from PHP document in Example #2 CURLFile::__construct() uploading multiple files example.

While the answer from #vee should have worked, this came down to validation on this particular server application. After consulting with the vender, I ended up having to do this:
$headers = ['Content-type: multipart/form-data'];
$postFields = [
// NEEDED TO INCLUDE THE MIME TYPE
'file' => curl_file_create($file, mime_content_type($file)),
'colours[]' => ['red', 'yellow', 'blue'],
];
// NEEDED TO REMOVE THE NUMBERS BETWEEN SQUARE BRACKETS
$postFieldString = preg_replace('/%5B[0-9]+%5D/simU', '', http_build_query($postFields));
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFieldString);
$response = curl_exec($ch);

Related

Postman and cURL is returning different output

This is url I'm running in the postman :- http://213.252.244.214/create-signature.php. It has two parameters string and key. It will return input which you have entered and the output which is RJAGDhoz8yDJ7GwVLberI/NMYy2zMTTeR9YzXj7QhCM= but if I run it from the curl then it is returning D9UmS6r/qg0QI/0eIakifqrM3Nd1g6B3W7RCsiyO7sc=. The output is in JSON Format. Following is the cURL code:-
public function create_signature($input, $key) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'http://213.252.244.214/create-signature.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "string=$input&key=$key");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
$json = json_decode($output);
$signature = $json->output; echo $signature; echo '<br>';
curl_close($ch);
return $signature;
}
sample string is:- 2019-01-23 14:00:594lzUTYHw01dW5EmPan01M07hEiWUaEmdKl3kzpUUqak=Ha2wZwz46l7vSboxVNx3/DAUYsInjjKtAbDSnPsdDnA=igK7XzaTBrusPc3q5OEOQg==igK7XzaTBrusPc3q5OEOQg==1.0.110671523012111548248459fR9b/McBCzk=Deposit Fund698EURLuisTurinTurinVenis13212TF990303274103325689667lg#gmail.comLuisTurinTurinVenis13212TF990303274103325689667lg#gmail.comLuisTurinTurinVenis13212TF990303274103325689667lg#gmail.comclient_deposithttp://localhost/feature/CD-716/gateways/certus_finance/paymenthttp://localhost/feature/CD-716/gateways/certus_finance/paymenthttp://localhost/feature/CD-716/gateways/certus_finance/payment
sample key is :- 85e1d7a5e2d22e46
Can anyone tell me why is it different?? Any help will be appreciated.
Your $input and $key values are not being encoded. From the curl_setopt() manual page...
This parameter can either be passed as a urlencoded string ... or as an array with the field name as key and field data as value
Postman does this by default.
To save yourself having to manually encode strings, just use the array method
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'input' => $input,
'key' => $key
]);
Take note of this caveat though...
Note:
Passing an array to CURLOPT_POSTFIELDS will encode the data as multipart/form-data, while passing a URL-encoded string will encode the data as application/x-www-form-urlencoded.
If required, to ensure application/x-www-form-urlencoded, you can build an encoded string using http_build_query(), eg
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'input' => $input,
'key' => $key
]));

Can not send ampersand + curren via curl post ($currency=A&otherkey=B)

I got problem with ampersand + curren in my POST string on curl processing - instead POST values I got sunny character - ยค.
My question is:
how to send
['currency' => 'somevalue', 'otherkey' => 'othervalue']
with POST via curl.
I tried to form my POST as
$post_val = "otherVal=1&currency=USD";
or
$post_val = "otherVal=1&currency=USD";
or
$post_val = urlencode("otherVal=1&currency=USD");
and then
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_val);
What is strange - it gives the same effect when I pass currency as first in string - "currency=USD&otherVal=1".
Also I tried
$array = http_build_query(['currency' => 'somevalue', 'otherkey' => 'othervalue']);
curl_setopt($ch, CURLOPT_POSTFIELDS, $array);
Perhaps curl allways make http_build_query which also gives some additional signs which the source server can not interpret correctly?
Any ideas how to solve it?
cheers
Simple way out
$data = array('otheritem'=>'item', 'currency'=>'usd');
curl_setopt($ch, CURLOPT_POST,TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
this should work

PHP cURL: circumventing '#' denoting a file POST

I'm trying to make a cURL post, and one of the parameters includes a string prefixed with the '#' symbol. Typically for a cURL post, the '#' means I'm trying post a file, but in this case, I just want to pass the string prefixed with '#'. Is there a way, or what is the best way to get around this?
Here's my params array:
$params = array(
'UserID' => $this->username,
'Password' => $this->password,
'Type' => $type,
'Symbol' => $symbol, // this will look something like #CH14
'Market' => '',
'Vendor' => '',
'Format' => 'JSN'
);
And here's how my cURL post is taking place (the url is irrelevant to the actual problem.):
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
// Return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$response = curl_exec($ch);
if($response === FALSE)
{
$error = curl_error($ch);
$error_code = curl_errno($ch);
throw new Exception("CURL ERROR: #$error_code\n$error\n");
}
curl_close($ch);
return $response;
This works for everything I need it to do except when I need to pass it a symbol with an '#' in front. Any help would be greatly appreciated. Thanks.
According to the curl_setopt() manual entry:
CURLOPT_POSTFIELDS
The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with # and use the full path. The filetype can be explicitly specified by following the filename with the type in the format ';type=mimetype'. This parameter can either be passed as a urlencoded string like 'para1=val1&para2=val2&...' or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data. As of PHP 5.2.0, value must be an array if files are passed to this option with the # prefix. As of PHP 5.5.0, the # prefix is deprecated and files can be sent using CURLFile.
Hence, we can simply convert it to a string using http_build_query():
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
Use http_build_query() to build the query string.
From the documentation for the function:
Generates a URL-encoded query string from the associative (or indexed) array provided.
As stated above, it will correctly encode all the special characters as required. It can be used as below:
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
Online demo

Help encoding a cURL argument (works fine from the command line, but not from a PHP script)

I am working with the Facebook API, and successfully use the following command via terminal to post a message to another users wall.
curl -F 'access_token=XXXXXXXXXX' \
-F 'message=Hello World' \
-F 'to={["id":XXXXXXX]}' \
https://graph.facebook.com/me/feed
This works great. I am trying to do the same via php with this code;
$fields = array(
'access_token' => $t,
'message' => $message,
'to' => '{["id":'.$id.']}'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_exec($ch);
curl_close($ch);
This code successfuly posts a message, but it does it to my OWN wall (i.e. it is ignoring the 'to' parameter). I'm new to cURL, and I'm sure I am encoding it wrong, or maybe missing a cURL flag, but I've been through several tutorials on POSTing via cURL, including a few SO answers, and I can't see what I'm missing.
Really appreciate any help!
What does this print out?
if ( 'POST' == $_SERVER[ 'REQUEST_METHOD' ]) {
echo 'Posted: ';
print_r( $_POST );
exit;
}
$t = '121';
$message = 'helo Worlds';
$id = 1234;
$fields = array(
'access_token' => $t,
'message' => $message,
'to' => '{["id":'.$id.']}'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost:8888/testbed/' ); // THIS script
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE );
$out = curl_exec($ch);
curl_close($ch);
echo 'Received[ ' . $out . ' ]';
Prints this on my local box:
Received[ Posted: Array ( [access_token] => 121 [message] => helo Worlds [to] => {[\"id\":1234]} ) ]
UPDATED:
$fields should be a GET like string
para1=val1&para2=val2&...
or an array:
The full data to post in a HTTP "POST"
operation. To post a file, prepend a
filename with # and use the full path.
The filetype can be explicitly
specified by following the filename
with the type in the format
';type=mimetype'. This parameter can
either be passed as a urlencoded
string like
'para1=val1&para2=val2&...' or as an
array with the field name as key and
field data as value. If value is an
array, the Content-Type header will be
set to multipart/form-data. As of PHP
5.2.0, files thats passed to this option with the # prefix must be in
array form to work.

How to send form fields and a file using PHP Curl?

I'm trying to send form fields and file to a web service using php curl. The form has already been passed from a browser to a proxy php client web app and I'm trying to forward it to the web service.
When I pass an array to curl_setopt like this:
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $this->fields);
I get a Array to String notice although it is meant to take an array. Here's my array that is passed to $this->fields in the constructor.
$fields = array('title'=>$title,
'content'=>$content,
'category'=>$category,
'attachment'=>$_FILES['attachment']);
If I pass a string using http_build_query my web serivce complains about not having multipart/form data.
If I then force the multipart/form enctype using curl_setopt I get an error saying there's no boundary:
org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
Any ideas?
The array to string notice you have with the following code :
$fields = array(
'title'=>$title,
'content'=>$content,
'category'=>$category,
'attachment'=>$_FILES['attachment']
);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $fields);
is not because of you're passing an array as 3rd parameter to curl_setopt : it's because you're passing an array for attachment.
If you want to pass a file this way, you should pass its absolute path, pre-pending a # before it :
$fields = array(
'title'=>$title,
'content'=>$content,
'category'=>$category,
'attachment'=> '#' . $_FILES['attachment']
);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $fields);
(This is supposing that $_FILES['attachment'] contains the full path to your file -- up to you to change this code so it's using the right data, if needed)
As a reference, quoting the manual page of curl_setopt, for the CURLOPT_POSTFIELDS option :
The full data to post in a HTTP "POST" operation.
To post a file, prepend a filename with # and use the full path.
This can either be passed as a urlencoded string like 'para1=val1&para2=val2&...' or as an array with the field name as key and field data as value.
If value is an array, the Content-Type header will be set to multipart/form-data.
try this,
$filePath = "abc\\xyz.txt";
$postParams["uploadfile"] = "#" . $filePath;
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_URL, 'https://website_address');
curl_setopt($ch, CURLOPT_POST, 1 );
curl_setopt($ch, CURLOPT_POSTFIELDS, $postParams);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
if (curl_errno($ch))
{
echo curl_error($ch);
exit();
}
curl_close($ch);

Categories