How to catch PostTooLargeException in Laravel?
Asked Answered
E

4

2

To reproduce the error, simply upload a file(s) to any POST routes in Laravel that exceeds the post_max_size in your php.ini configuration.

My goal is to simply catch the error so I can inform the user that the file(s) he uploaded is too large. Say:

public function postUploadAvatar(Request $request)
  try {
    // Do something with $request->get('avatar')
    // Maybe validate file, store, whatever.
  } catch (PostTooLargeException $e) {
    return 'File too large!';
  }
}

The above code is in standard Laravel 5 (PSR-7). The problem with it is that the function can't execute once an error occurs on the injected request. Thereby can't catch it inside the function. So how to catch it then?

Examinee answered 19/3, 2017 at 5:14 Comment(0)
L
11

Laravel uses its ValidatePostSize middleware to check the post_max_size of the request and then throws the PostTooLargeException if the CONTENT_LENGTH of the request is too big. This means that the exception is thrown way before it even gets to your controller.

What you can do is use the render() method in your App\Exceptions\Handler e.g.

public function render($request, Exception $exception)
{
    if ($exception instanceof PostTooLargeException) {
        return response('File too large!', 422);
    }

    return parent::render($request, $exception);
}

Please note that you have to return a response from this method, you can't just return a string like you can from a controller method.

The above response is to replicate the return 'File too large!'; you have in the example in your question, you can obviously change this to be something else.

Hope this helps!

Littoral answered 19/3, 2017 at 9:22 Comment(4)
This catches the error, allows me to handle it in some way. But along with returning a response, PHP also echoes the message"Warning: POST Content-Length of 18156282 bytes exceeds the limit of 8388608 bytes in Unknown on line 0". Now how may I deal with that?Examinee
@Examinee What version or PHP are you using, what version of Laravel are you using, and what have you got your app environment set to?Littoral
I have PHP 7.0.5, Laravel 5.4. It's a Homestead environment. Set to local environment. Debug is enabled. But even if I disable debug, the warning still occurs.Examinee
@Examinee That is weird as (unless I'm mistaken) Laravel should set display_errors to 'off' unless your in testing. Have you explicitly set display_errors to 'on' anywhere?Littoral
H
5

You can also redirect to a Laravel view of your choice if you wish to add a more content richer response to the user.

public function render($request, Exception $exception)
{
    if ($exception instanceof \Illuminate\Http\Exceptions\PostTooLargeException)
        return response()->view('errors.post-too-large');

    return parent::render($request, $exception);
}

ALSO NOTE: For the exception to be caught you should make sure you provide the proper path to the PostTooLargeException by either importing the class using the use Illuminate\Http\Exceptions\PostTooLargeException; import statement or just writing the full path like in my example.

Hawn answered 4/10, 2017 at 11:45 Comment(0)
P
0

The exception is rendered before the Session starts so you cannot redirect back with an error message.

You can create a new blade file and redirect there like this:

public function render($request, Throwable $exception)
{
    if ($exception instanceof \Illuminate\Http\Exceptions\PostTooLargeException) {
        return $this->showCustomErrorPage();
    }

    return parent::render($request, $exception);
}

protected function showCustomErrorPage()
{
    return view('errors.errors_page');
    //you can also return a response like: "return response('File too large!', 422);"

}

To show a static message using sessions:

1.You have to move the ValidatePostSize class from the middleware array into the middlewareGroups array, directly after the StartSession.

        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
  1. After that in Handler.php you can do:

     public function render($request, Throwable $exception)
     {
     if ($exception instanceof \Illuminate\Http\Exceptions\PostTooLargeException) {
         return $this->showCustomErrorPage();
     }
         return parent::render($request, $exception);
     }
    
     protected function showCustomErrorPage()
     {
         return \Illuminate\Support\Facades\Redirect::back()->withErrors(['max_upload' => 'The Message']);
     }
    
  2. Show the message on your controller like this:

     @error('max_upload')
     <div class="alert" id="create-news-alert-image">{{ $message }}</div>
     @enderror
    
Pimp answered 2/12, 2020 at 10:21 Comment(0)
M
0

You can use the render() method in your App\Exceptions\Handler:

public function render($request, Exception $exception)
{
    if ($exception instanceof PostTooLargeException) {
        return redirect()->route('errors.413');
    }

    return parent::render($request, $exception);
}

implement a 413 route that redirects back with error message or session flash message:

Route::get('413', function (Request $request) {

    if ($request->wantsJson()) {
        return response()->json(['error' => __('validation.post_too_large')], 413);
    }

    $request->session()->flash('error', __('validation.post_too_large'));

    return redirect()->back();
})->name('errors.413');

since I'm using toastr to display an error message I pass a flash message to the session, but you can also redirect()->back()->withErrors([...]);

Macri answered 25/8, 2023 at 16:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.