PHP: how to convert shell_exec( cURL ) into Guzzle format? - php

The below cURL works while running shell exec but how do I format this in Guzzle?
shell_exec('curl https://*********************** -H "Authorization: *********************** -X POST -F attributes=\'{"name":"testFile.txt", "parent":{"id":"***********"}}\' -F file=#path/To/File.txt');
I want to convert the shell_exec into Guzzle format like the code below but it produces this error:
Client error: POST https://***********************
resulted in a `405 Method Not Allowed
$response = $client->request('POST', 'https://***********************', [
'debug' => true,
'headers' => $headers,
'form_params' => [
'attributes' => [
'name' => 'testFile.txt',
'parent' => [
'id' => '***********',
]
],
'file' => '#path/To/File.txt',
]
]);
Any idea what I need to change?

As #Zak already said, 405 is the server's response, it's has nothing to do with your code. You should get the same response with cURL.
BTW, to send files you need multipart, not form_params. And Guzzle doesn't support #... notation as command-line cURL does. So see the docs, there is an example.

Related

Can’t get a refreshed access_token using spotify api and laravel

First time using HTTP Client and Spotify API in Laravel.
The first step is to get a code by visiting
https://accounts.spotify.com/authorize?client_id=c1990...deed3&response_type=code&redirect_uri=http%3A%2F%2Fexample.test%2F&scope=user-read-currently-playing%20user-top-read
I then copy the code from the url after being redirected.
Then using curl -
curl -H "Authorization: Basic YzE5OT...Q2ZjA=" -d grant_type=authorization_code -d code=AQBX...X5zg -d redirect_uri=http%3A%2F%2Fexample.test%2F https://accounts.spotify.com/api/token
This returns the refresh token in JSON format -
{
"access_token":"BQBQL...vNDQ",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"AQCy...areM",
"scope":"user-read-currently-playing user-top-read"
}
But then I can't seem to get an access token using the refresh_token.
I'm getting "Bad Request" statusCode: 400 in my app
$response = Http::withHeaders([
'Authorization' => `Basic YzE5O...Q2ZjA`,
'Content-Type' => 'application/x-www-form-urlencoded'
])
->asForm()
->post(
'https://accounts.spotify.com/api/token',
[
'grant_type' => 'refresh_token',
'refresh_token' => 'AQC7...YphY'
]
);
Here is the documentation https://developer.spotify.com/documentation/general/guides/authorization/code-flow/.
Has anyone implemented this before in Laravel and if so how?
I have no idea about the Spotify API, but I am 99% sure your error is ->asForm(), you are sending that as a form instead of a normal request... so your code may need to be like this:
$response = Http::withToken('YzE5O...Q2ZjA')
->post(
'https://accounts.spotify.com/api/token',
[
'grant_type' => 'refresh_token',
'refresh_token' => 'AQC7...YphY'
]
);
See that I have removed ->asForm() and Content-Type (not sure why you are using that, it is a normal API... and ->asForm() already sets the same content you have manually set...
This is the Spotify API and I do not see any need to set the Conetnt-Type.
My bad, you need to set the ->asForm(), so the code should be:
$response = Http::withToken('YzE5O...Q2ZjA')
->asForm()
->post(
'https://accounts.spotify.com/api/token',
[
'grant_type' => 'refresh_token',
'refresh_token' => 'AQC7...YphY'
]
);
But I still think you are missing something. Check that your refresh_token is correct. Also lookf for more debugging output
This worked for me.
'Content-Type' => 'application/x-www-form-urlencoded' was removed from withHeaders
$response = Http::withHeaders([
'Authorization' => 'Basic ' . 123...123,
])
->asForm()
->post(
'https://accounts.spotify.com/api/token',
[
'grant_type' => 'refresh_token',
'refresh_token' => 123...456
]
);

Uploaded file opened using fopen error in guzzle json_encode error: Type is not supported

I cannot attach the uploaded file. I see that fopen($image->getPathname(),'r') returns not convertible json data type making guzzle return error json_encode error: Type is not supported. What am I doing wrong here? Thank you.
stream resource #586 ▼
timed_out: false
blocked: true
eof: false
wrapper_type: "plainfile"
stream_type: "STDIO"
mode: "r"
unread_bytes: 0
seekable: true
uri: "\Temp\php2D41.tmp"
options: []
//use Illuminate\Support\Facades\Http;
//use Illuminate\Support\Facades\File;
if($request->hasFile('imgInp1'))
{
foreach(request('imgInp1') as $image)
{
$message = Http::post('https://graph.facebook.com/v9.0/me/message_attachments?access_token='.$access_token,
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
'multipart' => [
'name' => 'image',
'image_path' => $image->getPathname(),
'image_mime' => $image->getmimeType(),
'image_org' => $image->getClientOriginalName(),
'contents' => fopen($image->getPathname(), 'r'),
],
'message'=>[
'attachment' => [
'type' => 'image',
'payload' => [
"is_reusable"=> true,
],
],
],
]);
}
}
From the url you used this is the curl request provided in facebook api_guide
curl \
-F 'message={"attachment":{"type":"image", "payload":{"is_reusable":true}}}' \
-F 'filedata=#/tmp/shirt.png;type=image/png' \
"https://graph.facebook.com/v9.0/me/message_attachments?access_token=<PAGE_ACCESS_TOKEN>"
This is what -F means in curl
-F, --form <name=content>
 (HTTP SMTP IMAP) For HTTP protocol family, this lets curl emu‐
late a filled-in form in which a user has pressed the submit
button. This causes curl to POST data using the Content-Type
multipart/form-data according to RFC 2388.
(Source: man curl)
By interpreting second line of curl,
You can also tell curl what Content-Type to use by using
'type=', in a manner similar to:
curl -F "web=#index.html;type=text/html" example.com
or
curl -F "name=daniel;type=text/foo" example.com
So it tells that you need multipart/form-data.
I am using guzzle directly inplace of using HttpClient(comes by default in laravel, comfirm from composer.json). Also I suggest to use try catch block as it is not necessary that it will always be 200 response.
$message["attachment"] = [
"type" => "image",
"payload"=> ["is_reusable"=>true]
];
try{
$client = new \GuzzleHttp\Client();
if(file_exists($image)){ // or can use \Illuminate\Support\Facades\File::exists($image)
$request = $client->post( 'https://graph.facebook.com/v9.0/me/message_attachments?access_token='.$access_token, [
// 'headers' => [], //if you want to add some
'multipart' => [
[
'name' => 'message',
'contents' => json_encode($message),
],
[
'Content-type' => $image->getmimeType(),
'name' => 'filedata',
'contents' => fopen($image->getPathname(), 'r'),
]
]
]);
if ($request->getStatusCode() == 200) {
$response = json_decode($request->getBody(),true);
//perform your action with $response
}
}else{
throw new \Illuminate\Contracts\Filesystem\FileNotFoundException();
}
}catch(\GuzzleHttp\Exception\RequestException $e){
// see this answer for https://stackoverflow.com/questions/17658283/catching-exceptions-from-guzzle/64603614#64603614
// you can catch here 400 response errors and 500 response errors
// see this https://stackoverflow.com/questions/25040436/guzzle-handle-400-bad-request/25040600
}catch(Exception $e){
//catch other errors
}

Missing parameter

I'm having trouble to pass the version parameter in a POST request using GuzzleHttp.
Client error: GET https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone resulted in a 400 Bad Request response: {"code":400,"sub_code":"C00005","error":"Missing a minor version parameter in the URL. To use the latest version, add th (truncated...)
This is the latest I've tried:
$client = new \GuzzleHttp\Client([
'base_uri' => 'https://gateway.watsonplatform.net/'
]);
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'form_params' => [
'version' => '2017-09-21',
'tone_input' => $text,
'sentences' => true
]
]);
This was failing too:
$client = new \GuzzleHttp\Client([
'base_uri' => 'https://gateway.watsonplatform.net/'
]);
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'version' => '2017-09-21',
'tone_input' => $text,
'sentences' => true
]);
Failing as well if using GET instead of POST.
If I change the URI and add the version, then it works fine (well, it fails as it doesn't have the text to analyse in the request):
Change: tone-analyzer/api/v3/tone
To: tone-analyzer/api/v3/tone?version=2017-09-21
So, I guess the question is HOW DO YOU PASS URL PARAMETERS in a request using GuzzleHttp?
Note: my CURL command works fine (http 200):
curl -X POST -u "{username}":"{password}" --header 'Content-Type: text/plain' --header 'Accept: application/json' --header 'Content-Language: en' --header 'Accept-Language: en' -d 'I hate these new features On #ThisPhone after the update.\r\n \
I hate #ThisPhoneCompany products, you%27d have to torture me to get me to use #ThisPhone.\r\n \
The emojis in #ThisPhone are stupid.\r\n \
#ThisPhone is a useless, stupid waste of money.\r\n \
#ThisPhone is the worst phone I%27ve ever had - ever 😠.\r\n \
#ThisPhone another ripoff, lost all respect SHAME.\r\n \
I%27m worried my #ThisPhone is going to overheat like my brother%27s did.\r\n \
#ThisPhoneCompany really let me down... my new phone won%27t even turn on.' 'https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone?version=2017-09-21&sentences=true'
You need to send "query" parameter for querystring. Pleaes check the below codes:
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'query' => [
'version' => '2017-09-21'
]
]);

How to send data to CloudFlare API?

I'm trying to delete files from my CloudFlare cache using PHP. Using Guzzle I've done this:
$client = new \GuzzleHttp\Client;
$response = $client->delete('https://api.cloudflare.com/client/v4/zones/myzoneid/purge_cache', [
'query' => [
'files' => 'https://example.com/styles.css,
],
'headers' => [
'X-Auth-Email' => 'myemail',
'X-Auth-Key' => 'myapikey',
],
]);
But when I run this I get an error:
Client error: DELETE https://api.cloudflare.com/client/v4/zones/myzoneid/purge_cache?files=https%3A%2F%2Fexample.com/etc resulted in a 400 Bad Request response: {"success":false,"errors":[{"code":1012,"message":"Request must contain one of \"purge_everything\", \"files\", \"tags\" (truncated...)
I can't get it to work using Postman either. I put in the required headers and try to set a key of files or files[] with the URL but it doesn't work. I've also tried data with raw JSON as the value like {"files":["url"]} (along with a JSON content-type header) but get the same error. It thinks I'm not sending the files key.
The method for purge_cache is POST instead of DELETE (Source: https://api.cloudflare.com/#zone-purge-files-by-url).
The payload is not sent as 'query', but as 'json'.
Files should be an array, not a string.
So the correct syntax should be....
$client = new \GuzzleHttp\Client;
$response = $client->post('https://api.cloudflare.com/client/v4/zones/myzoneid/purge_cache', [
'json' => [
'files' => ['https://example.com/styles.css'],
],
'headers' => [
'X-Auth-Email' => 'myemail',
'X-Auth-Key' => 'myapikey',
],
]);

CloudMQTT API Guzzle

I have a problem with translating curl to guzzle request.
In docs to create a user i just need to post:
$ curl -XPOST -d '{"username":"test", "password":"super_secret_password"}' -H "Content-Type:application/json" -u "$CLOUDMQTT_USER:$CLOUDMQTT_PASSWORD" https://api.cloudmqtt.com/user
In my project I cannot use curl, so i use guzzle:
$client = new Client();
$res = $client->post('https://api.cloudmqtt.com/user', ['auth' => ['xxx', 'xxx'], 'body' => ["username"=>"user", "password"=>"super_secret_password"]]);
And user is created, I can see new user on the users list on panel, but server is responsing with 500 when creating the user. What am I doing wrong? Maybe my guzzle request is wrong format? I have no idea
https://www.cloudmqtt.com/docs-api.html link to API
This will match up your Guzzle request to the curl request, although I can't say for sure that will solve your 500 error:
$client = new Client([
'headers' => [ 'Content-Type' => 'application/json' ]
]);
$response = $client->post('https://api.cloudmqtt.com/user',
[
'auth' => ['xxx', 'xxx'],
'body' => json_encode(
[
"username"=>"user",
"password"=>"super_secret_password"
]
)
]
);
The differences here include setting the Content-Type header and also encoding the body to json instead of an array (which may not have an effect here?).
EDIT:
It looks like the json parameter will automatically set the header and json_encode the body for you:
$client = new Client();
$response = $client->post('https://api.cloudmqtt.com/user',
[
'auth' => ['xxx', 'xxx'],
'json' =>
[
"username"=>"user",
"password"=>"super_secret_password"
]
]
);
Docs

Categories