I am using an OAuth library to connect to Etsy shop API. Code looks like this:
foreach ($transactions as $transactionSingle) {
try {
$oauth = new OAuth('xxx', 'xxx',
OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
$oauth->setToken($access_token, $access_token_secret);
$data = $oauth->fetch("https://openapi.etsy.com/v2/users/".$transactionSingle['buyer_id']."/profile", null, OAUTH_HTTP_METHOD_GET);
$json = $oauth->getLastResponse();
$results = json_decode($json, true);
} catch (OAuthException $e) {
return null;
}
}
Now the problem is that I run this code multiple times on foreach and if this URL is wrong and it fails to get any data - the whole function stops and doesn't continue anymore. It works perfectly until an old user ID is passed to URL and $oauth->fetch just reuturns message :
Invalid auth/bad request (got a 404, expected HTTP/1.1 20X or a
redirect)
Any ideas how to continue to run the function despite any errors?
The problem was in error cathing itself. Needed backslash on
catch (\OAuthException $e) {
}
Now the code catches the errors and continues if no code is provided inside catch.
Related
I have this simple code, where I'm trying to access a page with an ID. Whenever I run this code, I get an error "Unsupported get request. Please read the Graph API documentation"
$leheid = $page['accounts'][$x]['id'];
try {
$page = $fb->get("$leheid?fields=events", $at);
$page = $page->getGraphPage();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
echo $e->getMessage();
} catch(Facebook\Exceptions\FacebookSDKException $e) {
echo $e->getMessage();
}
Okay, but whenever I run the same code without a variable and with a string, no errors...
If I echo or print the same variable I get the right string with no spaces or anything else in there, so I'm quite confused...
Also, I tried $leheid. '....'
It's an old question but i would like to contribute and maybe help someone else with the same problem.
The reason why the code above didn't work, was because i mistyped the API response function
In short:
$page = $page->getPage();
should have been replaced with
$page = $page->getGraphPage()->asArray();
Which will also give you the response as an array
I've written some code in Laravel 5.2 to retrieve results from an unrelible API source. However, it needs to be able to automatically retry the request on failed attempts, as the API call results in a 503 about a third of the time.
I'm use Guzzle to do this, and I think I know where to put the code that will intercept the 503 responses before they are processed; but I'm not sure what to actually write there.
The guzzle documentation doesn't offer much as far as retries go, and all of the examples I've come across of Guzzle 6 only show how to retrieve results (which I can already do), but not how to get it to repeat the request if needed.
I'm by no means asking anyone to do the work for me - but I think I'm approaching the limits of my understanding on this. If anybody can point me in the right direction, it'd be much appreciated :)
EDIT:
I will try and revise. Please consider the following code. In it, I want to send a GET request which should normally yield a JSON response.
DataController.php
$client = new \GuzzleHttp\Client();
$request = $client->request('GET', 'https://httpbin.org/status/503'); // URI is for testing purposes
When the response from this request is a 503, I can intercept it here:
Handler.php
public function render($request, Exception $e)
{
if ($e->getCode() == 503)
{
// Code that would tell Guzzle to retry the request 5 times with a 10s delay before failing completely
}
return parent::render($request, $e);
}
I don't know that that is the best place to put it, but the real problem is I don't know is what to write inside the if ($e->getCode() == 503)
Guzzle by default throws exceptions when a non 2** response is returned. In your case you're seeing a 503 response. Exceptions can be thought of as errors that the application can recover from. The way this works is with try catch blocks.
try {
// The code that can throw an exception will go here
throw new \Exception('A generic error');
// code from here down won't be executed, because the exception was thrown.
} catch (\Exception $e) {
// Handle the exception in the best manner possible.
}
You wrap the code that could throw an exception in the try portion of the block. Then you add your error handling code in the catch portion of the block. You can read the above link for more information on how php handles exceptions.
For your case, lets move the Guzzle call to it's own method in your controller:
public function performLookUp($retryOnError = false)
{
try {
$client = new \GuzzleHttp\Client();
$request = $client->request('GET', 'https://httpbin.org/status/503');
return $request->send();
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
if ($retryOnError) {
return $this->performLookUp();
}
abort(503);
}
}
Now in your controller you can execute, $this->performLookUp(true);.
Just to add some information to clarify a few points that Logan made.
Guzzle "can" throw exceptions on a Response other then 2**/3**. It all depends upon how the GuzzleHttp\HandlerStack is created.
$stack = GuzzleHttp\HandlerStack::create();
$client = new Client(['handler'=> $stack]);
$client = new Client();
// These two methods of generating a client are functionally the same.
$stack = New GuzzleHttp\HandlerStack(new GuzzleHttp\Handler\CurlHandler());
$client = new Client(['handler'=> $stack]);
// This client will not throw exceptions, or perform any of the functions mentioned below.
The create method adds default handlers to the HandlerStack. When the HandlerStack is resolved, the handlers will execute in the following order:
Sending request:
http_errors - No op when sending a request. The response status code is checked in the response processing when returning a response promise up the stack.
allow_redirects - No op when sending a request. Following redirects occurs when a response promise is being returned up the stack.
cookies - Adds cookies to requests.
prepare_body - The body of an HTTP request will be prepared (e.g., add default headers like Content-Length, Content-Type, etc.).
send request with handler
Processing response:
prepare_body - no op on response processing.
cookies - extracts response cookies into the cookie jar.
allow_redirects - Follows redirects.
4.http_errors - throws exceptions when the response status code >= 300.
When provided no $handler argument, GuzzleHttp\HandlerStack::create() will choose the most appropriate handler based on the extensions available on your system. As indicated within the Handler Documentation
By manually creating your GuzzleHttp\HandlerStack, you can add middleware to the application. Given the context of your original question "how do i repeat the request" I believe you are most interested in the Retry Middleware that is provided within Guzzle 6.1. This is a middleware that retries requests based on the result of the provided decision function.
Documentation has yet to catch up with this class.
final class HttpClient extends \GuzzleHttp\Client
{
public const SUCCESS_CODE = 200;
private int $attemptsCount = 3;
private function __construct(array $config = [])
{
parent::__construct($config);
}
public static function new(array $config = []): self
{
return new self($config);
}
public function postWithRetry(string $uri, array $options = []): Response
{
$attemptsCount = 0;
$result = null;
do {
$attemptsCount++;
$isEnd = $attemptsCount === $this->attemptsCount;
try {
$result = $this->post(
$uri,
$options,
);
} catch (ClientException $e) {
$result = $e->getResponse();
} catch (GuzzleException $e) {
if ($isEnd) {
Logger::error($e->getMessage());
$result = $e->getResponse();
}
}
} while ($this->isNeedRetry($result, $attemptsCount));
return $result;
}
private function isNeedRetry(?Response $response, int $attemptsCount): bool
{
return $response === null && $attemptsCount < $this->attemptsCount;
}
I'm trying to figure out if a user is following another user on Soundcloud using the Soundcloud API and php.
So far I came across a solution which would either return an object (user) or a 404 error:
$test = json_decode($client->get('/users/{id1}/followers/{id2}'));
I've tried it multiple times with different user IDs but I always receive a the following error message:
'Services_Soundcloud_Invalid_Http_Response_Code_Exception' with message 'The requested URL responded with HTTP code 404.'
I know that this is supposed to be the error message which informs me that user2 is not following user1. However I've tried this snippet with ids where I know a reciprocal following exists for sure.
Any suggestions on how this can be solved?
Update (21.05.15):
I've read through some of the Soundcloud documentation and cam across a code snippet:
<?php
require_once 'Services/Soundcloud.php';
// create a client object with access token
$client = new Services_Soundcloud('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');
$client->setAccessToken('YOUR_ACCESS_TOKEN');
// Follow user with ID 3207
$client->put('/me/followings/3207');
// Unfollow the same user
$client->delete('/me/followings/3207');
// check the status of the relationship
try {
$client->get('/me/followings/3207');
} catch (Services_Soundcloud_Invalid_Http_Response_Code_Exception $e) {
if ($e->getHttpCode() == '404')
print "You are not following user 3207\n";
}
?>
This is pretty much what I was referring to. However if I open a php page with this script the result is always one of three cases:
You are not following user 3207 (expected output)
No output (I'm following the user)
Uncaught exception 'Services_Soundcloud_Invalid_Http_Response_Code_Exception' with message 'The requested URL responded with HTTP code 404.'
The third option is either referring to $client->put or $client->delete
Here is how i would do this:
<?php
require_once 'Services/Soundcloud.php';
$client = new Services_Soundcloud(
'xxxxxxxxxxxxxxxxxxx160', 'xxxxxxxxxxxxxxxxxx34dd1 ');
$userid = 1672444;
$followerid = 383228;
$yesno = '';
try {
$response = json_decode($client->get('users/'.$userid.'/followers'), true);
$yesno = IdInArray($response, $followerid);
echo $yesno;
} catch (Services_Soundcloud_Invalid_Http_Response_Code_Exception $e) {
exit($e->getMessage());
}
function IdInArray($response, $followerid){
echo $followerid.'<br/>';
for($i = 0; $i < count($response); ++$i) {
if($response[$i]['id'] == $followerid){
return 'yolo';
}
else{
return 'nolo';
}
}
}
?>
I run a bunch of servers that I monitor on a minutely basis from another server. The relevant bit of code goes like this
$ctx = stream_context_create(array('http'=>array('timeout'=>10)));
try
{
$mei = file_get_contents("https://url/status.php?key=shhh",false,$ctx);
} catch(Exception $e)
{
trigger_error($e->getMessage());
$mei = null;
}
I started providing a stream context when I realized that if one of the monitored servers is down the whole setup stops working and returns a 504, Bad Gateway, error.
Everything good so far. What puzzles me is this - for some reason the 10s timeout is triggering an error message in my Nginx log file but I am unable to catch the exception in my code above. I should mention that this is NOT and error_reporting issue. I checked my error_reporting settings and, for good measure, tried with error_reporting(E_ALL) right at the top.
I could always just stick in an # prior to file_get_contents and everything would be fine but this puzzles me - either I need to stop working and spot my mistake here or else there is another issue at work.
In PHP (>=7) it would be better to catch \Throwable type, because it's the base class for both Error and Exception.
$ctx = stream_context_create(array('http'=>array('timeout'=>10)));
try
{
$mei = file_get_contents("https://url/status.php?key=shhh",false,$ctx);
}
catch(\Throwable $e)
{
trigger_error($e->getMessage());
$mei = null;
}
Use Guzzle or curl to verify the availability of the server prior your request the it's file_get_contents.
can be prettier but you get the point:
$server = 'https://url/status.php?key=shhh';
$client = new GuzzleHttp\Client();
$res = $client->request('GET', $server);
if ($res->getStatusCode() == 200) {
$ctx = stream_context_create(array('http' => array('timeout' => 10)));
try {
$mei = file_get_contents($server, false, $ctx);
} catch (Exception $e) {
trigger_error($e->getMessage());
$mei = null;
}
}
I am using SoapClient but I am not able to get the result. I get this error:
The server was unable to process the request due to an internal error.
For more information about the error, either turn on
IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute
or from the configuration behavior) on the server in order to send the
exception information back to the client, or turn on tracing as per
the Microsoft .NET Framework 3.0 SDK documentation and inspect the
server trace logs.
<?php
$silverpop = new SoapClient($my_url, array('trace' => 1));
/*$client = new stdClass();
$client->LoginID = 'mylogin-id';
$client->LicenceKey = 'mylicense-key';*/
$clientobj = (object) array("LoginID" => "mylogin-id", "LicenceKey" => "mylicense-key");
try {
//$var = $silverpop->__soapCall("GetServicesforPincode",array('P_Pincode'=>'110014','P_ClientObject'=>$clientobj));
//$var = $silverpop->GetServicesforPincode('110014',$clientobj);
$var = $silverpop -> __soapCall("GetServicesforPincode", array('110014', $clientobj));
} catch (SoapFault $exception) {
echo $exception -> getMessage();
}
echo '<pre>';
print_r($var);
?>
What am I doing wrong?
Either you have send your data not according to the specifications or your SoapServer is not working. I think the first one as Soap isn't always as clear as it should. As it looks like the error message is actually generated by the SoapServer, I recommend checking the schema for allowed parameters/calls and their format. If that's all correct, check if you are missing headers etc.
If all of the above is correct, fix your SoapServer. If you haven't gotten access to it, poke the owner.
try{
$client = new SoapClient($my_url,array('trace' => 1));
$object = new stdClass();
$object->LoginID = 'mylogin-id';
$object->LicenceKey = 'mylicense-key';
$xml = simplexml_load_string($client->GetServicesforPincode($object));
$json = json_encode($xml);
print_r($json);
}
catch (SoapFault $exception) { echo $exception; }