Setting request body for Guzzle 6 put() - put

I am setting the request body incorrectly for these Guzzle put() calls. I am making get() calls to same API using same token without issue.
The API has a test environment and here is what a successful put call looks like in cURL:
curl -X PUT --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'Authorization: Basic tokenishere=' -d '{ \
"OrganizationCode": "10", \
"EventID": 5524, \
"FunctionID": 321, \
"Description": "Test" \
}' 'https://example.com/api/v1/Functions/10/5524/321'
My Guzzle code is
use GuzzleHttp\Psr7;
use GuzzleHttp\Exception\RequestException;
$client = new \GuzzleHttp\Client(array("base_uri" => "https://example.com"));
$response = $client->put("/api/v1/Functions/10/".$_SESSION['eventID'].'/'.$functionID,
array(
'headers' => array(
'token' => $token,
'debug' => true,
),
'body' => $data
)
I have also tried
$request = $client->put("/api/v1/Functions/10/$_SESSION[eventID]/$functionID", array('headers' => array('token' => $token)));
$request->setBody($data);
$response = $request->send();
And I have tried using param name json instead of body.
I have verified the JSON string in $data.
https://guzzle3.readthedocs.io/http-client/request.html shows an example where the body is 3rd arg:
$request = $client->put('http://httpbin.org/put', array(), 'this is the body');
So I also tried this below but same issue...
$request = $client->put("/api/v1/Functions/10/".$_SESSION['eventID'].'/'.$functionID, array(
'headers' => array(
'token' => $token,
'debug' => true,
)), $data);
Debug output is
PUT /api/v1/Functions/10/5524/321 HTTP/1.1
User-Agent: GuzzleHttp/6.3.3 curl/7.52.1 PHP/7.3.6-1+0~20190531112735.39+stretch~1.gbp6131b7
Host: example.com
token: tokenisreallyhere==
debug: 1
{"OrganizationCode":10,"EventID":"5524","FunctionID":"321","Description":"Test"}PUT /api/v1/Functions/10/5524/321 HTTP/1.1
User-Agent: GuzzleHttp/6.3.3 curl/7.52.1 PHP/7.3.6-1+0~20190531112735.39+stretch~1.gbp6131b7
Host: example.com
token: tokenisreallyhere==
debug: 1
{"OrganizationCode":10,"EventID":"5524","FunctionID":"321","Description":"Test"}HTTP/1.1 400 Missing model object in request body. Check body And header content type.
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
ETag: ""
X-Frame-Options: SAMEORIGIN
Date: Thu, 05 Sep 2019 21:57:06 GMT
Content-Length: 0
Where do I set the body?

Use form_params body is deprecated
$response = $client->put("/api/v1/Functions/10/".$_SESSION['eventID'].'/'.$functionID,
array(
'headers' => array(
'token' => $token,
'debug' => true,
),
'form_params' => $data
)

Of course the part I think is irrelevant is the answer: I did not show that I was using json_encode() on $data before passing it. The array, not a json object string, was expected so with $data as an array this works correctly.
$response = $client->put("/api/v1/Functions/10/".$_SESSION['eventID'].'/'.$functionID,
array(
'headers' => array(
'token' => $token,
'debug' => true
),
'json' => $data
)
);

Related

guzzle http post not working with form_params

When I try to send a Guzzle-POST, I always get a error returned:
{"errors":[{"code":"0","status":"400","title":"Bad Request","detail":"The JSON payload is malformed."}]}
As I don't see any error,inside the data-array itself, maybe it can be a wrong header information? It is an simple POST request to shopware 6 API where I try toadd a new article.
$payload= [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'form_params' =>[
"name" => "productname",
"productNumber" => "101003",
"stock" => 2,
"taxId" => "50ee15989533451095c9d7e03d9ce479",
"price" => [
[
"currencyId" => "b7d2554b0ce847cd82f3ac9bd1c0dfca",
"gross" => 15,
"net" => 10,
"linked" => false
]
]
]
];
$response = $client->request('POST', 'http://shopware6.shop.de/api/product',
$data
);
If I use Postman or RESTer or similar tools, I get a positive result, It works. So I guess I am missing sth. inside my guzzle-request (which is a copy of the origin documentation from https://shopware.stoplight.io/docs/admin-api/ZG9jOjEyMzA4NTUy-product-data )
I am using guzzle with kamermans oauth2 middleware
A simple GET-request is working too:
$response = $client->request('GET', 'http://shopware6.shop.de/api/product/{productid}',
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
]
]
);
You are missing the entire authentication in your request, which you might've omitted on purpose but I thought I should add it in the following example for the sake of completion.
Aside from that the cause for the bad request is using the key 'form_params', which is only used for Content-Type: multipart/form-data, instead of 'json' for the payload.
$response = $client->request('POST', 'http://localhost/api/oauth/token', [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'grant_type' => 'client_credentials',
'client_id' => '...',
'client_secret' => '...',
],
]);
$token = json_decode($response->getBody()->getContents(), true)['access_token'];
$payload = [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $token,
],
'json' => [
'name' => 'productname',
'productNumber' => '101003',
'stock' => 2,
'taxId' => '...',
'price' => [
[
'currencyId' => '...',
'gross' => 15,
'net' => 10,
'linked' => false,
],
],
],
];
$response = $client->request('POST', 'http://localhost/api/product', $payload);

