Bad request using file_get_contents for PUT request in PHP - php

This api call works fine using Postman (a REST Client),
but when making the request on the server in my GAE application I am currently getting the following error:
HTTP request failed! in C:\Projects\app\file.php on line 26
failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request in C:\Projects\app\file.php on line 26
Here is the code from my application, which makes a call to the rest api method /exampleMethod
$dataraw = [
'email' => 'email#ex.com',
'first_name' => 'firstname',
'last_name' => 'lastname',
'fEmail' => 'email#ex.com',
'message' => 'test'
];
$data = http_build_query ( $dataraw );
$context = [
'http' => [
'method' => 'PUT',
'header' => "Authorization: apikeystring\r\n" . "Content-Length: " . strlen($data) . "\r\n" . "Content-Type: application/json\r\n",
'content' => $data,
'proxy' => 'tcp://euproxy.example.com:0000'
]
];
$context = stream_context_create ( $context );
$result = file_get_contents ( $GLOBALS ['REST_API_URL'] . '/exampleMethod', false, $context );
In the application I have successfully used file_get_contents for GET requests, but with this PUT request I am getting a 400 bad request which is not coming from the Rest Api.

Change mb_strlen(serialize($dataraw), '8bit') to strlen($data)

Related

Unauthorized Mirosoft Graph request? Calendar.Read

