PHP cURL: circumventing '#' denoting a file POST - php

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

Related

PHP Curl array post fields including a file upload

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);

Can't understand Instagram API code snippet

I was looking to do a project to understand how API integrations work in web applications. So, i chose instagram's login api. What it basically does is store user info like username etc. if somebody chooses to log into my website through instagram.
I didn't know where to begin so i started to go through other people's code, who had already done it. So there is a function called getAccessTokenAndUserDetails() that I don't understand. And here is the code snippet:
public function getAccessTokenAndUserDetails($code) {
$postFields = array(
"client_id" => $this->clientID,
"client_secret" => $this->clientSecret,
"grant_type" => "authorization_code",
"redirect_uri" => $this->redirectURI,
"code" => $code
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,
"https://api.instagram.com/oauth
/access_token");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
Apart from the $postFields associative array that is being set, this code is french to me. Need help.
curl is a command line tool for making web requests. This function is configuring and using this tool to access the remote api.
public function getAccessTokenAndUserDetails($code) {
// These are the parameters that the api needs to process the request.
// You can think of them like the information filled out by a human on a webform.
$postFields = array(
"client_id" => $this->clientID,
"client_secret" => $this->clientSecret,
"grant_type" => "authorization_code",
"redirect_uri" => $this->redirectURI,
"code" => $code
);
// Gets an instance of the curl tool
$ch = curl_init();
// curl_setopt configures the curl tool options
// all of the options can be found in the docs:
// https://www.php.net/manual/en/book.curl.php
// https://www.php.net/manual/en/function.curl-setopt.php
// The URL to fetch. This can also be set when initializing a session with curl_init().
curl_setopt($ch, CURLOPT_URL,
"https://api.instagram.com/oauth
/access_token");
// TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it directly.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 1 to check the existence of a common name in the SSL peer certificate.
// 2 to check the existence of a common name and also verify that it matches the hostname provided.
// 0 to not check the names. In production environments the value of this option should be kept at 2 (default value).
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
// FALSE to stop cURL from verifying the peer's certificate.
// Alternate certificates to verify against can be specified with the CURLOPT_CAINFO option
// or a certificate directory can be specified with the CURLOPT_CAPATH option.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
// TRUE to do a regular HTTP POST.
// This POST is the normal application/x-www-form-urlencoded kind, most commonly used by HTML forms.
curl_setopt($ch, CURLOPT_POST, 1);
// 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.
// The # prefix can be disabled for safe passing of values beginning with # by setting the CURLOPT_SAFE_UPLOAD option to TRUE.
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
// actually visits the site and stores the response in $response
$response = curl_exec($ch);
// close the connection and release the memory used by the curl tool
curl_close($ch);
// assumes that the response was JSON encoded, so decodes it into a more useful PHP format and returns the decoded value.
return json_decode($response, true);
}

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
]));

PHP & CURL not sending file, even with # prepended

I am using PHP (WAMPServer) to receive a form submission, and then CURL to pass the file to another server for processing.
Here is an example to illustrate (not the actual code):
$data = array(
'file' => '#'.$_FILES['key']['tmp_name']
);
Here's what I'm using for CURL... and as I was pasting the code I noticed that I still have http_build_query() in my code... so, that must be the problem.
$CURL = curl_init();
curl_setopt($CURL, CURLOPT_URL, $operation['callback']);
$query_string = http_build_query($arguments);
curl_setopt($CURL, CURLOPT_POSTFIELDS, $query_string);
curl_setopt($CURL, CURLOPT_POST, TRUE);
curl_setopt($CURL, CURLOPT_RETURNTRANSFER, TRUE);
$result = curl_exec($CURL);
curl_close($CURL);
return $result;
My problem is that the last server isn't receiving the file. Instead, the data is passed as a key-value pair.
$_POST contains 'file' => '#c:\wamp\tmp\xyz.tmp'
What I would prefer, is that the files was transferred, and $_FILES has information about it.
Don't build an http query for the CURLOPT_POSTFIELDS. Curl can directly accept an array of fields and do its own encoding/mangling.
By building your own query, you're 'hiding' the # that indicates a file upload and CURL will not trigger its upload mechanisms.
In other words, this will fix things:
$data = array(
'file' => '#'.$_FILES['key']['tmp_name']
);
curl_setopt($CURL, CURLOPT_POSTFIELDS, $data);
if you add your CURL method code, we could better answer you...
Try to transfer the file as binary, and add the filesize in the header in your curl.

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