I am currently working with php-curls and I had a question on an example I was looking at, the code is below.
$url = "https://my.test.api";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: 0' ));
$result = curl_exec($ch);
The question I had is, on the line curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");, what would be a benefit here of using POST vs GET, if that is a thing. I understand the difference between the two just not the case of using it in this situation.
Coming from the PHP-manual (http://php.net/manual/en/function.curl-setopt.php)
A custom request method to use instead of "GET" or "HEAD" when doing a HTTP request. This is useful for doing "DELETE" or other, more obscure HTTP requests. Valid values are things like "GET", "POST", "CONNECT" and so on; i.e. Do not enter a whole HTTP request line here. For instance, entering "GET /index.html HTTP/1.0\r\n\r\n" would be incorrect.
Which does not really make much sense to me.
If you are working with a REST api, a truly RESTful service will use HTTP semantics for what it is doing. You GET data that already exists. You POST new data. You PUT changes to data. You DELETE data.
Now, as far as actually working with an API, you can indeed use cURL for all 4 methods. However, it is often much easier, simple, and less code to use file_get_contents() for GET requests, IF your PHP install allows HTTP(s) URIs for the various fopen and related functions.
Related
I've been going round in circles trying to get this bit of code working. The problem I am facing is that there could be any number of places where something is wrong and I'm not experienced enough with cURL and API requests to know if I've just done something simple and silly somewhere. The code below is supposed to fetch a JSON response. What I am currently getting is "false". The API developer keeps giving me a CLI sample and I don't know how to "translate" that into something I can use in PHP.
I have to hide the domain, service name and authentication details in my examples.
The string I was given:
'https://[domain]/agw/latest/services/[service]-api/latest/api/v2/[service]-actual-prizes -vk -H "Proxy-Authorization: Basic [authstr]"'
([authstr] is the username and password, separated by a colon and BASE64 encoded - the API dev has confirmed that my authorisation string is correct)
What I have been trying:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://[domain]/agw/latest/services/lottery-api/latest/api/v2/sportka-actual-prizes');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Proxy-Authorization: Basic '.$authstr.'"
,"Content-type: application/json"
));
$response = curl_exec($ch);
curl_close($ch);
var_dump($response);
If I understand this correctly (and I'm not sure that I do), then I'm passing the URL (without flags), saying that I don't want a header in the response (I've tried TRUE as well without any success) and then passing headers with my request that includes the authorisation.
I've tried file_get_contents with a stream_context_create header but that fails too.
Am I missing a header option or flag or something in my cURL code?
How can I "correctly" upload the content of a file with cURL?
There are a lot of explanations and questions here where tmp files are send by curl with a #prefix on the file or using the curlFile api. In My use case I don't want to create a tmp file, and just post the content of file_get_contents('php://input') as body of the post request. The server does not accept multipart form requests.
The Following snipped will work in PHP7:
$body = file_get_contents('php://input');
$ch = curl_init();
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
It feels ugly to set the content type to json, no matter what the actual content of the stream may holds. But it seems to work. Sadly I need to support a really old version of PHP and feel like running out of options.
My question is:
Is the above example correct, even for PHP 7 or can it be made better?
Additionally: Is there any improvement or option that can be used to make this work with PHP 5.3.10? In this old version the post body always seems to be empty.
Finally I found and answer on this blog
Adding curl_setopt($curl, CURLOPT_POSTREDIR, 3); was the required option to acutally make the post request work without having an empty body.
Edit & heads up: This option is only needed when you expect your request to be redirected. I made a mistake while asking this question and posting the answer. Please check if your requests is redirected form http to https or the other way around and fix this first to prevent problems.
Copied from blog post of Evert Pot, linked above:
Using CURLOPT_POSTFIELDS you can supply a request body as a string.
Lets try to upload our earlier failed request using that method:
<?php
$curl = curl_init('http://example.org/someredirect');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl, CURLOPT_POSTFIELDS, file_get_contents('largefile.json'));
curl_exec($curl);
?>
This also will not work exactly as you expect. While the second
request to /someredirect will still be a POST request, it will be sent
with an empty request body.
To fix this, use the undocumented CURLOPT_POSTREDIR option.
<?php
$curl = curl_init('http://example.org/someredirect');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl, CURLOPT_POSTFIELDS, file_get_contents('largefile.json'));
curl_setopt($curl, CURLOPT_POSTREDIR, 3);
curl_exec($curl);
?>
According to the PHP changelog, this was added in PHP 5.3.2, and
according to PHP bug #49571 there are four possible values:
0 -> do not set any behavior 1 -> follow redirect with the same type
of request only for 301 redirects. 2 -> follow redirect with the same
type of request only for 302 redirects. 3 -> follow redirect with the
same type of request both for 301 and 302 redirects.
I am trying to delete a member of chat room from XMPP server via php. I am using curl request for that.
I am following this documentation:
https://www.igniterealtime.org/projects/openfire/plugins/restapi/readme.html#delete-a-user-from-a-chat-room
$url = "http://188.***.***.***/plugins/restapi/v1/chatrooms/".$roomName."/members/".$userJID;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/xml", "Authorization : ******")); //I am using plugin.userservice.secret key here
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
It should return me http response 201, but I am getting login form of server in response or 401 (unauthorized user).
I am trying to do this since last one week, but did not get any solution of this till, please help me.
Thanks in advance for your kind support.
Please note that this question if very specific: it relates to a specific XMPP server implementation (Openfire) and makes use of a proprietary, non-standard interface (its REST plugin). The fact that you're making use of an Android environment, PHP and/or cURL is irrelevant.
When you receive 401 responses, then there is a problem with authentication.
As Roman points out in a comment below, you're using the wrong documentation. Use this instead!
Two other observations that Roman made (out-of-band):
There's a surplus space character in "Authorization :" It need to be "Authorization:"
The property that you should use is plugin.restapi.secret, not plugin.userservice.secret.
Since this question is already well answered but I will like answer for Android specific context so other user coming to this question can find an alternate way.
There is a library for RestApiClinet for android here. You can integrate it directly as android module. Here is an app already using it. You can also have a look on this client library written in php.
I have written a very simple application to update my twitter status on a given condition. I have used the twitter documentation to understand the requirements of creating the OAuth signature and also how to structure the Authorization header. I then send the request with cURL in PHP.
Using the OAuth Tools on the twitter dev site, I compared both my signature base string and authorization header, and both are exactly the same:
Signature Base String
POST&https%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&oauth_consumer_key%3DYNxxxxxxxxxxxWnfI6HA%26oauth_nonce%3D31077a3c7b7bee4e4c7e2b5185041c12%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1340729904%26oauth_token%3D2991771-4csoiO2fxmWgSxxxxxxxxxxDjWj2AbyxATtiuadNE%26oauth_version%3D1.0%26status%3Dblah%2520test%2520blah.
Authorization header
Authorization: OAuth oauth_consumer_key="YN4FLBxxxxxxxxxxI6HA", oauth_nonce="31077a3c7b7bee4e4c7e2b5185041c12", oauth_signature="M2cXepcxxxxxxxxxxAImeAjE%2FHc%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1340729904", oauth_token="2991771-4cxxxxxxxxxxSmRvjzMoooMDjWj2AbyxATtiuadNE", oauth_version="1.0"
Obviously I've replaced some characters with x to hide my data, but comparing the two character for character yields exactly the same result. For reference, I hard-code the timestamp and nonce that the OAuth Tool generates so that my values can be the same for checking. My access level is set to Read and write. On that same page there is a final example - the command to run with cURL on the command line. When I run this command, it works perfectly and posts to my twitter feed with no issue.
With that in mind I believe everything I've created so far is fine, and don't think there's much point me posting the code that generates the details mentioned previously. However the code that I use to make the call, using cURL, I think is the culprit, but can't tell why:
<?php
// ...
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $baseUrl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: $header"));
curl_setopt($curl, CURLOPT_POSTFIELDS, array('status' => $status));
$result = json_decode(curl_exec($curl));
curl_close($curl);
var_dump($result);
Note that $baseUrl, $header and $status are the same variables used in generating the signature base string and authorization header, which matched just fine.
The output of the page when run is:
object(stdClass)#1 (2) { ["error"]=> string(34) "Could not authenticate with OAuth." ["request"]=> string(23) "/1/statuses/update.json" }
I hope there are enough details here for someone to point me in the right direction!
After much more searching, testing with apache_request_headers() and sticking to the notion that my data was fine and it was cURL where the problem laid, I realised that cURL was setting the Content-type of the request as multipart/form-data; and adding boundary information, obviously with a longer Content-Length field too. This meant that the status wasn't getting sent correct, I presume because of a malformed multipart/form-data; request.
The solution was to send it as a string. For instance, this works:
curl_setopt($curl, CURLOPT_POSTFIELDS, 'status='. rawurlencode($status));
But I found that there's an even nicer way (especially with multiple values, when I want to use an array):
$postfields = array('status' => $status);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postfields));
which looks much nicer IMHO.
I think it's your nonce. From the docs: "The oauth_nonce parameter is a unique token your application should generate for each unique request" (emphasis mine).
Caveat: I'm more familiar with OAuth 2 + Java or JavaScript rather than OAuth 1 + PHP.
If that's not it (or not the only thing), you could compare your actual HTTP request (e.g. using WireShark) to the sample request they document on that page. The note there on "Building the header string" may help too.
i have a hosted script somewhere that only accept POST request.
example, some.hosted/script.php
how can i setup another simple php that can accept GET request and then POST it to the hosted script.
so that i can put up a link like this: other.site/post2hostedscript.php?postthis=data
and then it POST postthis=data to the hosted script.
tnx
edit:
post2hostedscript.php do not give any result.
the result will go directly to some.hosted/script.php
just as if the user POST directly at the hosted script.
Your post2hostedscript.php will have to :
Fetch all parameters received as GET
Construct a POST query
Send it
And, probably, return the result of that POST request.
This can probably be done using curl, for instance ; something like this should get you started :
$queryString = $_SERVER['QUERY_STRING'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.othersite.com/post2hostedscript.php");
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $queryString);
curl_exec($ch);
curl_close($ch);
For a list of options that can be used with curl, you can take a look at the page of curl_setopt.
Here, you'll have to use, at least :
CURLOPT_POST : as you want to send a POST request, and not a GET
CURLOPT_RETURNTRANSFER : depending on whether you want curl_exec to return the result of the request, or to just output it.
CURLOPT_POSTFIELDS : The data that will be posted -- i.e. what you have in the query string of your incoming request.
And note that the response from the POST request might include some interesting HTTP header -- if needed, you'll have to fetch them (see the CURLOPT_HEADER option), and re-send the interesting ones in your own response (see the header function).
Take a look at the "curl" functions, they provide everything you need.
You might consider replacing all instances of $_POST in the old script to $_REQUEST, which will result in it accepting both GET and POST alike.