I am trying to execute the following Microsoft Graph request:
$url = 'https://graph.microsoft.com/v1.0/me/calendarview?startdatetime=2020-04-17T12:13:36.933Z&enddatetime=2020-04-24T12:13:36.933Z';
$data = array('grant_type' => 'authorization_code', 'client_id' => '<myclientid>', 'client_secret' => '<myclientsecret>', 'redirect_uri' => 'http://localhost/myapp/request.php', 'code' => '<myauthorisationcode>');
$options = array(
'http' => array(
'header' => "Authorization: Bearer <myaccesstoken>",
'header' => "Host: login.microsoftonline.com",
'header' => "Content-type: application/json",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
var_dump($result);
Actually I should get information about my calendar now. But I receive the following warning:
Warning: file_get_contents(https://graph.microsoft.com/v1.0/me/calendarview?startdatetime=2020-04-17T12:13:36.933Z&enddatetime=2020-04-24T12:13:36.933Z): failed to open stream: HTTP request failed! HTTP/1.1 401 Unauthorized in C:\xampp\htdocs\myapp\request.php on line 16
bool(false)
In Azure I have added the following 3 API permissions: Calendars.Read, User.Read, User.Read.All.
my API Authorizations
Does anyone know why my request has not been accepted?
Thanks for your help!

HTTP request failed! with file get contents

I used OAuth for Dropbox to get access token: https://blogs.dropbox.com/developers/2012/07/using-oauth-1-0-with-the-plaintext-signature-method/
But I got error message:
Warning: file_get_contents(https://api.dropbox.com/1/oauth/request_token): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request
My PHP Code:
$Header = json_encode(array('Authorization: OAuth oauth_version="1.0"', "oauth_signature_method" => "PLAINTEXT", "oauth_consumer_key" => "XX", "oauth_signature" => "XX"));
$Options = array('http' =>
array(
'method' => 'POST',
'header' => $Header,
)
);
$Context = stream_context_create($Options);
$Result = file_get_contents("https://api.dropbox.com/1/oauth/request_token", false, $Context);
print_r($Result);
Based on the documentation at http://php.net/manual/en/context.http.php, it looks like the header option is just a normal string, not json_encoded. Alternatively, you should be able to use a numerically indexed array of headers, like so:
$Header = array(
"Authorization: OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\"XXXXX\", oauth_signature=\"XXXXX&\"\r\n"
);
$Options = array('http' =>
array(
'method' => 'POST',
'header' => $Header,
)
);
This is wrong:
$Header = json_encode(array('Authorization: OAuth oauth_version="1.0"', "oauth_signature_method" => "PLAINTEXT", "oauth_consumer_key" => "XX", "oauth_signature" => "XX"));
The header paramter in an http stream is either a simple single string containing one single header key: value, or an array of key: value strings. You're stuffing in a single json string as your header, meaning it's NOT a valid http header.
Remove the json_encode() part completely. $Header = array(...) is all you need.

doing a REST PUT in PHP

I hope my question will be understood, my english is a not so good.
I'm nearly new with PHP and I just discovered REST APIs: I'm trying to use a REST API from my PHP script. Docs for the API can be found here
My final goal is to get a single product from this webservice and update it by adding the wholesalePrices array.
I've already managed to perform a GET request using file_get_contents(), in order to get the product ID i want to update. Now I have such id but can't understand how to perform the PUT request: as far I can understand, there are mainly two ways to do REST calls in PHP: one with file_get_contents, another by using cURL.
Since I used file_get_contents for my GET request, I continued with this approach, but my code:
$wholesalePrices = json_encode($wholesalePrices);
$dataRAW = array(
"wholesalePrices" => $wholesalePrices
);
$dataToPut = http_build_query($dataRAW);
$context = [
'http' => [
'method' => 'PUT',
'header' => "Authorization: apikeystring\r\n" . "Content-Length: " . strlen($dataToPut) . "\r\n" . "Content-Type: application/json\r\n",
'content' => $dataToPut
]
];
$context = stream_context_create($context);
$url = "https://app.ecwid.com/api/v3/xxxxxxx/products/".urlencode($productId)."?token=".urlencode(myToken);
$result = file_get_contents ($url, false, $context);
returns a PHP warning:
Warning: file_get_contents(https://app.ecwid.com/api/v3/xxxxxxxxx/products/xxxxxxxxx?token=xxxxxxxxxxx): failed to open stream: HTTP request failed! HTTP/1.1 400 Wrong JSON format: A JSONObject text must begin with '{' at 1 [character 2 line 1] in upload.php on line 95
var_dumping $wholesalePrices just after the json_encode() results in
string '[{"quantity":1,"price":0},{"quantity":5,"price":6},{"quantity":25,"price":12},{"quantity":100,"price":25}]' (length=106)
where am I wrong?
ok, I tried using RamRaider approach and now my code is this
$data = json_encode(array('wholesalePrices' => $wholesalePrices)/*, JSON_FORCE_OBJECT*/);
$dataRAW = array(
"wholesalePrices" => $wholesalePrices
);
$dataToPut = $dataRAW;
$dataToPut = http_build_query($dataRAW);
$context = array('http' => array('method' => 'PUT',
'header' => "Authorization: apikeystring\r\nContent-Length: ".strlen($data)."\r\nContent-Type: application/json\r\n",
'content' => $data));
$context = stream_context_create($context);
$url = "https://app.ecwid.com/api/v3/".urlencode(MY_STORE_ID)."/products/".urlencode($productId)."?token=".urlencode(MY_TOKEN);
$result = file_get_contents ($url, false, $context);
But I obtain a HTTP request failed! HTTP/1.1 400 Field Product.wholesalePrices should be an array message.
If I comment the , JSON_FORCE_OBJECT instead, the HTTP message becomes 409 Conflict and it refers at the line with $result = file_get_contents ($url, false, $context); so perhaps I am on the right track, but how can I troubleshoot such error?
ok, done some mods: now - after the json_encode() - my dataToPut (which I put in "Content" in the HTTP request) var_dumps as following (WPPair is a class I specifically created to reproduce the format required):
object(stdClass)[3]
public 'wholesalePrices' =>
array (size=3)
1 =>
object(WPpair)[5]
public 'quantity' => int 5
public 'price' => int 6
2 =>
object(WPpair)[4]
public 'quantity' => int 25
public 'price' => int 12
3 =>
object(WPpair)[6]
public 'quantity' => int 100
public 'price' => int 25
so I think it has to be right for the api. But I still get a HTTP request failed! HTTP/1.1 400 Bad Request
Ok, finally I managed to form a (perhaps) right structure for my JSON, all the more so as Postman validates my dataToPut with an HTTP
200 OK
And my test record results updated.
This is the print_r() output on dataToPut after json_encode():
string
'{"id":56782231,"wholesalePrices":[{"quantity":5,"price":5.64},{"quantity":25,"price":5.28},{"quantity":100,"price":4.5}]}'
(length=121)
However, if I try to send the same JSON from my PHP page, I still get a
failed to open stream: HTTP request failed!
and in fact, my records still aren't updated.
Here's my code:
$dataToPut = $dataRAW;
$dataRAW = http_build_query($dataRAW);
$context = [
'http' => [
'method' => 'PUT',
'header' => "Authorization: apikeystring\r\n" . "Content-Length: ".sizeof($dataToPut)."\r\n" . "Content-Type: application/json\r\n",
'content' => $dataToPut
]
];
$context = stream_context_create($context);
$url = "https://app.ecwid.com/api/v3/xxxxxxx/products/".urlencode($productId)."?token=".urlencode(myToken);
$dataToPut = json_encode($dataToPut);
$result = file_get_contents($url, false, $context);
Where am I wrong this time?
After rewriting my code by using cURL instead of file_get_contents to connect to the API, I managed to get it to work.
Now the API call part looks like this:
$dataToPut = $dataRAW;
$dataRAW = http_build_query($dataRAW);
$context = [
'http' => [
'method' => 'PUT',
'header' => "Authorization: apikeystring\r\n" . "Content-Length: ".sizeof($dataToPut)."\r\n" . "Content-Type: application/json\r\n",
'content' => $dataToPut
]
];
$context = stream_context_create($context);
$url = "https://app.ecwid.com/api/v3/xxxxxxx/products/".urlencode($productId)."?token=".urlencode($myToken);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Host: app.ecwid.com','Content-Type: application/json;charset=utf-8','Cache-Control: no-cache'));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $dataToPut);
// Make the REST call, returning the result
$response = curl_exec($curl);
echo ($response."<br/>");
if (!$response) {
echo("Connection Failure: ".curl_error($curl));
die();
}
curl_close($curl);
Without seeing the documentation for their api I might be leading you astray but the error message does suggest that their api expects json data whereas you encode the data and then add to an array which seems back to front somehow.
$data = json_encode( array( 'wholesalePrices' => $wholesalePrices ), JSON_FORCE_OBJECT );
/* Perhaps this also is not required */
#$data = http_build_query( $data );
$context = array(
'http' => array(
'method' => 'PUT',
'header' => "Authorization: apikeystring\r\nContent-Length: " . strlen( $data ) . "\r\nContent-Type: application/json\r\n",
'content' => $data
)
);
$context = stream_context_create( $context );
$url = "https://app.ecwid.com/api/v3/7560546/products/".urlencode( $productId )."?token=".urlencode( myToken );
$result = file_get_contents( $url, false, $context );
Having had a quick look at the api documentation I found the following:
PUT https://app.ecwid.com/api/v3/{storeId}/products/{productId}?token={token}
Request body
A JSON object of type 'Product’ with the following fields:
wholesalePrices -> Array<WholesalePrice>
described as: "Sorted array of wholesale price tiers (quantity limit and price pairs)"
The given example request to update a product is:
PUT /api/v3/4870020/products/39766764?token=123456789abcd HTTP/1.1
Host: app.ecwid.com
Content-Type: application/json;charset=utf-8
Cache-Control: no-cache
{
"compareToPrice": 24.99,
"categoryIds": [
9691094
]
}
So using test data
$wholesalePrices=array(
array('quantity'=>10,'price'=>1000),
array('quantity'=>2,'price'=>43),
array('quantity'=>43,'price'=>34),
array('quantity'=>7,'price'=>5),
array('quantity'=>9,'price'=>63),
);
$data = json_encode( array( 'wholesalePrices' => $wholesalePrices ) );
echo '<pre>',$data,'</pre>';
Gives data in the format:
{
"wholesalePrices":[
{"quantity":10,"price":1000},
{"quantity":2,"price":43},
{"quantity":43,"price":34},
{"quantity":7,"price":5},
{"quantity":9,"price":63}
]
}

GAE, PHP and GCM: failed to open stream: HTTP request failed! HTTP/1.0 405 Method Not Allowed

I'm developing a web application (using GAE for PHP) that notifies android clients (via GCM - Google Cloud Messaging) when some content are available for download.
The following PHP script should do job:
$json = array(
'data' => array( ... ),
'registration_ids' => array( ... )
);
$data = json_encode( $json );
$context = array(
'http' => array(
'method' => 'post',
'header' => 'Authorization: key=MY_SECRET_KEY' . "\r\n" .
'Content-Type: application/json' . "\r\n",
'content' => $data
)
);
$context = #stream_context_create($context);
$result = #file_get_contents("https://android.googleapis.com/gcm/send", false, $context);
The above code runs correctly when the app is deployed, but do not when running on my local development environment.
On local development environment $result is null and the file_get_contents "echo" the following warning failed to open stream: HTTP request failed! HTTP/1.0 405 Method Not Allowed.
I finally figured out what was happening.
The HTTP/1.0 405 Method Not Allowed was related with the 'method' => 'post'.
Belive me, simply changing it to 'method' => 'POST' (note the uppercase!) did the trick.

PHP set protocol_version for stream_context_create

I want to access an oauth server with a php script, the remote server requires the following request:
POST /oauth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 81
Authorization: Basic CHAINE_ENCODEE
grant_type=password&username=USERNAME&password=PASSWORD&scope=all
So I wrote the following code:
$params = array ('grant_type' => 'password',
'username' => 'USERNAME',
'password' => hash('sha256', 'PASSWORD'),
'scope' => 'all',
);
$query = http_build_query ($params);
$contextData = array (
'protocol_version'=> '1.1',
'method' => 'POST',
'header' => "Connection: close\r\n".
"Content-Type: application/x-www-form-urlencoded\r\n".
"Content-Length: 81\r\n".
"Authorization: Basic ".base64_encode('APPIDENTIFIER:SECRET'),
'content' => $query );
$context = stream_context_create (array ( 'http' => $contextData ));
$result = file_get_contents (
'https://rest2.some-url.net/oauth/token', // page url
false,
$context);
return $result;
But this gives me the following error:
Warning: file_get_contents(https://rest2.some-url.net/oauth/token): failed to open stream:
HTTP request failed! HTTP/1.0 500 Internal Server Error
My guess is that the problem comes from the protocol_version which I set to 1.1 as required by the api. But the error apparently uses HTTP/1.0
I have tried every possible way, i have seen no one saying it was not working for them so I guess I am missing something. Why is not the HTTP set to HTTP/1.1?

Categories