Displaying exception error message in 404 pages - php

I have a controller where i do something like this
return abort('401', 'User cannot be found');
How do i access the message in my view (errors/401.blade.php).
/************* 401.blade.php ***********/
{{ dd($exception) }}
If i die dump $exception in my view i get this
HttpException {#203 ▼
-statusCode: "401"
-headers: []
#message: "User cannot be found"
#code: 0
#file: "C:\laravel\framework\src\Illuminate\Foundation\Application.php"
#line: 882
-trace: array:54 [▶]
}
How to do i access the message variable?

Well, in Laravel documentation said this:
Custom HTTP Error Pages
Laravel makes it easy to return 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.
I think you have to create a 401.blade.php view and then your code will work.
As showed here: https://stackoverflow.com/a/29633624/4425719
Extend Laravel's Exception Handler,
Illuminate\Foundation\Exceptions\Handler, and override
renderHttpException(Symfony\Component\HttpKernel\Exception\HttpException
$e) method with your own.
If you haven't run php artisan fresh, it will be easy for you. Just
edit app/Exceptions/Handler.php, or create a new file.
Handler.php
<?php namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
class Handler extends ExceptionHandler {
// ...
protected function renderHttpException(HttpException $e) {
$status = $e->getStatusCode();
if (view()->exists("errors.{$status}")) {
return response()->view("errors.{$status}", compact('e'), $status);
}
else {
return (new SymfonyDisplayer(config('app.debug')))->createResponse($e);
}
}
}
And then, use $e variable in your 404.blade.php.
i.e.
abort(404, 'Something not found');
and in your 404.blade.php
{{ $e->getMessage() }}
For other useful methods like getStatusCode(), refer
Symfony\Component\HttpKernel\Exception

Related

'Session store not set on request' after including header

I'm using the following exception handler in the handler.php file :
public function render($request, Exception $e)
{
if ($e instanceof CustomException) {
return response()->view('errors.404', [], 404);
}
return parent::render($request, $e);
}
It is working fine until I include the header to the 404.blade.php file :
#include('includes.header')
I start receiving this error :
Session store not set on request. (View: C:\xampp\htdocs\sharp\resources\views\includes\header.blade.php)
Because the route wasn't found, the web middleware, which starts the session, was never applied.
I'm not a fan of this answer, but it is relevant.
Instead, consider passing a parameter to your nested template specifying if the section of your template calling Auth::user() should be rendered, via the #if blade directive.
Something like:
#include('includes.header', ['omit_auth' => true])
then in your header template:
#if (!empty($omit_auth))
{{ Auth::user()->name }}
#endif

Laravel custom exception

Before posting this question I have searched internet for appropriate answers but got none.These are my following questions:
1) How to throw exception without try catch in laravel controller and get exception in the view of the called controller.
Example : TestController.php
function index(){
throw new CustomException('Data not found');
return view('dashboard');
}
How to get exception message in dashboard view
2) How to set format for exception message, suppose I want to return format as
$response['code'] = 0;
$response['status'] = 'error';
$response['message'] = 'message';
$response['data'] = '';
I have created a custom exception but don't know how to use it to fully
<?php
namespace App\Exceptions;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Mockery\Exception;
class CustomException extends Exception{
public $response;
/**
* Report the exception.
*
* #return void
*/
public function report()
{
}
/**
* Render the exception into an HTTP response.
*
* #param \Illuminate\Http\Request
* #return \Illuminate\Http\Response
*/
public function render($request,$exception){
ob_clean();
$response['code'] = 0;
$response['status'] = 'error';
$response['message'] = 'Message';
$response['data'] = '';
if(!$request->ajax()){
// non ajax response
}else{
return response()->json($response);
}
}
}
Answering your questions:
To pass this exception to view, you can implement render method what you already started to do. You can just do:
if(!$request->ajax()){
view('error_handler', compact('exception'))
} else {
return response()->json($response);
}
so now you can just create error_handler.blade.php view and you will have access in there to $exception variable, so you can use in there {{ $exception->getMessage}} and so on
You didn't define what exactly you want to achieve, however it should work without any problem:
public function render($request,$exception) {
if(!$request->ajax()){
view('error_handler', compact('exception'))
}
return response()->json([
'code' => $exception->getCode(),
'status' => 'error',
'message' => $exception->getMessage(),
'data' => 'sample data'
]);
}
Of course instead of using $exception->getCode() for code you can put anything you want, this is just an example that you can also use code and message that you have in your exception assuming you set some custom when you throw exception for example:
throw new CustomException('This is custom message', 123);
There isn't realy reason to thrown an exception if your purpose is to show the message of that exception within the view which is rendered by the controller. And It isn't a best way to manage exception, because by default all exception which are throw are handle and catch within the App\Exceptions\Handler class.
I think you know exactly when that type of CustomExption you have create will be thrown, but instead of throwing that error just traite that error which need an exception in different way without exception. For that you can create an Array in which old code, status, message, data and pass it to the view method;
class CustomController extends Controller
{
public function samemethod(){
// some code that can generate an error
// construct the error data
$customErrorData = [
'code' => 0000,
'status' => "some status",
'message' => "Some error message",
'data' => [...]
];
// After error data creation you can pass it to the view
return View::make('customview', compact('customErrorData'));
}
}
You have you error data in your view
All uncaught exceptions are intercepted by default exceptions handler. If you want this to behave differently, you just need to modify it: https://laravel.com/docs/5.7/errors#the-exception-handler

Laravel API receive JSON 404 not found

