I've tried using Guzzle's docs to set proxy but it's not working. The official Github page for Goutte is pretty dead so can't find anything there.
Anyone know how to set a proxy?
This is what I've tried:
$client = new Client();
$client->setHeader('User-Agent', $user_agent);
$crawler = $client->request('GET', $request, ['proxy' => $proxy]);
I have solved this problem =>
$url = 'https://api.myip.com';
$client = new \Goutte\Client;
$client->setClient(new \GuzzleHttp\Client(['proxy' => 'http://xx.xx.xx.xx:8080']));
$get_html = $client->request('GET', $url)->html();
var_dump($get_html);
You thinking rigth, but in Goutte\Client::doRequest(), when create Guzzle client
$guzzleRequest = $this->getClient()->createRequest(
$request->getMethod(),
$request->getUri(),
$headers,
$body
);
options are not passed when create request object. So, if you want to use a proxy, then override the class Goutte\Client, the method doRequest(), and replace this code on
$guzzleRequest = $this->getClient()->createRequest(
$request->getMethod(),
$request->getUri(),
$headers,
$body,
$request->getParameters()
);
Example overriding class:
<?php
namespace igancev\override;
class Client extends \Goutte\Client
{
protected function doRequest($request)
{
$headers = array();
foreach ($request->getServer() as $key => $val) {
$key = implode('-', array_map('ucfirst', explode('-', strtolower(str_replace(array('_', 'HTTP-'), array('-', ''), $key)))));
if (!isset($headers[$key])) {
$headers[$key] = $val;
}
}
$body = null;
if (!in_array($request->getMethod(), array('GET','HEAD'))) {
if (null !== $request->getContent()) {
$body = $request->getContent();
} else {
$body = $request->getParameters();
}
}
$guzzleRequest = $this->getClient()->createRequest(
$request->getMethod(),
$request->getUri(),
$headers,
$body,
$request->getParameters()
);
foreach ($this->headers as $name => $value) {
$guzzleRequest->setHeader($name, $value);
}
if ($this->auth !== null) {
$guzzleRequest->setAuth(
$this->auth['user'],
$this->auth['password'],
$this->auth['type']
);
}
foreach ($this->getCookieJar()->allRawValues($request->getUri()) as $name => $value) {
$guzzleRequest->addCookie($name, $value);
}
if ('POST' == $request->getMethod() || 'PUT' == $request->getMethod()) {
$this->addPostFiles($guzzleRequest, $request->getFiles());
}
$guzzleRequest->getParams()->set('redirect.disable', true);
$curlOptions = $guzzleRequest->getCurlOptions();
if (!$curlOptions->hasKey(CURLOPT_TIMEOUT)) {
$curlOptions->set(CURLOPT_TIMEOUT, 30);
}
// Let BrowserKit handle redirects
try {
$response = $guzzleRequest->send();
} catch (CurlException $e) {
if (!strpos($e->getMessage(), 'redirects')) {
throw $e;
}
$response = $e->getResponse();
} catch (BadResponseException $e) {
$response = $e->getResponse();
}
return $this->createResponse($response);
}
}
And try send request
$client = new \igancev\override\Client();
$proxy = 'http://149.56.85.17:8080'; // free proxy example
$crawler = $client->request('GET', $request, ['proxy' => $proxy]);
You can directly use in Goutte or Guzzle Request
$proxy = 'xx.xx.xx.xx:xxxx';
$goutte = new GoutteClient();
echo $goutte->request('GET', 'https://example.com/', ['proxy' => $proxy])->html();
Use Same method in Guzzle
$Guzzle = new Client();
$GuzzleResponse = $Guzzle->request('GET', 'https://example.com/', ['proxy' => $proxy]);
You can set a custom GuzzleClient and assign it to Goutte client.
When Guzzle makes the request through Goutte uses the default config. That config is passed in the Guzzle construct.
$guzzle = new \GuzzleHttp\Client(['proxy' => 'http://192.168.1.1:8080']);
$goutte = new \Goutte\Client();
$goutte->setClient($guzzle);
$crawler = $goutte->request($method, $url);
For recent versions use:
Goutte Client instance (which extends Symfony\Component\BrowserKit\HttpBrowser)
use Symfony\Component\HttpClient\HttpClient;
use Goutte\Client;
$client = new Client(HttpClient::create(['proxy' => 'http://xx.xx.xx.xx:80']));
...
Related
I spent some time without touching this Api, and now I have received the following error:
Unpermitted fields present in REQUEST_BODY:
It's a sharing code:
$link = 'https://example.com.br';
$access_token = $access_token;
$linkedin_id = $linkedin_profile_id;
$body = new \stdClass();
$body->content = new \stdClass();
$body->content->contentEntities[0] = new \stdClass();
$body->text = new \stdClass();
$body->content->contentEntities[0]->thumbnails[0] = new \stdClass();
$body->content->contentEntities[0]->entityLocation = $link;
$body->content->contentEntities[0]->thumbnails[0]->resolvedUrl = "https://example.com.br/img/logo-header-120x50.png";
$body->content->title = 'Example';
$body->owner = 'urn:li:person:'.$linkedin_id;
$body->text->text = 'Kasum';
$body->visibility = new \stdClass();
$body->visibility->code = new \stdClass();
$body->visibility->code = 'anyone';//<-------------that is a line error
$body_json = json_encode($body, true);
try {
$client = new Client(['base_uri' => 'https://api.linkedin.com']);
$response = $client->request('POST', '/v2/shares', [
'headers' => [
"Authorization" => "Bearer " . $access_token,
"Content-Type" => "application/json",
"x-li-format" => "json"
],
'body' => $body_json,
]);
if ($response->getStatusCode() !== 201) {
echo 'Error: '. $response->getLastBody()->errors[0]->message;
}
echo 'Post is shared on LinkedIn successfully';
} catch(Exception $e) {
echo $e->getMessage(). ' for link '. $link;
}
As indicated in the code, the visibility field triggers this error
Without it, sharing occurs, but with visibility only for connections. That way the post loses the share button.
Is it no longer allowed to configure this field, or am I doing it wrong?
I am sending a POST request to an API, Curl returns 200 and the correct response.
When Implementing with GuzzleHttp\Client, I get a 400 Bad request, what is wrong with my formatting.
here is my code using Laravel Returns 400 Bad Request:
$client = new Client();
$URI = 'http://api.example.com';
$params['headers'] = ['Content-Type' => 'application/json',
'apikey' => config('app._api_key'),
'debug' => true
];
$params['form_params'] = [
'sender' => 'Test_sender',
'recipient' => config('app.test_recipient'),
'message_body' => 'Test body'
];
return $response = $client->post($URI, $params);
Curl (Returns 200):
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'apikey: 212121212’ -d '{ "message_body": "test","sender": "2018","recipient": “4453424141” }' 'http://api.example.com'
Try the below code:
$client = new \GuzzleHttp\Client(['headers' => ['Content-Type' => 'application/json',
'apikey'=> config('app._api_key'),
'debug' => true
]
]);
$URI = 'http://api.example.com';
$body['sender']='Test_sender';
$body['recipient']=config('app.test_recipient');
$body['message_body']='Test body';
$body=json_encode($body);
$URI_Response = $client->request('POST',$URI,['body'=>$body]);
$URI_Response =json_decode($URI_Response->getBody(), true);
return $URI_Response;
Note: I would suggest you to handle error please refer GuzzleDocumentation
That is proper error handling:
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
try {
$response = $client->get(YOUR_URL, [
'connect_timeout' => 10
]);
// Here the code for successful request
} catch (RequestException $e) {
// Catch all 4XX errors
// To catch exactly error 400 use
if ($e->getResponse()->getStatusCode() == '400') {
echo "Got response 400";
}
// You can check for whatever error status code you need
} catch (\Exception $e) {
// There was another exception.
}
Implementation: http://guzzle.readthedocs.org/en/latest/quickstart.html
You can handle errors like this
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\RequestException;
use Exception;
try{
$client = new Client();
$response = $client->request('POST', $url,[
'headers' => $header,
'form_params' => $form-params
]);
$body = $response->getBody();
$status = 'true';
$message = 'Data found!';
$data = json_decode($body);
}catch(ClientException $ce){
$status = 'false';
$message = $ce->getMessage();
$data = [];
}catch(RequestException $re){
$status = 'false';
$message = $re->getMessage();
$data = [];
}catch(Exception $e){
$this->status = 'false';
$this->message = $e->getMessage();
$data = [];
}
return ['status'=>$status,'message'=>$message,'data'=>$data];
Im trying to consume a webserivce usnig soapclient.
The instructions for the connection is to use:
request method = "POST";
request ContentType = "application/soap+xml";
This is the code im using to create the client
public function init_client(){
if( $this->env == 'dev'){
$api_url = self::$test_url;
}else{
$api_url = self::$production_url;
}
try{
$options = array(
'soap_version' => SOAP_1_2
);
$this->client = new SoapClient( $api_url , $options );
return true;
}catch(Exception $e){
return $e->getMessage();
}
}
How can i set the client's method and content type ?
I use the following method to dispatch a Slim app's route in my PHPUnit tests:
protected function dispatch($path, $method='GET', $data=array())
{
// Prepare a mock environment
$env = Environment::mock(array(
'REQUEST_URI' => $path,
'REQUEST_METHOD' => $method,
));
// Prepare request and response objects
$uri = Uri::createFromEnvironment($env);
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new RequestBody();
// create request, and set params
$req = new Request($method, $uri, $headers, $cookies, $serverParams, $body);
if (!empty($data))
$req = $req->withParsedBody($data);
$res = new Response();
$this->headers = $headers;
$this->request = $req;
$this->response = call_user_func_array($this->app, array($req, $res));
}
For example:
public function testGetProducts()
{
$this->dispatch('/products');
$this->assertEquals(200, $this->response->getStatusCode());
}
However, as much as things like the status code and header are in the response, (string) $response->getBody() is empty so I cannot check for the presence of elements in the HTML. When I run the same route in the browser, I get the expected HTML output. Also, if I echo $response->getBody(); exit; and then view the output in the browser, I see HTML body. Is there any reason, with my implementation, I'm not seeing this in the my tests? (in the CLI, so different environment I guess)
$response->getBody() will be empty as you've set up the parsed body. It's easier to put it into the RequestBody as a string in the same way as it would be set if it came in over the wire.
i.e something like this:
protected function dispatch($path, $method='GET', $data=array())
{
// Prepare a mock environment
$env = Environment::mock(array(
'REQUEST_URI' => $path,
'REQUEST_METHOD' => $method,
'CONTENT_TYPE' => 'application/json',
));
// Prepare request and response objects
$uri = Uri::createFromEnvironment($env);
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new RequestBody();
if (!empty($data)) {
$body->write(json_encode($data));
}
// create request, and set params
$req = new Request($method, $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();
$this->headers = $headers;
$this->request = $req;
$this->response = call_user_func_array($this->app, array($req, $res));
}
I've been able to successfully log a user in and return their details. The next step is to get them to post a comment via my app.
I tried modifying code from the reddit-php-sdk -- https://github.com/jcleblanc/reddit-php-sdk/blob/master/reddit.php -- but I can't get it to work.
My code is as follows:
function addComment($name, $text, $token){
$response = null;
if ($name && $text){
$urlComment = "https://ssl.reddit.com/api/comment";
$postData = sprintf("thing_id=%s&text=%s",
$name,
$text);
$response = runCurl($urlComment, $token, $postData);
}
return $response;
}
function runCurl($url, $token, $postVals = null, $headers = null, $auth = false){
$ch = curl_init($url);
$auth_mode = 'oauth';
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 10
);
$headers = array("Authorization: Bearer {$token}");
$options[CURLOPT_HEADER] = false;
$options[CURLINFO_HEADER_OUT] = false;
$options[CURLOPT_HTTPHEADER] = $headers;
if (!empty($_SERVER['HTTP_USER_AGENT'])){
$options[CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT'];
}
if ($postVals != null){
$options[CURLOPT_POSTFIELDS] = $postVals;
$options[CURLOPT_CUSTOMREQUEST] = "POST";
}
curl_setopt_array($ch, $options);
$apiResponse = curl_exec($ch);
$response = json_decode($apiResponse);
//check if non-valid JSON is returned
if ($error = json_last_error()){
$response = $apiResponse;
}
curl_close($ch);
return $response;
}
$thing_id = 't2_'; // Not the actual thing id
$perma_id = '2daoej'; // Not the actual perma id
$name = $thing_id . $perma_id;
$text = "test text";
$reddit_access_token = $_SESSION['reddit_access_token'] // This is set after login
addComment($name, $text, $reddit_access_token);
The addComment function puts the comment together according to their API -- http://www.reddit.com/dev/api
addComment then calls runCurl to make the request. My guess is that the curl request is messed up because I'm not receiving any response whatsoever. I'm not getting any errors so I'm not sure what's going wrong. Any help would really be appreciated. Thanks!
If you are using your own oAuth solution, I would suggest using the SDK as I said in my comment, but extend it to overwrite the construct method.
class MyReddit extends reddit {
public function __construct()
{
//set API endpoint
$this->apiHost = ENDPOINT_OAUTH;
}
public function setAuthVars($accessToken, $tokenType)
{
$this->access_token = $accessToken;
$this->token_type = $tokenType;
//set auth mode for requests
$this->auth_mode = 'oauth';
}
}
You just need to make sure that you call setAuthVars before running any api calls.