Laravel redirect ALL types of errors to custom view - laravel

I'm looking for a way to catch all possible errors and redirect all types of errors to 1 page.
My current code in /Exceptions/Handler.php:
if ($this->isHttpException($exception)) {
$statusCode = $exception->getStatusCode();
switch ($statusCode) {
case '404':
return response()->view('layouts/404');
}
}
Problem is that ErrorException (E_NOTICE) types (which are caused by possible bugs in the code) aren't redirected to the 404 page. These errors end up on the 'Woops something went wrong' page.
I basically am trying to make every type of error end up on my custom error page.
All attempts end up on white pages.
What am I not seeing?

Well, to do what you're asking for you should go to App\Exceptions\Handler.php and there, you need to modify the render method:
public function render($request, Exception $exception)
{
abort(404);
}
But I insist, this is a terrible idea, you should catch the Exceptions that your app may get and show the error message to the user in a clean way, for example:
try{
//... your fancy code here
}catch(Exception $e){
// return with the message error $e->getMessage()
}

Related

Pass request to exception

Since I started logging exceptions on a production site I'm noticing a lot of them, especially 404s, more than I would expect for a site with barely any traffic, and I'd like to get to the bottom of whether they're genuine users or just bots. To help with this, I want to capture the URL that the user was trying to visit before being redirected to the 404 route, so I can keep track of which non-existent routes are being mistakenly hit. I think I'm correct in assuming this URL should be available in the request, and that I just need to store the request and pass it through to the exception.
What's the best way to do this in Laravel 8 onwards?
Catch 404 exceptions in Handler(App\Exceptions\Handler).
If you see Rendering Exceptions
By default, the Laravel exception handler will convert exceptions into
an HTTP response for you. However, you are free to register a custom
rendering closure for exceptions of a given type. You may accomplish
this via the renderable method of your exception handler.
The closure passed to the renderable method should return an instance
of Illuminate\Http\Response, which may be generated via the response
helper. Laravel will deduce what type of exception the closure renders
by examining the type-hint of the closure:
so in the register method,call renderable
public function register()
{
$this->renderable(function (NotFoundHttpException $e, $request) {
Log::alert("404",[
"fullUrl"=>$request->fullUrl(),
"path"=>$request->path(),
"message" =>$e->getMessage()
]);
return response()->view('errors.404', [], $e->getStatusCode());
});
}
Also, don't forget to import and use
Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
EDIT: just a few hours of using this solution in production, with the benefit of the newly-added request URLs, has confirmed for me just how many of these HTTP 4xx errors are junk - mostly automated bots and maybe a few script kiddies trying common routes. For this reason I've added some logic to ignore 404 and 405 errors, and may still add others that mostly contribute noise to the logfile.
This was harder than it should have been, but this is the solution I'm currently using to log the request with all exceptions. It's probably not the cleanest way to do it, but it works perfectly for my needs. Thanks to John Lobo's answer for pointing me in the right direction.
It works by inspecting each instance of the Exception class and using PHP's instanceof to check whether it's a HTTP exception or not. If it is, it gets logged with the request URL and returns a view with a status code. If it's a generic non-HTTP exception, it gets logged with the request URL and returns another view with no status code (or you can keep the default exception behaviour by removing the return block, which renders a blank screen in production).
public function register()
{
$this->renderable(function (Exception $exception, $request) {
$url = $request->fullUrl();
if ($exception instanceof HttpException) {
$status = $exception->getStatusCode();
// Do not log HTTP 404 and 405s errors for reasons that will
// become apparent after a few hours of logging 404s and 405s
if(($status !== 404) && ($status !== 405)) {
Log::warning("Error $status occurred when trying to visit $url. Received the following message: " . $exception->getMessage());
}
return response()->view("errors.error", [
"exception" => $exception,
"status" => $status
],
$status
);
} else {
$status = $exception->getCode();
Log::warning("Exception $status occurred when trying to visit $url. Received the following message: " . $exception->getMessage());
return response()->view("errors.exception", [
"exception" => $exception,
"status" => $status
]);
}
});
// Optionally suppress all Laravel's default logging for exceptions, so only your own logs go to the logfile
$this->reportable(function (Exception $e) {
})->stop();
}

Laravel: Way to diagnose "uncaught reflection: class log does not exist" without guessing?

