Facebook PHP SDK throws uncatchable "GraphMethodException" error - php

I'm experiencing something eerily similar to this question about an uncatchable PHP error thrown by the Facebook PHP SDK except for the fact that I'm not using PHP namespaces at all. This other question is also close, but doesn't explain why the error is uncatchable. Further, in my case, I have a Facebook app that issues a Facebook Graph API call against an object that the current user has blocked. This is certainly awkward, but legal for the purposes of this particular app. That means I need to catch the error, not prevent the user from making the search in the first place.
The fatal error's output in my development environment looks like this:
Fatal error: Uncaught GraphMethodException: Unsupported get request. thrown in /path/to/apps/lib/facebook/src/base_facebook.php on line 1271
So, Facebook's Graph API correctly returns an error as a result of the API call, citing "Unsupported get request." However, the Facebook PHP SDK seems to throw this as an uncatchable error, and I don't know why.
I've tried code like the following catch blocks with no success:
try {
$response = $facebook->api("/$some_id_of_object_current_user_has_blocked");
} catch (FacebookApiException $e) {
// Why does this never get caught?
} catch (Exception $e) {
// Similarly, this also never gets caught!
} catch (GraphMethodException $e) {
// Still can't catch this exception, and I don't grok why. :(
}
For the sake of ridiculous completeness, I've also tried namespaces including things like this:
try {
$response = $facebook->api("/$some_id_of_object_current_user_has_blocked");
} catch (\FacebookApiException $e) {
} catch (\Exception $e) {
} catch (\FacebookApiException\GraphMethodException $e) {
} catch (\GraphMethodException $e) {
} catch (... $e) {
}
Further investigation lead me to try catching this in the base_facebook.php file itself, where it seems to get thrown, in the protected Facebook::_graph method. And sure enough, it is catchable there. The original code at about line 879 of base_facebook.php is:
if (is_array($result) && isset($result['error'])) {
$this->throwAPIException($result);
// #codeCoverageIgnoreStart
}
Wrapping this call to throwAPIException() with a try...catch block works:
if (is_array($result) && isset($result['error'])) {
try {
$this->throwAPIException($result);
// #codeCoverageIgnoreStart
} catch (Exception $e) {
// WORKS!
}
}
So if it works there, why can't I catch this exception from my own scripts? Am I missing something fundamental about the way PHP error handling works?
Alternatively, is there a way for a Facebook app to get a list of all the objects a Facebook user has blocked, such as other Facebook users a user has blocked? I'm familiar with Graph API enough to know that there's a way for an app to access a list of all users a page has blocked, but that's specifically not what I'm looking for.
Thanks for your time.

It's apparently uncatchable because it relates to the permissions your app uses.
In your case, it looks like you were trying to GET the same thing as me, which requires the permission: read_stream
It makes sense that they would make this sort of thing uncatchable - but you'd think the facebook devs could do something a little more friendly...

Adding the try/catch around $this->throwAPIException($result); works in suppressing the error message but I would recommend checking the inputs to your functions to ensure they exist and are valid.
For example, check to see if $SESSION['fb<your_app_id>_access_token'] exists and is not null before passing this to any functions. If this is not set or is null, none of the functions that rely on it will work and you can catch the potential issue before communicating with Facebook's servers, which speeds up your application by skipping a function you can determine ahead of time will fail, and resolve issues quicker by asking for corrections proactively instead of re-actively.
I also was seeing this error which apparently was caused by my app not having the appropriate permissions, as #rm-vanda stated. Because the app id does not have the permissions, a token is not returned which results in the error you are seeing.
Hope that helps!

Related

How to catch an error thrown by a third party library in PHP

I'm using the phpWhois package in my Laravel application for performing whois lookup.
It's working fine except that for some websites that I enter, this error always occurs:
'ErrorException in whois.gtld.godaddy.php line 50: Undefined index: owner'
I googled it and found that this problem already has an open issue on Github and also an existing pull request.
I don't want to copy and paste the suggested fix in the source code because it means I have to do it in every time I do composer install.
So I decided to catch the error instead but I don't know how.
I found a somewhat similar question here and tried the accepted solution but it is still throwing the exception.
Here's the existing code that I tried:
$whois = new \Whois();
try {
$result = $whois->lookup($data['name']);
} catch (Exception $e) {
return response()->json(['error' => $e]);
}
I would appreciate any comment/help.
Thanks for your time.
If you want to catch an exception,You follow below mentioned programming style.
try {
$whois = new \Whois();
$result = $whois->lookup($data['name']);
} catch (\Exception $e) {
\var_dump($e->getMessage());
}
This above mentioned method work in almost all PHP frameworks.

Try {} catch {} on API call or handle differently?