eBay API error: Authorization is throwing the following error....invalid grant, invalid client

I am trying to authorize eBay user for exchanging token. Unfortunately, it's not working and returning 2type of error for different aspect. The errors are: 'invalid grant' and 'invalid client'
My code response is 200. But, in postman, it's showing the following response for 2 different Authorization criteria
Error for .. Authorization: Basic 'my code'
{
"error": "invalid_grant",
"error_description": "the provided authorization grant code is invalid or was issued to another client"
}
Error for .. Authorization: Bearer'my code'
{
"error": "invalid_client",
"error_description": "client authentication failed"
}
My Code:
<?php
$clientID = 'client_id';
$clientSecret = 'client_secret';
$authCode = 'authorization_code';
$url = 'https://api.sandbox.ebay.com/identity/v1/oauth2/token';
$redirectUrlName = 'redirect_uri';
$body = http_build_query([
'grant_type' => 'authorization_code',
'code' => $authCode,
'redirect_uri'=> $redirectUrlName
]);
$headers = [
'Cache-Control: no-cache',
'Accept : application/json',
'Content-Type : application/x-www-form-urlencoded',
'Authorization: Basic '.base64_encode($clientID.':'.$clientSecret)
];
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
// CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => $headers
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response."\n";
}
?>
Same thing worked for me, when I was trying for client credentials.
The body section seems to be incorrectly being passed:
'grant_type' => 'authorization_code'&,
'code' => $authCode&,
'redirect_uri'=> $redirectUrlName
In a working code for my case, here is how the body is passed:
CURLOPT_POSTFIELDS => 'grant_type=authorization_code&code=<code value>&redirect_uri=<uri for my test>',
The code was okay, except 2things.
Authorization code: This will come from eBay as a Response. We need to fetch the code.
$headers will have to write as following:
$headers = [
'Cache-Control: no-cache',
'Accept: application/json',
'Content-Type: application/x-www-form-urlencoded',
'Authorization: Basic '.base64_encode($clientID.':'.$clientSecret)
];
There Will have no space between Cache-Control and Colon(:). That mean, there will have no space at key and colon. Applicable for all key-value pair.

Replicate CURL multipart/form-data request with Guzzle / League OAuth2 Client

