I'm trying to post a Third party Api with raw body with my controller , It works fine when I test it from localhost , but when I publish my project on the Server (Cpanel) , I get this Error :
GuzzleHttp\Exception\ConnectException: cURL error 7: Failed to connect.
Here is an example of my code inside the controller :
use Illuminate\Support\Facades\Http;
public function testApi(){
$array = [
'FullName' => 'Full Name',
'PhoneNumber' => '9999999999',
'Date' => '2022-06-26 17:20',
'Note' => '',
];
try {
$response = Http::withBody(json_encode($array) , 'application/json')
->post('https://example');
return $response->status();
} catch (Exception $exception){
return $exception;
}
}
and I also tried using GuzzleHttp and the same thing it works on localhost , and not working when I publish the project on the server.
use GuzzleHttp\Client;
public function testApi(){
$array = [
'FullName' => 'Full Name',
'PhoneNumber' => '9999999999',
'Date' => '2022-06-26 17:20',
'Note' => '',
];
try {
$client = new Client();
$response = $client->request('POST', 'https://example', [
'body' => json_encode($array),
'headers' => [
'Content-Type' => 'application/json',
]
]);
return $response->getStatusCode();
} catch (Exception $exception){
return $exception;
}
}
before disable firewall and test again.
there can be a firewall that blocks your requests
Related
I searched online but couldn't find a proper solution. I am calling a Spring service with a POST request using Guzzle Client, The service in case of any errors provides the error message in its URL param like: http://localhost:8085/fedauth/null?errMessage=Mot%20de%20passe%20invalide%20pour%20l'utilisateur%20Karan%20Sharma.. How can I fetch this param errMessage using Guzzle. Below is my code with Slim in PHP.
$data = [
'userName' => base64_encode($userName),
'userPassword' => base64_encode($userPassword),
'institution' => $institution,
'redirectUrl' => $redirectUrl,
'callerUrl' => $callerUrl,
'clientId' => $clientId,
'encryptMode' => $encryptMode,
'moodleLandPage' => $moodleLandPage,
'login' => $login,
'isEncrypted' => true
];
try {
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
} catch (Exception $exception) {
return $response->write(json_encode(['error' => $exception->getMessage(), "auth" => "0" ]));
}
I have tried using the getEffectiveUrl() method but its no longer supported in Guzzle 7
I guess you get the response as a redirect url? Your question is not clear in that point. In this case you can access it like this:
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
echo $apiResponse->getEffectiveUrl();
like here: https://docs.guzzlephp.org/en/5.3/http-messages.html#responses
Actually found the answer. You need to add track redirects option as true and then use $response->getHeaderLine('X-Guzzle-Redirect-History'); like below
$client = new GuzzleHttp\Client(['headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded'], 'verify' => false, 'allow_redirects' => ['track_redirects' => true]]);
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
echo $apiResponse->getHeaderLine('X-Guzzle-Redirect-History');
use GuzzleHttp\Client;
function insert_freshdesk_note($ticketId, $content, $attachments=null)
{
if(is_null($content)) {
return false;
}
$url = 'https://mydomain.freshdesk.com/api/v2/tickets/'.$ticketId.'/notes';
$method = 'POST';
$userName = config('freshdesk_api_key');
$password = 'password';
$data = (!empty($attachments)) ? [
"attachments[]" => $attachments,
"body" => $content,
"private" => false,
] : [
"body" => $content,
"private" => false,
];
$options = (!empty($attachments)) ? [
'json' => $data,
'auth' => [$userName, $password],
'headers' => ['content-type' => 'multipart/form-data']
] : [
'json' => $data,
'auth' => [$userName, $password]
];
$client = new Client();
try {
$response = $client->request($method, $url, $options);
return json_decode($response->getBody(), true);
} catch (Exception $e) {
Log::error($e);
}
}
Above code is working fine without attachments but when an attachment comes into the picture it's throwing the following error:-
GuzzleHttp\Exception\ClientException: Client error: `POST https://mydomain.freshdesk.com/api/v2/tickets/13033/notes` resulted in a `400 Bad Request` response:
{"description":"Validation failed","errors":[{"field":"{\"attachments","message":"Unexpected/invalid field in request","
I am working according to the documentation and I have hit a dead end as of this point. I tried other permutations and combinations but via those, I wasn't able to resolve this problem.
Can anyone please help me.
Here is the link of the documentation of freshdesk
And in $attachments[] = '#/path/to/xyz.ext' this particular is going.
The function call will go like this:-
insert_freshdesk_note($this->freshdesk_ticket_id, $noteText, $image->image_full_path);
In the above question, I was trying to achieve the addition of note using GuzzleHTTP Client, Laravel Framework, and PHP language. Here's the following source code by which it starts working.
use GuzzleHttp\Client;
function insert_freshdesk_note($ticketId, $content, $attachments=null)
{
if(is_null($content)) {
return false;
}
$url = 'https://mydomain.freshdesk.com/api/v2/tickets/'.$ticketId.'/notes';
$method = 'POST';
$userName = config('freshdesk_api_key');
$password = 'password';
$attachmentsFilePath = explode('/',$attachments);
$fileName = end($attachmentsFilePath);
$options = (!empty($attachments)) ? [
'multipart' => [
[
'name' => 'body',
'contents' => $content,
],
[
'name' => 'private',
'contents' => "false",
],
[
'name' => 'attachments[]',
'contents' => fopen($attachments, 'r'),
'filename' => $fileName,
],
],
'auth' => [$userName, $password],
] : [
'json' => [
"body" => $content,
"private" => false,
],
'auth' => [$userName, $password]
];
$client = new Client();
try {
$response = $client->request($method, $url, $options);
return json_decode($response->getBody(), true);
} catch (Exception $e) {
Log::error($e);
}
}
We have to send the data in multipart fashion in order to Freshdesk backend to understand that data is there, by writing multipart/form-type in the header won't help. If you look at documentation also with and without attachments below:-
Without Attachment:-
curl -v -u user#yourcompany.com:test -H "Content-Type: application/json" -X POST -d '{ "body":"Hi tom, Still Angry", "private":false, "notify_emails":["tom#yourcompany.com"] }' 'https://domain.freshdesk.com/api/v2/tickets/3/notes'
With Attachment:-
curl -v -u user#yourcompany.com:test -F "attachments[]=#/path/to/attachment1.ext" -F "body=Hi tom, Still Angry" -F "notify_emails[]=tom#yourcompany.com" -X POST 'https://domain.freshdesk.com/api/v2/tickets/20/notes'
The difference in the curl can be seen.
This was the missing piece that I overlooked.
I have the following curl command
sudo curl -E openyes.crt.pem --key openyes.key.pem https://sky.myapitutorial.in:444/app/live/get
which works fine. But when I am trying to do from Guzzle, its failing.
I am unable to pass the client certificates in the request.
This is what I tried
$headers = ['Content-Type' => 'application/json','X-Client-Id' => config('mykey') , 'X-Client-Secret' => config('mykey')];
$client = new client();
try {
$response = $client->post(
$endpoint
,
['json' => $content, 'headers' => $headers,['connect_timeout' => 650]],
[
'config' => [
'curl' => [
'CURLOPT_SSLKEY' => base_path().'/openyes.key.pem',
'CURLOPT_SSLCERT' => base_path().'/openyes.crt.pem',
'CURLOPT_VERBOSE' => true
],
]
],
['debug'=>true],
['http_errors' => false]
);
dd($response);
}
catch (GuzzleHttp\Exception\ClientException $e) {
$response = $e->getResponse();
throw $e;
}
I couldn't find any solution in Guzzle documentation.
Any idea why is this not working?
The error I am getting is
cURL error 35: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure (see http:\/\/curl.haxx.se\/libcurl\/c\/libcurl-errors.html)
You can use ssl_key and cert:
$response = $client->post(
$endpoint, [
'json' => $content,
'headers' => $headers,
'connect_timeout' => 650,
// add these
'cert' => '/path/to/openyes.crt.pem',
'ssl_key' => '/path/to/openyes.key.pem'
]
);
if they have a pass phrase, you can set them like this:
'cert' => ['/path/to/openyes.crt.pem', 'password'],
'ssl_key' => ['/path/to/openyes.key.pem', 'password']
Currently using Laravel 5.5 and Guzzle that comes together with the laravel installer.
I am trying to make GET request (error occur with other HTTP requests as well) but don't seem work.
This code does not work:
public function callback(Request $request)
{
$code = $request->code;
$client = new Client(['exceptions' => false]);
try {
$response = $client->request('GET', 'http://localhost/api/tests');
// $response = $http->request('POST', Config::get('app.url') . '/oauth/token', [
// 'form_params' => [
// 'grant_type' => 'authorization_code',
// 'client_id' => Config::get('oauth_client.client_id'),
// 'client_secret' => Config::get('oauth_client.client_secret'),
// 'redirect_uri' => Config::get('oauth_client.redirect_uri'),
// 'code' => $code,
// ],
// ]);
// return json_decode((string) $response->getBody(), true);
} catch (\Exception $e) {
dd($e);
}
dd($response->getBody());
return;
}
But this code below is work very well
public function callback(Request $request)
{
$code = $request->code;
$client = new Client(['exceptions' => false]);
try {
$response = $client->request('GET', 'https://www.google.co.id');
// $response = $http->request('POST', Config::get('app.url') . '/oauth/token', [
// 'form_params' => [
// 'grant_type' => 'authorization_code',
// 'client_id' => Config::get('oauth_client.client_id'),
// 'client_secret' => Config::get('oauth_client.client_secret'),
// 'redirect_uri' => Config::get('oauth_client.redirect_uri'),
// 'code' => $code,
// ],
// ]);
// return json_decode((string) $response->getBody(), true);
} catch (\Exception $e) {
dd($e);
}
dd($response->getBody());
return;
}
I'm not understand why my Guzzle able to request to google.com but unable to connect to my own localhost server (to all ports).
Any help will greatly appreciate.
Thanks,
The reason why it does not work is that php artisan serve uses the PHP built-in web server and this is single threaded. So if you run your application it cannot make another request (your Guzzle request) until it finishes the initial request. That is why it hangs (as mentioned here).
One solution is (as you pointed out) to use a real webserver that is multi-threaded.
But if you still want to use php artisan serve instead of a web server like Nginx, there is an easy solution (that I already posted in another issue):
You could run another web server instance with another port and configure your application to use this base_uri when connecting to your API:
php artisan serve \\ defaults to port 8000
\\ in another console
php artisan serve --port=8001
$client->request('GET', 'http://localhost:8001/api/tests')
Using Apache2 and Virtual Host for my development server solved the problem, this approach more realistic than making any changes on my Guzzle parameters.
So my conclusion is Better to use real web server (Nginx, Apache) rather than artisan serve.
set 'CURLOPT_SSL_VERIFYPEER' option to false
public function callback(Request $request)
{
$code = $request->code;
$client = new Client(['exceptions' => false, 'CURLOPT_SSL_VERIFYPEER' => false]);
try {
$response = $client->request('GET', 'http://localhost/api/tests');
// $response = $http->request('POST', Config::get('app.url') . '/oauth/token', [
// 'form_params' => [
// 'grant_type' => 'authorization_code',
// 'client_id' => Config::get('oauth_client.client_id'),
// 'client_secret' => Config::get('oauth_client.client_secret'),
// 'redirect_uri' => Config::get('oauth_client.redirect_uri'),
// 'code' => $code,
// ],
// ]);
// return json_decode((string) $response->getBody(), true);
} catch (\Exception $e) {
dd($e);
}
dd($response->getBody());
return;
}
I have the following code to save content using API from another system. I have added the credentials but it showing wrong credentials error. It is working perfectly in postman.
$client = new GuzzleHttpClient();
try {
$request = new \GuzzleHttp\Psr7\Request('PUT', config('cms.api.backend') .'/products/'. $nid,
[
'auth' => [config('cms.api.user'), config('cms.api.password')],
'form_params' => [
'copywrite' => Input::get('copywrite'),
'status' => $status
],
]);
$promise = $client->sendAsync($request)->then(function ($response) {});
$promise->wait();
}
catch (RequestException $e) {
$this->logHttpError($e->getResponse()->getStatusCode(), $e->getResponse()->getBody(true));
}
What could be wrong in the above code?
Following is the exported code from postman.
$request = new HttpRequest();
$request->setUrl('http://mybackend/api/products/74371');
$request->setMethod(HTTP_METH_PUT);
$request->setHeaders(array(
'postman-token' => 'e0ddcaea-4787-b2c5-0c52-9aaee860ceac',
'cache-control' => 'no-cache',
'authorization' => 'Basic authenticationcode',
'content-type' => 'application/x-www-form-urlencoded'
));
$request->setContentType('application/x-www-form-urlencoded');
$request->setPostFields(array(
'copywrite' => 'date to be saved'
));
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
Third argument in \GuzzleHttp\Psr7\Request is for headers array only, so you won't send request body (4th arg) this way. Easiest way would be passing this array as second argument to sendAsync() method. It will recognise them and form_params option will be parsed as Content-Type: application/x-www-form-urlencoded header and create a valid stream for your request (it uses http_build_query() function if you want to do it directly in request constructor):
$request = new \GuzzleHttp\Psr7\Request('PUT', config('cms.api.backend') .'/products/'. $nid);
$options = [
'auth' => [config('cms.api.user'), config('cms.api.password')],
'form_params' => [
'copywrite' => Input::get('copywrite'),
'status' => $status
],
];
$promise = $client->sendAsync($request, $options)->then(function ($response) {});
$promise->wait();