cURL POST of custom binary data (not form contents) - php

The problem the following code piece successfully sends POST request but doesn't send the data in $sendStream (the stream is valid and contains data - this has been verified):
curl_setopt($request, CURLOPT_HTTPHEADER, array('Content-type: application/x-rethync-request'));
curl_setopt($request, CURLOPT_HEADER, true);
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
curl_setopt($request, CURLOPT_INFILE, $sendStream);
curl_setopt($request, CURLOPT_INFILESIZE, stream_length($sendStream));
curl_setopt($request, CURLOPT_CUSTOMREQUEST, "POST");
$response = curl_exec($request);
I've read probably all cURL POST-related posts here on SO, but no luck. Why is the data not posted?

The missing piece was
curl_setopt($request, CURLOPT_UPLOAD, 1);
The PHP documentation mentions this option briefly and nothing suggests that the option should be set. Still at least some (if not all) versions of cURL don't post data despite it's specified via CURLOPT_INFILE, unless CURLOPT_UPLOAD is also set.
NOTE: when you use this method to send the data, the response header will contain HTTP/1.1 100 Continue first, followed by HTTP/1.1 200 OK and so on. So when you parse response headers, beware of the first 100 Continue response (you'll need to strip it).

Related

using curl in php for real post request to remote server

I have to automate uploading values to a remote server by php script.
The interface accepts only POST variables - NO GET variables.
Interface documentation (for form field names) looks like:
iegUsername: your username
iegPassword: your password
iegImportFile: The UTF-8 encoded plain text import file. The file data may optionally be zipped.
This means i have to POST TWO VARIABLES and ONE FILE.
I'm new in Curl therefore i started in PHP with this:
// create curl resource
$request = curl_init();
// Array with the fields names and values
$postData = array(
'iegUsername' => 'myusername',
'iegPassword' => 'mypassword',
'submit' => 'ok'
);
//add file support with: 'file' => '#' . realpath('example.txt')
// set timeout if remote server is down
curl_setopt($request, CURLOPT_CONNECTTIMEOUT, 30);
// set remote target url
curl_setopt($request, CURLOPT_URL, ""); //for testing post on current page
//Enable the post response.
//curl_setopt($request, CURLOPT_POST, true);
curl_setopt($request, CURLOPT_CUSTOMREQUEST, "POST");
$headers = ['Content-Type: multipart/form-data'];
curl_setopt($request, CURLOPT_HTTPHEADER, $headers);
//The data to transfer with the response.
curl_setopt($request, CURLOPT_POSTFIELDS, $postData);
//return the transfer as a string
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
// disable verification
curl_setopt($request, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($request, CURLOPT_SSL_VERIFYHOST, false);
Actually i don't have added file support.
My Problem
In Browser dev tools i cannot see any POST only GET responses.
I need a real POST with data in it not a urled GET one...
Hopefully someone can give help.
okay, misunderstood of server side and client side. Thought a response back to my location should result in a post response within dev tools of browser, this is not correct.
POST works.

cURL retrieve only header without doing HEAD

So I am trying to retrieve only headers using cURL with the following:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, true); // we want headers
curl_setopt ($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
$output = curl_exec($ch);
The problem is that while trying to get headers of large file the script uses all the memory. I would like to avoid getting also the body and I have tried to use:
curl_setopt($ch, CURLOPT_NOBODY, true);
The problem is that this issues a HEAD request instead of GET. And some website retrun an error when you request with HEAD.
Is there any way with curl to retrieve only header without doing HEAD request?
First, don't use CURLOPT_RETURNTRANSFER as that's the option that makes it keep the entire response in memory.
Then, two options:
A) use a write callback and make that abort the transfer as soon as the first byte of the body is returned. There's a write callback example in the PHP.net docs.
B) use CURLOPT_RANGE and ask for only the first byte to be retrieved, 0-0. This avoids the write callback but has the downside that not all HTTP servers and URLs will acknowledge it.
If you dont have to use cURL, you could use get_headers(). By default get_headers uses a GET request to fetch the headers. And you could also modify that request by using stream_context_set_default()
$headers = get_headers('http://example.com');
More Info: PHP: get_headers

php curl and CURLOPT_FOLLOWLOCATION behavior