I am attempting to replicate a CURL POST request in Guzzle, but Guzzle request is failing.
This is the CURL request that works successfully:
$file = new \CURLFile( $document );
$file->setPostFilename( basename( $document ) );
$ch = curl_init();
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_URL, $endpoint );
curl_setopt( $ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $accessToken,
"Content-Type: multipart/form-data",
] );
curl_setopt( $ch, CURLOPT_POSTFIELDS, [ 'fileData' => $file ] );
$response = curl_exec( $ch );
And here is what I am currently using for the Guzzle request but it does not work:
$options['multipart'][] = [
'name' => 'fileData',
'contents' => fopen( $document, 'r' ),
'filename' => basename( $document ),
];
$request = $provider->getAuthenticatedRequest( 'POST', $endpoint, $accessToken, $options );
$response = $provider->getParsedResponse( $request );
The response from the Guzzle request is as follows:
{"message":"File cannot be empty","errors":[{"code":"Missing","fields":["document"]}]}
It's worth noting I am using the thephpleague/oauth2-client library to send the request. I'm looking for any discrepencies between the two request or information on how I can troubleshoot this further myself as I have been spinning my wheels all day on this. Much appreciated
thephpleague/oauth2-client uses different Providers to create the requests and these Providers implement AbstractProvider
The argument $options of AbstractProvider 's getAuthenticatedRequest() is different from GuzzleHttp\Client 's request():
/**
* Returns an authenticated PSR-7 request instance.
...
* #param array $options Any of "headers", "body", and "protocolVersion".
* #return RequestInterface
*/
public function getAuthenticatedRequest($method, $url, $token, array $options = [])
Only keys allowed for $options are "headers", "body", and "protocolVersion".
You should do the extra effort and create the headers and body needed:
$file = new \CURLFile( $document );
$file->setPostFilename( basename( $document ) );
$data = array(
'uploaded_file' => $file
);
$options = array(
'headers' => array("Content-Type" => "multipart/form-data"),
'body' => $data
);
$request = $provider->getAuthenticatedRequest( 'POST', $endpoint, $accessToken, $options );
Reference
Send file via cURL from form POST in PHP

Calling Twitter API results in "Timestamp out of bounds" Error

I am calling Twitter for fetching user Timeline Details. Here is my code
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterapi",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"authorization: OAuth oauth_consumer_key=\"XXXXXXX\",oauth_token=\"XXXXXXX\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"XXXXXXX\",oauth_nonce=\"XXXXXXXX\",oauth_version=\"1.0\",oauth_signature=\"XXXXXXX\"",
"cache-control: no-cache"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
I am able to fetch details. But after a day I am getting this response
{"errors":[{"code":135,"message":"Timestamp out of bounds."}]}
Is my Token getting expired ? I want to run this code as a background request.
The oauth_timestamp should be the number of whole seconds since 1 Jan 1970 00:00:00 UTC.
{"errors":[{"code":135,"message":"Timestamp out of bounds."}]}
Usually means that your server / machine time is off by more than 30 seconds (actual time not including time-zone differences). Look at the response header to see what Twitter's time is.
oauth_timestamp=1521786006

post data with curl and change page url

I have a shopping site and I have to send username and password and some other data to the bank, so I have used curl for posting data .because it should be safe.
but my problem is when I post data with curl to the bank, page url dont change! I see banks result in my server page !!!
I need this posting data same as posting data in html page redirect too the url which has been determined !!
$data = array(
"MID" => "0113-19",
"RedirectURL" => $SERVER . "/shop/profile.php",
"Amount" => $sum,
"ResNum" => $ResNum,
"username" => "xxxx",
"password" => "1234");
//traverse array and prepare data for posting (key1=value1)
foreach ( $data as $key => $value) {
$data[] = $key . '=' . urlencode($value);
}
$post_string = implode ('&', $data);
$res = array();
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_POST => true, // return web page
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_AUTOREFERER => false, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
CURLOPT_POSTFIELDS => $post_string, // stop after 10 redirects
CURLOPT_SSL_VERIFYPEER => false , // stop after 10 redirects
CURLOPT_COOKIEJAR => "cookie.txt" , // stop after 10 redirects
CURLOPT_COOKIEFILE => "cookie.txt" , // stop after 10 redirects
CURLOPT_SSL_VERIFYPEER => false , // stop after 10 redirects
CURLOPT_USERAGENT => "Mozilla/5.0 (Windows; U;
Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1" // stop after 10 redirects
);
//////////////////////
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );

Resources