I try to simulate the authorization LinkedIn web browser (PHP). I use Guzzle Http Client.
Here is part of the authorization code:
use GuzzleHttp\Client as LinkedinClient;
use PHPHtmlParser\Dom as Parser;
public function authLinkedin()
{
$client = new LinkedinClient(['base_url' => 'https://www.linkedin.com']);
try {
$postData = [
'session_key' => 'My_email',
'session_password' => 'My_password',
'action' => 'login'
];
$request = $client->createRequest('POST', '/uas/login', ['body' => $postData, 'cookies' => true]);
$response = $client->send($request);
if ($response->getStatusCode() === 200) {
$parser = new Parser();
$parser->load($client->get('https://www.linkedin.com/', ['cookies' => true])->getBody());
return $parser;
} else {
Log::store("Authorization error", Log::TYPE_ERROR, $request->getStatusCode());
return null;
}
return $request;
} catch (Exception $ex) {
Log::store("Failure get followers", Log::TYPE_ERROR, $ex->getMessage());
return null;
}
}
The request is successful, returns a 200 code, but I did not authorize.
Who can faced with a similar task, or in the code have missed something. I would appreciate any advice.
I think that the issue is with CSRF protection and other hidden parameters. LinkedIn, as other sites, usually returns 200 OK for all situations, even for an error, and describes details in resulting HTML.
In your case it's better to use a web scraper, like Goutte. It emulates a user with a browser, so you don't need to worry about many things (like CSRF protection and other hidden fields). Examples can be found on the main pages, try something like this:
$crawler = $client->request('GET', 'https://www.linkedin.com');
$form = $crawler->selectButton('Sign In')->form();
$crawler = $client->submit($form, array(
'login' => 'My_email',
'password' => 'My_password'
));
You can use it with Guzzle as a driver, but some sites might require JavaScript (I'm not sure about Amazon). Then you have to go to a real browser or PhantomJS (a kind of headless Chrome).
I would like to use Guzzle to check if a remote file exists.
This is an example of how I am currently checking:
/**
* #return boolean
*/
function exists()
{
// By default get_headers uses a GET request to fetch the headers.
// Send a HEAD request instead
stream_context_set_default(
array(
'http' => array(
'method' => 'HEAD'
)
)
);
// Get the file headers
$file_headers = #get_headers($this->file);
// Check file headers for 404
if($file_headers[0] == 'HTTP/1.1 404 Not Found')
return false; // File not available.
return true; // File is available!
}
However, since I'm already using Guzzle elsewhere, I'd think I could make this prettier and more readable.
Am I right in thinking that? How would I accomplish that?
I did manage to find part of the answer in the docs. Guzzle - Request Methods
Combined with a gist that has a similar function, that checks for 404 status.
/**
* #return boolean
*/
function exists()
{
$client = new GuzzleHttp\Client();
try {
$client->head($this->file);
return true;
} catch (GuzzleHttp\Exception\ClientException $e) {
return false;
}
}
function order_confirmationAction($order,$token) {
$client = new \GuzzleHttp\Client();
$answer = $client->post("http://www.fullcommerce.com/rest/public/Qtyresponse",
array('body' => $order)
);
$answer = json_decode($answer);
if ($answer->status=="ACK") {
return $this->render('AcmeDapiBundle:Orders:ack.html.twig', array(
'message' => $answer->message,
));
} else throw new \Symfony\Component\HttpKernel\Exception\HttpException(500, $answer->message);
}
If $client->post() response status code is an "Error 500" Symfony stops the script execution and throw new exception before the json decoding.
How can I force Symfony to ignore $client->post() bad response and execute till the last if statement?
$client = new \GuzzleHttp\Client();
try {
$answer = $client->post("http://www.fullcommerce.com/rest/public/Qtyresponse",
array('body' => $serialized_order)
);
}
catch (\GuzzleHttp\Exception\ServerException $e) {
if ($e->hasResponse()) {
$m = $e->getResponse()->json();
throw new \Symfony\Component\HttpKernel\Exception\HttpException(500, $m['result']['message']);
}
}
I solved like this. In that way I can access to responses of remote server even if it returns an error 500 code.
Per Guzzle documentation:
Guzzle throws exceptions for errors that occur during a transfer.
Specifically, if the API responds with a 500 HTTP error, you shouldn't expect its content to be JSON, and you don't want to parse it, so you're better off re-throwing an exception from there already (or informing the user that something went wrong). I would suggest trying this out:
function order_confirmationAction($order, $token) {
$client = new \GuzzleHttp\Client();
try {
$answer = $client->post("http://www.fullcommerce.com/rest/public/Qtyresponse",
array('body' => $order)
);
}
catch (Exception $e) {
throw new \Symfony\Component\HttpKernel\Exception\HttpException(500, $e->getMessage());
}
$answer = json_decode($answer);
if ($answer->status=="ACK") {
return $this->render('AcmeDapiBundle:Orders:ack.html.twig', array(
'message' => $answer->message,
));
} else {
throw new \Symfony\Component\HttpKernel\Exception\HttpException(500, $answer->message);
}
}
It is probably also a good idea to check for errors when JSON-decoding the response, because there could be surprises in the content you're getting (eg. wrong format, missing or unexpected fields or values, etc.).
What I want is get an object from an API with a HTTP (eg, jQuery's AJAX) request to an external api. How do I start? I did research on Mr Google but I can't find anything helping.
Im starting to wonder is this is even possible?
In this post Laravel 4 make post request from controller to external url with data it looks like it can be done. But there's no example nor any source where to find some documentation.
Please help me out?
Based upon an answer of a similar question here:
https://stackoverflow.com/a/22695523/1412268
Take a look at Guzzle
$client = new GuzzleHttp\Client();
$res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]);
echo $res->getStatusCode(); // 200
echo $res->getBody(); // { "type": "User", ....
We can use package Guzzle in Laravel, it is a PHP HTTP client to send HTTP requests.
You can install Guzzle through composer
composer require guzzlehttp/guzzle:~6.0
Or you can specify Guzzle as a dependency in your project's existing composer.json
{
"require": {
"guzzlehttp/guzzle": "~6.0"
}
}
Example code in laravel 5 using Guzzle as shown below,
use GuzzleHttp\Client;
class yourController extends Controller {
public function saveApiData()
{
$client = new Client();
$res = $client->request('POST', 'https://url_to_the_api', [
'form_params' => [
'client_id' => 'test_id',
'secret' => 'test_secret',
]
]);
echo $res->getStatusCode();
// 200
echo $res->getHeader('content-type');
// 'application/json; charset=utf8'
echo $res->getBody();
// {"type":"User"...'
}
You just want to call an external URL and use the results? PHP does this out of the box, if we're talking about a simple GET request to something serving JSON:
$json = json_decode(file_get_contents('http://host.com/api/stuff/1'), true);
If you want to do a post request, it's a little harder but there's loads of examples how to do this with curl.
So I guess the question is; what exactly do you want?
As of Laravel v7.X, the framework now comes with a minimal API wrapped around the Guzzle HTTP client. It provides an easy way to make get, post, put, patch, and delete requests using the HTTP Client:
use Illuminate\Support\Facades\Http;
$response = Http::get('http://test.com');
$response = Http::post('http://test.com');
$response = Http::put('http://test.com');
$response = Http::patch('http://test.com');
$response = Http::delete('http://test.com');
You can manage responses using the set of methods provided by the Illuminate\Http\Client\Response instance returned.
$response->body() : string;
$response->json() : array;
$response->status() : int;
$response->ok() : bool;
$response->successful() : bool;
$response->serverError() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;
Please note that you will, of course, need to install Guzzle like so:
composer require guzzlehttp/guzzle
There are a lot more helpful features built-in and you can find out more about these set of the feature here: https://laravel.com/docs/7.x/http-client
This is definitely now the easiest way to make external API calls within Laravel.
Updated on March 21 2019
Add GuzzleHttp package using composer require guzzlehttp/guzzle:~6.3.3
Or you can specify Guzzle as a dependency in your project's composer.json
{
"require": {
"guzzlehttp/guzzle": "~6.3.3"
}
}
Include below line in the top of the class where you are calling the API
use GuzzleHttp\Client;
Add below code for making the request
$client = new Client();
$res = $client->request('POST', 'http://www.exmple.com/mydetails', [
'form_params' => [
'name' => 'george',
]
]);
if ($res->getStatusCode() == 200) { // 200 OK
$response_data = $res->getBody()->getContents();
}
Definitively, for any PHP project, you may want to use GuzzleHTTP for sending requests.
Guzzle has very nice documentation you can check here.
I just want to say that, you probably want to centralize the usage of the Client class of Guzzle in any component of your Laravel project (for example a trait) instead of being creating Client instances on several controllers and components of Laravel (as many articles and replies suggest).
I created a trait you can try to use, which allows you to send requests from any component of your Laravel project, just using it and calling to makeRequest.
namespace App\Traits;
use GuzzleHttp\Client;
trait ConsumesExternalServices
{
/**
* Send a request to any service
* #return string
*/
public function makeRequest($method, $requestUrl, $queryParams = [], $formParams = [], $headers = [], $hasFile = false)
{
$client = new Client([
'base_uri' => $this->baseUri,
]);
$bodyType = 'form_params';
if ($hasFile) {
$bodyType = 'multipart';
$multipart = [];
foreach ($formParams as $name => $contents) {
$multipart[] = [
'name' => $name,
'contents' => $contents
];
}
}
$response = $client->request($method, $requestUrl, [
'query' => $queryParams,
$bodyType => $hasFile ? $multipart : $formParams,
'headers' => $headers,
]);
$response = $response->getBody()->getContents();
return $response;
}
}
Notice this trait can even handle files sending.
If you want more details about this trait and some other stuff to integrate this trait to Laravel, check this article. Additionally, if interested in this topic or need major assistance, you can take my course which guides you in the whole process.
I hope it helps all of you.
Best wishes :)
Basic Solution for Laravel 8 is
use Illuminate\Support\Facades\Http;
$response = Http::get('http://example.com');
I had conflict between "GuzzleHTTP sending requests" and "Illuminate\Http\Request;" don't ask me why... [it's here to be searchable]
So looking for 1sec i found in Laravel 8 Doc...
**Guzzle is inside the Laravel 8 Http Request !**
https://laravel.com/docs/8.x/http-client#making-requests
as you can see
https://laravel.com/docs/8.x/http-client#introduction
Laravel provides an expressive, minimal API around the Guzzle HTTP
client, allowing you to quickly make outgoing HTTP requests to
communicate with other web applications. Laravel's wrapper around
Guzzle is focused on its most common use cases and a wonderful
developer experience.
It worked for me very well, have fun and if helpful point up!
I also created trait similar to #JuanDMeGonthat's that u can use anywhere in your project.Please check this out
trait ApiRequests
{
public function get($url, $data = null)
{
try {
$response = Http::get($this->base_url . $url, $data);
} catch (\Exception $e) {
info($e->getMessage());
abort(503);
}
if ( $response->status() == 401) {
throw new AuthenticationException();
} else if (! $response->successful()) {
abort(503);
}
return $response->json();
}
public function post($url, $data = [])
{
$token = session()->get('token');
try {
$response = Http::acceptJson()->withToken($token)->post($this->base_url . $url, $data);
} catch (\Exception $e) {
abort(503);
}
if ($response->status() == 401 && !request()->routeIs('login')) {
throw new AuthenticationException();
}
return $response;
}
}
class Controller extends BaseController
{
protected $base_url;
use AuthorizesRequests, DispatchesJobs, ValidatesRequests, ApiRequests;
public function __construct()
{
$this->base_url = env("BASE_URL","http://192.168.xxxxxxx");
View::share('base_url', $this->base_url);
}
}
You can use Httpful :
Website : http://phphttpclient.com/
Github : https://github.com/nategood/httpful
Here is the simple call for laravel 9.4
Route::get('/currency', function () {
$response = Http::withHeaders([
'x-api-key' => 'prtl6749387986743898559646983194',
])->get('https://partners.api.skyscanner.net/apiservices/v3/culture/currencies');
return response()->json(['status'=> true,'data'=> json_decode($response->body()), 'Message'=>"Currency retrieved successfully"], 200);
});
Don't forget to import
use Illuminate\Support\Facades\Http;
I set my loggers up in my Bootstrap.php like so:
$logger = new Zend_Log();
if($environment->debug == '1')
{
$stream = #fopen('/var/www/html/rta/rta.log','a',false);
if(!$stream){ throw new Exception('Failed to open log stream'); }
$writer = new Zend_Log_Writer_Stream($stream);
$logger->addWriter($writer);
$logger->addWriter(new Zend_Log_Writer_Firebug());
}
else
{
// Do something else
}
Zend_Registry::set('logger',$logger);
I have the following code that I set up to fail:
$data = array(
'config_id' => $config->getConfigId(),
'pass_column' => $config->getPassColumn(),
'filename' => $config->getFilename(),
'date_format' => $config->getDateFormat(),
'mapping_config' => $config->getMappingConfig(),
'config_name' => $config->getConfigName(),
'client_id' => $config->getClientId(),
'description' => $config->getDescription(),
);
$where = $this->getDbTable()->getAdapter()->quoteInto('config_id = ?',$config->getConfigId());
$where = null;
try
{
$this->getDbTable()->update($data,$where);
}catch(Exception $e)
{
Zend_Registry::get('logger')->err('Could not update configuration.');
Zend_Registry::get('logger')->err($e);
return false;
}
return true;
I set two log writers: Stream and FirePHP.
The stream log writer successfully caught and wrote the exception but FirePHP didn't do anything. If I put other log messages other places in my code, like indexAction it shows those just fine in both. Am I missing something?
EDIT
The failure code is in my database mapper, not a controller. Could it be that it doesn't have access to the HTTP headers?
The following example below shows how to make FirePHP get the header info it needs without using the FrontController.
// create the logger and log writer
$writer = new Zend_Log_Writer_Firebug();
$logger = new Zend_Log($writer);
// get the wildfire channel
$channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
// create and set the HTTP response
$response = new Zend_Controller_Response_Http();
$channel->setResponse($response);
// create and set the HTTP request
$channel->setRequest(new Zend_Controller_Request_Http());
// record log messages
$logger->info('info message');
$logger->warn('warning message');
$logger->err('error message');
// insert the wildfire headers into the HTTP response
$channel->flush();
// send the HTTP response headers
$response->sendHeaders();
?>