I'm developing a Laravel 5.6 API and I'm using Resources and Collections, Route Model Binding.
To show an item, I currently use following code in my controller:
public function show(Todo $todo)
{
TodoResource::withoutWrapping();
return new TodoResource($todo);
}
In the Exceptions > Handler.php I have the following:
public function render($request, Exception $exception)
{
// This will replace our 404 response with
// a JSON response.
if ($exception instanceof ModelNotFoundException) {
return response()->json([
'error' => 'Resource not found'
], 404);
}
return parent::render($request, $exception);
}
This works perfectly when the item is found in the database. If the item is not in the database I get a (when using a browser):
"Sorry, the page you are looking for could not be found"
When using POSTMAN rest client, I'm getting
{
"message": "No query results for model [App\\Todo].",
"exception": "Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException",
....
....
I would like to simply retrieve a 404 error with text "Resource not found", using both a browser or POSTMAN.
* Update with Routing info *
In my api.php, I have the following:
Route::apiResource('todos', 'TodoController');
Route::fallback(function () {
return response()->json(['message' => 'Not Found!'], 404);
});
In web.php, I have:
Route::Resource('todos', 'TodoController');
What is the best way to achieve this?
Make sure to alias the exception class you are checking for.
use Illuminate\Database\Eloquent\ModelNotFoundException;
Without this you are checking for an instance of App\Exceptions\ModelNotFoundException.

Laravel Exception is a 401 but response header is 500

i'm throwing a exception in my controller when the user is not authorized to make any action, i created a custom exception class to do it. i'm using this package too: https://github.com/esbenp/heimdal to format my response in a better format.
however, when i set my status code in my exception to 401, my response is 500.
<?php
namespace App\Acl\Exceptions;
use Exception;
use Throwable;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class UserUnauthorizedException extends Exception
{
public function __construct($message = "", $code = 0, \Throwable $previous = null)
{
parent::__construct('you are not authorized to perform this action', 401, $previous);
}
Instead of
class UserUnauthorizedException extends Exception
try:
class UserUnauthorizedException extends UnauthorizedHttpException
Note that 401 that you are using in the constructor is not a HTTP code. It's an arbitrary value that you can set for custom evaluation somewhere else.
Try below code:
<?php
namespace App\Acl\Exceptions;
use Exception;
use Throwable;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class UserUnauthorizedException extends UnauthorizedHttpException
{
public function __construct($message = "", $code = 0, \Throwable $previous = null)
{
parent::__construct('you are not authorized to perform this action', 401, $previous);
}
This is caused by the library you use. You could create an issue or submit a PR yourself otherwise you might have to switch to an alternative.
For reference, this is where the response status code is set: https://github.com/esbenp/heimdal/blob/master/src/Formatters/ExceptionFormatter.php#L13
edit: Basically you have to either extend the correct HttpException that is already being handled by the HttpExceptionFormatter in your library or update the configuration specifying that your Exception should be handled by it. The config could look something like this:
return [
'formatters' => [
\App\Acl\Exceptions\UserUnauthorizedException::class => \Optimus\Heimdal\Formatters\HttpExceptionFormatter::class,
\Exception::class => \Optimus\Heimdal\Formatters\ExceptionFormatter::class,
]
];
This will use the HttpExceptionFormatter for your exception (and every class inheriting from it) whereas all other exceptions are handled by the generic ExceptionFormatter.
The default config can be found in the project's README: https://github.com/esbenp/heimdal#formatters
From this you can also gather that if you extend Symfony\Component\HttpKernel\Exception\HttpException the HttpExceptionFormatter should kick in and should use the status code that you provide.

How to catch authorization errors in Laravel's Handler render

I'm trying to show a custom error page, which I'd like to appear if the error wasn't a 'page not found' or a authentication issue (e.g. trying to access a page which the user doesn't have access to). I'm using the code below in Laravel 5.3's Handler.php. While the 404 part works, the authentication part doesn't (triggering this error just returns the 500 page instead). What am I missing?
public function render($request, Exception $e)
{
if ($e instanceof NotFoundHttpException || $e instanceof AuthorizationException || $e instanceof AuthenticationException) {
return parent::render($request, $e);
}
else {
return response()->view('errors.500', [
'sentryID' => $this->sentryID,
], 500);
}
}
Edit : Looks like you want to handle all the global error pages. Laravel uses symfony's exception handler to generate the error page text and style. This can be found at
vendor/symfony/debug/ExceptionHandler.php
It's used in vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php as
use Symfony\Component\Debug\ExceptionHandler as SymfonyExceptionHandler;
To handle every error and exception you can extend the method prepareResponse to app/Exceptions/Handler.php and make appropriate changes.
protected function prepareResponse($request, Exception $e)
{
if ($this->isHttpException($e)) {
return $this->toIlluminateResponse($this->renderHttpException($e), $e);
} else {
return $this->toIlluminateResponse($this->convertExceptionToResponse($e), $e);
}
}
You can check the underlying working of this method in vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php
End edit
You don't need to mess in the render method for this. Out of the box laravel searches for error views and renders them if available based on the error code. So for 404 and 500 you could just create the following two views and customize it in there.
resources/views/errors/404.blade.php
resources/views/errors/500.blade.php
This views get the exception, status and header information for you to display if needed. They are called like so
return response()->view("errors.{$status}", ['exception' => $e], $status, $e->getHeaders());
For the authentication check. Laravel calls the unauthenticated method in app/Exceptions/Handler.php when a user is unauthenticated. This code by default redirects the users to login page or shows a json response. You can make you changes here.
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
return redirect()->guest('login');
}

Categories