In a Laravel 5.2 app, I'm trying to figure out the most elegant way to handle exceptions when those exceptions are thrown by API calls of external services. These shouldn't stop the program from continuing, because there are other parts of the app that still can be run afterwards that can be done even without the problematic API call.
E.g. currently I have
try {
$statistics->results = $api->call($parameter);
$statistics->status = Statistic::SUCCESS;
} catch (ExternalApiCallException $e) {
$statistics->results = null;
$statistics->status = Statistic::API_CALL_ERROR;
}
I was thinking of using Laravel's app/Exceptions/Handler.php and using
if ($e instanceof ExternalApiCallException $e) {
Log::warning("API Call didn't work");
}
but then I wouldn't be able to set the status of the statistics there, because Handler.php wouldn't have access to it. Is there a better way or are try-catch-blocks the way to go here?
try-catch-finally is definitely a good approach here. In your case API exceptions are localized and should not appear globally (I presume), so I would opt for keeping logic in one place and not putting exception handling as a condition in Handler.php file. In my opinion Handler.php should be used as a last resort option, to style and report otherwise uncaught and unexpected exceptions. For all other cases where exceptions are not critical or even expected, local try {} blocks are easier to maintain, as important parts of the code are not hidden from developer in another file.
Do not forget that you can also use finally {} block, which will be executed after both try{} and catch{} blocks, no matter if the exception was triggered or not.
try
{
// run this first
}
catch (ExternalApiCallException $e)
{
// in case something went wrong
}
finally
{
// this runs after everything else
}

PHPUnit Assertions project

I am working on a PHP project that requires validating a JSON request to a predefined schema, that is available in swagger. Now I have done my research and have found that the best project for this is SwaggerAssertions:
https://github.com/Maks3w/SwaggerAssertions
Within SwaggerAssertions/tests/PhpUnit/AssertsTraitTest.php, I would love to make use of the testAssertRequestBodyMatch method, where you do this:
self::assertRequestBodyMatch($request, $this->schemaManager, '/api/pets', 'post');
This assertion above does exactly what I need, but if I pass a invalid request it causes a fatal error. I want to trap this and handle the response back rather than the app quitting altogether.
How can I make use of this project, even though it looks like its all for PHPUnit? I am not too sure how one would make use of this project in normal PHP production code. Any help would be greatly appreciated.
Assertions throw exceptions if the condition is not met. If an exception is thrown, it will stop all following code from being executed until it's caught in a try catch block. Uncaught exceptions will cause a fatal error and the program will exit.
All you need to do to prevent your app from crashing, is handling the exception:
try {
self::assertRequestBodyMatch($request, $this->schemaManager, '/api/pets', 'post');
// Anything here will only be executed if the assertion passed
} catch (\Exception $e) {
// This will be executed if the assertion,
// or any other statement in the try block failed
// You should check the exception and handle it accordingly
if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
// Do something if the assertion failed
}
// If you don't recognise the exception, re-throw it
throw $e;
}
Hope this helps.

Catching Exceptions from library using Laravel 5.2

Pretty new to laravel, so I'm not exactly sure how it handles errors and how best to catch them.
I'm using a 3rd party game server connection library that can query game servers in order to pull data such as players, current map etc..
This library is called Steam Condenser : https://github.com/koraktor/steam-condenser
I have imported this using composer in my project and all seems to be working fine, however I'm having trouble with catching exceptions that are thrown by the library.
One example is where the game server you are querying is offline.
Here is my code:
public function show($server_name)
{
try{
SteamSocket::setTimeout(3000);
$server = server::associatedServer($server_name);
$server_info = new SourceServer($server->server_ip);
$server_info->rconAuth($server->server_rcon);
$players = $server_info->getPlayers();
$total_players = count($players);
$more_info = $server_info->getServerInfo();
$maps = $server_info->rconExec('maps *');
preg_match_all("/(?<=fs\)).*?(?=\.bsp)/", $maps, $map_list);
}catch(SocketException $e){
dd("error");
}
return view('server', compact('server', 'server_info', 'total_players', 'players', 'more_info', 'map_list'));
}
If the server is offline, it will throw a SocketException, which I try to catch, however this never seems to happen. I then get the error page with the trace.
This causes a bit of a problem as I wish to simply tell the end user that the server is offline, however I cannot do this if I can't catch this error.
Is there something wrong with my try/catch? Does laravel handle catching errors in this way? Is this an issue with the 3rd party library?
A couple things:
Does the trace lead to the SocketException or to a different error? It's possible that a different error is being caught before the SocketException can be thrown.
Your catch statement is catching SocketException. Are you importing the full namespace at the top of your PHP file? use SteamCondenser\Exceptions\SocketException;
Also for debugging purposes, you could do an exception "catch all" and dump the type of exception:
try {
...
}catch(\Exception $e){
dd(get_class($e));
}
If you still get the stack trace after trying the above code, then an error is being thrown before the try/catch block starts.

PHP Facebook Class: how top block fatal errors?

I am using FB Connect and the PHP class called Facebook, that is provided by FB. Whenever something goes wrong FB throws Fatal Error and application dies. That's great for testing but now very nice for production code. I've looked through code and can't find a way to disable that but may be I overlooked something. So, is there any way to disable fatal errors other than looking through their class and removing every line like this
throw new FacebookApiException($result);
You should catch exceptions, not remove them.
try {
//do something with the facebook api
}
catch (FacebookApiException $e) {
//an error occured, handle it
}
And btw: fatal errors are different from exceptions.

Categories