I am using the Stripe API and Laravel together. If Stripe detects an error charging the card (such as using a test credit card number that throws an invalid security code error), the API bindings are supposed to throw an exception, which they do. The problem is, I am having issues catching the exception before Laravel throws up the error 500 page (I am trying to perform a redirect with an error message instead).
The code I've written is available on Pastebin: http://pastebin.com/ZaW2xbbt
The behavior I'm expecting is for the catch to fire and the redirect to be performed, but instead, I get the stack trace with the message and "Unhandled Exception". That's confusing me because I am handling the exception.
Variables such as $customer are valid and have been defined previously. Any ideas what's going on?
For any future viewers, here's an article on error handling in laravel 4.
Laravel 4 lets you catch Exceptions by exception type. For instance, you can handle Symfony's HttpException and of its sub-classes by adding this to your code:
// Catch HttpException, NotFoundHttpException, etc etc
App::error(function(HttpException $exception, $code, $fromConsole)
{
...
});
Symfony HttpExceptions (used in Laravel) can be found here.
You can also throw this in a ServiceProvider:
<?php namespace My\Namespace;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\HttpKernel\Exception\HttpException;
class MyServiceProvider extends ServiceProvider {
public function register()
{
$this->app->error(function(HttpException $exception, $code, $fromConsole)
{
...
});
}
}
Hope that helps!
Generally, all errors logged by Laravel are logged under storage/logs folder
Anyway, the 500 error could be a syntax/parse error, in such case the Laravel framework could be not yet loaded when the error occurs and if so, the exception is not lhandled by Laravel.
In this case you should access the apache/vargrant/whatif php error log in some way (dependently on your server capabilities and configuration), in my personal cases I have configured the server to put that logs in a /storage/logs/error_log.txt file such that I can access them as other Laravel server logs
Note that in Laravel 5, you have app/Exceptions/Handler.php as entry point for customize exception handling/reporting
https://laravel.com/docs/5.7/errors#the-exception-handler
Related
I am using latest version laravel(5.6)
Now in my code whenever an exception occurs laravel treating it as a fatal error, stop executing instantly and displaying the error message in some template.
But I don't want that, I want to handle exceptions and display some custom error messages
I found some ways like
changing the APP_DEBUG value in the .env file to false. But this also displays another
page with the message "whoops!some this want wrong";
In Handler.php which is in app/Exceptions, I had put some exceptions in not report zone. But the app is still reporting them
Custom HTTP Error Pages
Laravel makes it easy to display custom error pages for various HTTP
status codes. For example, if you wish to customize the error page for
404 HTTP status codes, create a resources/views/errors/404.blade.php.
This file will be served on all 404 errors generated by your
application. The views within this directory should be named to match
the HTTP status code they correspond to. The HttpException instance
raised by the abort function will be passed to the view as an
$exception variable.
https://laravel.com/docs/5.6/errors#custom-http-error-pages
Really you want to be handling your exceptions. Wrap the code in a try catch and you can do all manner of things (e.g. email / slack / log). Once you have handled the exception you can still use custom http error pages inside the catch so the end user get's a friendly message on a nicely designed page. There is even a report helper built in to allow you to externally log and continue on processing the code.
#Devon's above answer re: Custom HTTP Error Pages gets you exactly what you want also.
Please note few important points :
The App\Exceptions\Handler class is where all exceptions triggered by your application are logged and then rendered back to the user. This class has two method report() and render(), both has their own responsibility.
The report method is used to log exceptions. By default, the report method passes the exception to the base class where the exception is logged. However, you are free to log exceptions however you wish. For example, if you need to report different types of exceptions in different ways, you may use the PHP instanceof comparison operator
The render method is responsible for converting a given exception into an HTTP response that should be sent back to the browser. By default, the exception is passed to the base class which generates a response for you. However, you are free to check the exception type or return your own custom response.
As in your case you want to return custom message for exception, inside render() you may use the PHP instanceof comparison operator and return you own logic.
Example :
if($exception instanceof PostTooLargeException || $exception instanceof FileException){
return response()->json([
'error' => true,
'error_message' => "The file you are trying to upload exceeds the maximum limit. Please try to upload a smaller file."
],200);
}
Go through https://laravel.com/docs/5.6/errors for more datails
Sorry for this vague title, I didn't know how to title my question.
I'm listening on kernel.exception via the kernel.event_listener service. I use it in my API to catch all exceptions and serialize them in JSON for a clean error handling for the API customers.
I have to adapt the serialization depending on the exception types (my HTTP exceptions, Symfony HTTP exceptions, and others).
When a user is not authenticated when accessing a section restricted by access_control in security.yml, Symfony throws a non-HTTP Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException. In my serializer, a non-HTTP exception is converted in a 500 error. Since an InsufficientAuthenticationException is rather a 401 Unauthorized error, I have to catch this exception separately and convert it in my app-specific exception type.
Example:
# Find appropriate serialization
if($ex instanceof HttpErr\HttpErrorInterface) {
# AppBundle\Exceptions\Http\*
# A displayable error thrown intentionally by our controllers
$status = $ex->getStatusCode();
$message = $ex->getMessage();
$other = $ex->getAdditionalDatas();
} elseif($ex instanceof InsufficientAuthenticationException) {
throw new HttpErr\EUnauthorized; # look a this line
}
# more elseifs...
That works. The Symfony authentication exception is catched, then converted in EUnauthorized, and then EUnauthorized is serialized into JSON. But you can see that I throw the exception without message or previous exception.
Because I want to do this:
elseif($ex instanceof InsufficientAuthenticationException) {
# the standard argument $previous is in 2nd position in my exceptions instead of being 3rd.
# the previous argument is important for me since it will keep context in error propagation.
throw new HttpErr\EUnauthorized($ex->getMessage(), $ex);
}
When I do this (so, just adding two arguments), the serialization stops working, my event listener is not called and the app crashes (in prod, this will turn into a friendly WSoD):
Why?
In the first "if" you extract data for serialization, in the second you are just rethrowing a new exception.
This new exception does not go the kernel.exception flow anymore. It is correctly just thrown: as you can see you have the full stack of exceptions shown.
Ideally, you should end your onKernelException with some kind of Response.
EDIT
I'll expand a bit my previous answer with references to the Symfony documentation and code.
The HttpKernel docs say
If an exception is thrown at any point inside HttpKernel::handle, another event - kernel.exception is thrown. Internally, the body of the handle function is wrapped in a try-catch block. When any exception is thrown, the kernel.exception event is dispatched so that your system can somehow respond to the exception.
So, your listener is called after an exception in the handle function, but, as you can see in source no try/catch is provided by the handleException function. This basically means that an Exception thrown in your listener should not be caught.
In your listener you could swap the current exception with a new one with $event->setException(...) or just try to build a Response yourself.
In any case, throwing a new Exception does not seem the proper way here. I sadly don't know why you code works with or without parameters without all the code involved.
I don't know if it helps here, but I had similar problem my event listener is not called and the app crashes. So i worked around that and overrided one method in Kernel.php file like that:
protected function initializeContainer() {
try {
$container = parent::initializeContainer();
} catch (\Throwable $throwable){
// MY CATCH CODE GOES HERE
}
return $container;
}
You can also hook up to other Kernel methods and override them.
Notice: I'm using Symfony 4.2.*
I am using Symfony 2.4 and am trying to create a more powerful exceptions handler that, on certain PDO / Doctrine exceptions, changes the status code of the response from 500 to 503 to display a different custom error message than our standard (in other words, it returns the error503.html.twig template rather than error500.html.twig). So far, I have created a custom Exceptions controller that extends the TwigBundle ExceptionController, I have changed the Twig exception parameter in config.yml, and I am able to catch any and all exceptions that are thrown once Symfony calls handle(...) in HttpKernel.php:185 (so it's really the second time that handle is called -- this time being on the HttpKernel rather than the AppKernel). I'll refrain from posting all that code, and instead direct the reader here to learn more about my method if they are unfamiliar. All of that code is working just fine -- I am able to modify any applications that are thrown within my application, so you can assume that I'm using the aforementioned approach properly.
The issue I am running into is that in addition to catching exceptions that are thrown within Symfony, I also want to also be able to catch exceptions that are thrown before the HttpKernel's handle method is called (an example being a PDO Access Denied exception that is thrown from improper database credentials). To give you a more specific rundown, in app_dev.php, you have:
$response = $kernel->handle($request);
which calls:
/**
* {#inheritdoc}
*
* #api
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if (false === $this->booted) {
$this->boot();
}
return $this->getHttpKernel()->handle($request, $type, $catch);
}
Now, if an exception gets thrown in $this->boot(), it doesn't look like it gets caught anywhere, and because of that, I can't see any way of gracefully handling said exception in Symfony. It's only if the exception gets thrown within the try / catch block contained in $this->getHttpKernel()->handle($request, $type, $catch) that it will be caught and gracefully handled using Symfony code. Am I wrong about that? Does anyone know of an approach to handling exceptions that are thrown in this context that utilizes Symfony? My apologies in advance if this has already been answered elsewhere.
I ran into a similar problem, I didn't see a neat way around this but was able to get nice error pages for my specific problem simply by generating a Response object and sending that. I placed the following in some code which was called by boot()
try {
someExceptionFunction();
} catch (Exception $e) {
$response = new Response('<html><body>'.$e->getMessage().'</body></html>');
$response->send();
exit;
}
You could easily add some more logic to the catch block, catching different exceptions. It's not as clean/abstract as it could be, but since the entire framework fails to boot I don't know of any option you could use it to parse an error page.
Hope this helps
The problem
I'm building a small application with Silex. It's divided between a REST application and a website. (two controllers, same app).
The website has installed its own custom error handler, which returns a user friendly html page. The problem is that in the part dedicated REST application, I should somehow handle exceptions to return type [json] and content different from the error handler's custom website.
With Symfony2
This argument can also be applied to Symfony2, I would like also possible solution for it!
A first solution for Silex
Wrap the methods in try-catch block in order to rethrowing the exception to handler.
$app->get('/api/show-list', function() use($app){
try {
$show = // db query, etc.
return $app->json(array('show' => $show), 200);
} catch (Exception $e) {
throw new MyException;
}
});
$app->error(function (MyException $e, $code) {
// error api
});
The issue is that if an exception is thrown out of my controllor the default error handler will be used. Some tips?
And with Symfony?
I have been using the following in my Silex RESTful app to return errors in json format:
$app->error(function (\Exception $e, $code) use($app) {
return $app->json(array("error" => $e->getMessage()),$code);
});
Not sure if this is the right way, but it works for me.
This is documented on the Silex site:
http://silex.sensiolabs.org/doc/usage.html#error-handlers
On Symfony2 you can use the ExceptionHandler. On the Exception you have the stack trace, so you can identify where it was thrown.
Also, in Symfony2 you can customize depending on the expected format. It's well explained in it's documentation.
For instance, if you replace the ExceptionController with one of yours, the third parameter shows the expected format:
Reference on where to change the ExceptionController
ExceptionController API
When a user accesses /user/validate without the correct post parameters, my Zend application throws a zend exception. (I get the standard "An Error Occurred" message, framed within my layout). This is intentional.
I am now trying to test that behaviour with PHPUnit. Here's my test:
/**
* #expectedException Zend_Exception
*/
public function testEmptyUserValidationParametersCauseException() {
$this->dispatch('/user/validate');
}
When I run the test I get a message saying it failed, "Expected exception Zend_Exception". Any ideas?
I have other tests in the file which are working just fine...
Thanks!
The Zend_Controller_Plugin_ErrorHandler plugin handles exceptions for you and the default Error_Controller forces a 500 redirect which may mean the exception you are testing for no longer exists. Try the following unit test and see if it passes:
public function testUnknownUserRedirectsToErrorPage()
{
$this->dispatch('/user/validate');
$this->assertController('error');
$this->assertAction('error');
$this->assertResponseCode('500');
}
If this works then it shows that by the time you are rendering the error view the exception will no longer exist as it is contained in the code before the redirect.
Well, maybe it simply fails because no exception is thrown?
Did you try running the test without "#expectedException Zend_Exception"? Is there an exception at all?