As we all painfully know, this message is generated when an error occurs before Laravel has had a chance to instantiate a "Log" class instance to handle it. And... it therefore seems to completely conceal just what the underlying error is!
In my case the php artisan command won't run either.
Is there any way to find out what's wrong without "blind guessing?"
When you want to handle exceptions, a good way to catch it would be to implement a way to trapping exception out of controllers or services. You can do it in the "render" method of the App\Exceptions\Handler class. In this "render" method, you can write a block of "if" code to show the messages generated by an exception when Laravel throws an exception. For example:
public function render($request, Exception $exception)
{
if($exception) {
// do something
return response()->json(['error' => $exception->getMessage(),
$exception->getTraceAsString()], 500);
}
// Or if you created an exception specialization
if ($exception instanceof MyCustomException) {
return response()->view('errors.custom', [], 500);
}
return parent::render($request, $exception);
}
This was indeed caused by a syntax error, and I'm really surprised that Laravel had even managed to "get started" by that point in time. I literally found it by looking with git at a list of files that had recently changed.

How to redirect another page instead of redirecting to abort 403 error page in Laravel 5.4

My question is whenever there is a 403 error I should redirect to my own custom page or show the flash message(on the same page) something like that.How can I achieve this in Laravel?.
You can use app/Exceptions/Handler.php for this
public function render($request, Exception $e)
{
if ($e->getStatusCode() == 403) {
return redirect('yourpage'); // this will be on a 403 exception
}
return parent::render($request, $e); // all the other exceptions
}
You can create a view for specific HTTP error codes. If you set up a Blade template at resources/views/errors/403.blade.php, it will get used for all 403 error responses.
Source
Alternatively you can set up a custom exception handler for 403 responses if you need something more involved. I found a good example of this here.
you can make you own page in inside the view .resources/views/errors/yourblade.blade.php
after that just return your page to that page.
You can use app/Exceptions/Handler.php for this as Thomas Moors stated above or you can use a try catch for basic error handling.
try {
do Something //
}
catch (Exception $e) {
//log error in log file or dv
return redirect->('home');
}

Design 500 error page only for production

I'm looking for a modern (Laravel 5.4) way to display custom 500 error page only for HTTP (non ajax/fetch) response. I read some threads but each response looks like a trick or is outdated. There is probably something to modify in \App\Exceptions\Handler, but I did not find the "right way".
Is there a simple way to display a specific page on fatal error (uncatched, returning 500) in Laravel 5.4?
In other words, when I have a syntax error on one of my controller, it displays "Whoops something went wrong" with some HTML and 500 error code. I would like to display something else, with the same rules as default behavior (ideally only for HTML browser, not for ajax/fetch, etc.).
EDIT: only in production environment.
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.4/errors#custom-http-error-pages
From the selected "best answer" of this thread: https://laracasts.com/discuss/channels/general-discussion/custom-error-page-er500
You could modify \App\Exceptions\Handler::render():
public function render($request, Exception $exception)
{
if (config('app.debug') && !$this->isHttpException($exception)) {
$exception = new \Symfony\Component\HttpKernel\Exception\HttpException(500);
}
return parent::render($request, $exception);
}
Your exception will be reported in the logs as usually, but woops page will be replaced by your 500.blade.php view.
Sometimes you have to catch the specific exception in order to render the error view. in Laravel 5.4 you can do this by editing the report() method in the App\Exceptions\Handler class
public function report(Exception $exception)
{
if ($exception instanceof CustomException) {
// here you can log the error and return the view, redirect, etc...
}
return parent::report($exception);
}

Creating custom error page in Lumen

How do I create custom view for errors on Lumen? I tried to create resources/views/errors/404.blade.php, like what we can do in Laravel 5, but it doesn't work.
Errors are handled within App\Exceptions\Handler. To display a 404 page change the render() method to this:
public function render($request, Exception $e)
{
if($e instanceof NotFoundHttpException){
return response(view('errors.404'), 404);
}
return parent::render($request, $e);
}
And add this in the top of the Handler.php file:
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Edit: As #YiJiang points out, the response should not only return the 404 view but also contain the correct status code. Therefore view() should be wrapped in a response() call passing in 404 as status code. Like in the edited code above.
The answer by lukasgeiter is almost correct, but the response made with the view function will always carry the 200 HTTP status code, which is problematic for crawlers or any user agent that relies on it.
The Lumen documentation tries to address this, but the code given does not work because it is copied from Laravel's, and Lumen's stripped down version of the ResponseFactory class is missing the view method.
This is the code which I'm currently using.
use Symfony\Component\HttpKernel\Exception\HttpException;
[...]
public function render($request, Exception $e)
{
if ($e instanceof HttpException) {
$status = $e->getStatusCode();
if (view()->exists("errors.$status")) {
return response(view("errors.$status"), $status);
}
}
if (env('APP_DEBUG')) {
return parent::render($request, $e);
} else {
return response(view("errors.500"), 500);
}
}
This assumes you have your errors stored in the errors directory under your views.
It didn't work for me, but I got it working with:
if($e instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
return view('errors.404');
}
You might also want to add
http_response_code(404)
to tell the search engines about the status of the page.

Resources