php curl and CURLOPT_FOLLOWLOCATION behavior - php

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

Related

Error when trying to send file in CURL POST call

I am trying to make a call from my Laravel application to the Bullhorn API to convert a document to HTML, but it looks like the file isn't being attached to the call. Below is my code:
$data = curl_file_create("full/path/to/file.docx", 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'testcv');
$ch = curl_init();
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
$response = curl_exec($ch);
However I receive the following 500 error:
Bad File Uploaded: the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is application/x-www-form-urlencoded
When I try to set the Content-Type explicitly:
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: multipart/form-data'
));
I still receive a 500 error, just slightly different:
Bad File Uploaded: the request was rejected because no multipart boundary was found
I don't believe it's an issue with the Bullhorn API because executing the following call through the command line works fine:
curl -X POST "https://restXXX.bullhornstaffing.com/rest-services/{corptoken}/resume/convertToHtml?format=docx&BhRestToken={bhRestToken}" -F "file=#full\path\to\file.docx"
I assume that for some reason the file isn't being attached in my PHP call but I cannot figure out why.
Any help would be greatly appreciated.
The content-type: multipart/form-data uses boundary parameter for encapsulation, you can pass the boundary value as a string
'Content-Type: multipart/form-data; boundary=---------------------------7da24f2e50046'
Boundary is a string of "--" followed by a random string.
https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
If I ever have any weird problems with requests, I always put the request into postman and test it there since it compiles most of the headers and options for you, then just hit the code button on the top right to generate code in whatever language you want.
For your case you could datadump (dd) out your $data variable and copy it into one of the postman fields then set the url as well as the request type then run it and see what you get back.
Just a suggestion on how to debug a problem like this, hope it helps! good luck!

Oanda API v20 requests failing

I have tried the following code and receive a message saying my particular request is not supported, I cannot find any solutions that are not python for the v20 api. any help would be appreciated on what to use or where im going wrong
My error message is:
{"errorMessage":"Requested HTTP method is not supported for supplied
endpoint."}
<?php
$ch = curl_init();
$vars = "price=B&granularity=M5&count=20";
curl_setopt($ch, CURLOPT_URL,"https://api-fxpractice.oanda.com/v3/instruments/EUR_USD/candles");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$vars); //Post Fields
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$headers = [
'Content-Type: application/json',
'Authorization: Bearer access-token',
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$server_output = curl_exec ($ch);
curl_close ($ch);
print $server_output ;
?>
My goal here is to successfully connect and get the response from the endpoint containing data. I have no python experience which is why im trying curl or even a javascript solution would work. Am i just not understanding this API at all?
Two things that stand out in the code are:
that there is no actual authorisation code. I don’t know if you have removed it for security while posting, or if you don’t realise you need to create a practice account and get an authorisation code for it? Both are free.
Your code curl_setopt($ch, CURLOPT_POST, 1); suggests you are trying a POST, whereas a GET is required for the \instruments endpoint.
But the simplest thing I can suggest that might help is to look at the following Github bash script that has taken OANDA's V1 API bash cURL example, and updated it for the v2 rest API.
https://github.com/p-burke/oanda-REST-v2-API-bash-script

Set request type & content type in CURL request

I am using KODAK api to integrate photo print functionality in my website. All is working fine but it gives error message at the time of creating order as you can see on below URL
https://ws.test.kdfse.com/vasp2/rest/order/?retailer=Target&app=PNMEMORYDEMO&country=US&app_version=1.0
If you are not able to see the error message, you can see message which I have got as error
------------------------------
HTTP Status 401
type : Status report
message:Method Not Allowed
description : The specified HTTP method is not allowed for the requested resource (Method Not Allowed).
GlassFish Server Open Source Edition 3.1.2.2
------------------------------
For that reason, I have also talked with kodak api technical support but they said that make sure to set the correct "Request method" as POST and "Content-Type" as application/x-www-form-urlencoded when making this call.
I have used cURL for making this call but doesn't know how to set request type & content type in CURL request.
I am using below code. Please suggest & correct me for the same.
$ch = curl_init("https://ws.test.kdfse.com/vasp2/rest/order/PNPlasqTouch_T1366049430039_OKS13105x64222081_CTARGET/status/current");
curl_setopt($ch,CURLOPT_HEADER,1);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_TIMEOUT,60);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
$result=curl_exec ($ch);
echo "<pre>";print_r($result);exit;
Thanks in advance.
By HTTP Status 401 it means you are unauthorized. I have clicked your link and it asked for user/password. So set the authentication as follows:
// use your user/password at here
curl_setopt($curl, CURLOPT_USERPWD, "username:password");
You can use;
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
And final code will be;
$ch = curl_init("https://ws.test.kdfse.com/vasp2/rest/order/PNPlasqTouch_T1366049430039_OKS13105x64222081_CTARGET/status/current");
curl_setopt($ch,CURLOPT_HEADER,1);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_TIMEOUT,60);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
curl_setopt($curl, CURLOPT_USERPWD, "your_username:your_password");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
$result=curl_exec ($ch);
echo "<pre>";print_r($result);exit;
Update: You can see here for more detail about setting http headers. Also you are using secured service, you may set CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST as 1

cURL with PUT method

Is it possible to do a cURL request with the PUT method using only a URL? Here is the URL i would like to be able to call using cURL with the PUT method:
$url = https://url.net/card/activate.xml?card_id=1234567890&application_key=123123&accesskey=abcdef
I was able to make it work using the REST Console(Chrome Extension) but not using cURL. I tried using curl_setopt with CURLOPT_PUT, CURLOPT_INFILE and CURLOPT_INFILESIZE but I was receiving an empty page, no response at all.
This is the headers and curl options I currently have:
$header[] = 'Authorization: Basic abc123';
$header[] = 'Accept: text/xml';
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($soap_do);
Currently, with those settings, I'm getting the 411 Length Required error. Would it be possible to make it work like that or am I trying to configure something that will never work?
The HTTP 411 Error
The Web server (running the Web site) thinks that the HTTP data stream sent by the client (e.g. your Web browser or our CheckUpDown robot) should include a 'Content-Length' specification. This is typically used only for HTTP methods that result in the placement of data on the Web server, not the retrieval of data from it.
You need to set the Content Length of your Data
$header[] = 'Content-length: '.strlen($put_data);
OR If you don't have any data, just put 0 there.

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