Here's the situation. On one side, we have a server, with a RESTful service. One possible query to it is a POST query to create an object. When that is done, the server returns a 'Location' header, to indicate where information on the newly created object can be found.
However, said server is anal about having the correct Content-Type for each request. For instance, POST requires 'application/json', and GET requires this to be unset (make sense, since GET doesn't have a body).
To sum up, we have:
www.example.com/articles/ ; one can send a POST request with 'Content-Type: application/json', and server will return 'Location: www.example.com/articles/123' if 123 is the id of the new object ;
www.example.com/articles/123 ; one can send a GET request with no 'Content-Type' and server will return a description of the new article object.
On client side, we use PHP with cURL. We use the CURLOPT_FOLLOWLOCATIONsetting so we can read the description of the newly created object. Obviously, we also set 'Content-Type: application/json' for our POST request:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"name": "test"}');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_URL, "https://www.example.com/Articles/");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$result=curl_exec($ch);
var_dump($result);
curl_close ($ch);
?>
This is what we get:
string(101) "{ "errorNo": 415, "error": "Unsupported Media Type Content-Type should not be set in a GET request" }"
I looked at the log of the server, and indeed, 'Content-Type: application/json' is sent to GET www.example.com/articles/123.
Is this an expected behaviour?
If yes, what is then best approach:
remove the 'Content-Type' check on GET requests, server-side?
(sounds silly)
forget about CURLOPT_FOLLOWLOCATION, and make 2 clearly separated curl requests, so I have control over the headers? (but then what's the point of CURLOPT_FOLLOWLOCATION?)
something else?
For control and testing, I also use Postman, and I have no problem with it, it follows the location, doesn't send the 'Content-Type' on the GET part (apparently) after the redirection and so I don't have an error.
EDIT:
There seems to be nothing useful in the PHP doc. But I found something interesting in the command line man page:
https://curl.haxx.se/docs/manpage.html
It says:
"WARNING: headers set with this option will be set in all requests - even after redirects are followed, like when told with -L, --location."
So I guess it probably is the expected behaviour for PHP too. May someone suggest best practices then?
Have you tried using
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
to set the post type

Which is more secure GET or POST sending parameters with cURL at PHP

I want to connect in a secure way with an API and I am using cURL to do it using HTTPS and SSL.
Now, i was wondering what is better in terms of security, sending the data through GET or POST:
$ch = curl_init("http://api.website.com/connect.php?user=xxx&pass=xxxx");
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
$result = curl_exec($ch);
curl_close($ch);
Or
$param['user'] = 'xxxx';
$param['pass'] = 'xxxx';
$ch = curl_init("http://api.website.com/connect.php");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $Parameters);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
$result = curl_exec($ch);
curl_close($ch);
I also realized that POST is much more slower retrieving the data.
Neither. "GET parameters" are part of the URL which is part of the HTTP request header, "POST parameters" are part of the HTTP request body. Both are part of the same HTTP request, which is all just plain text. There's no difference in "security".
Use GET or POST semantically depending on the kind of request, not because of security concerns.
The only thing is that the requested URLs are more likely to appear in log files than the entire request body. But the one logging would be the service you send the data to anyway, so it doesn't make much of a difference.
None of them is secure, but if you use a secure connection (https) you can use POST, asthe body will get encrypted. It is not a good idea to send passwords, not even usernames with the URI.
In this cause because you are using HTTPS, GET and POST as just as secure as eachother because both of which will be encrypted on the transport layer.
If for example you weren't using HTTPS then in some cases, POST can be better but not necessarily more secure. This is because servers typically log the querystring whereas POST data isn't typically logged.

Error Handling in Web service XML request

I've been trying to perform an XML request. I've faced so many problems that I managed to solve. But this one I couldn't solve.
this is the script:
$url ="WebServiceUrl";
$xml="XmlRequest";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_MUTE, 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_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_POSTFIELDS, "$xml");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
It is giving me this error:
System.InvalidOperationException: Request format is invalid: text/xml. at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters() at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()
I'm still a noob at this. So go easy on me:)
thanks.
Looks like you're sending stuff as text/xml, which is not what it wants. Find the docs for this web service e.g. WSDL stuff if it's there, and find out what data formats it accepts.
Be sure e.g. that it's not really saying it will respond in XML, after receiving a request as standard HTML POST variables.
There are two main content types used with the HTTP POST method: application/x-www-form-urlencoded and multipart/form-data.
The content-type determines what the format of the CURLOPT_POSTFIELDS should be. If you are using the default, which is "application/x-www-form-urlencoded" you probably want to use build_http_query() to construct the url encoded query string.
If you are sending non-ASCII data you canpass an associative array with keys that match the field names and values that correspond to the value for the field. Using this technique will cause the request to be issued with a multipart/formdata content-type.
At this point, it sounds like your next step should be figuring out what fields the API is expecting.
application/x-www-form-urlencoded or multipart/form-data?

Categories