23

I would like to disable error reporting entirely on production, because we have some very old code we still need to fix but for now does work (yes I don't like it either). We cannot fix everything in a few days, so we need to just supress the warnings and exceptions like we always did.

The real problem is that it already throws an exception on a simple lazy bug like (because var is not defined)

if(!$var) {
     // do whatever
}

tried

APP_DEBUG=false

APP_LOG_LEVEL=emergency

display_errors(false);
set_error_handler(null);
set_exception_handler(null);

But it still shows an ErrorException

Undefined variable: script_name_vars_def

edit: The code works like this

web.php

Route::any('/someroute', 'somecontroller@controllerFunc');

somecontroller.php

public controllerFunc() {
    ob_start();
    require '/old_index.php';
    $html = ob_get_clean();

    return response($html);
}

This way we use Laravel routing without having to rewrite the old code immediately.

I know I can fix this warning very easy, but there are many, many more of these errors and we need to use Laravel routing now. Fix the problems later.

ideas

edit to explain after which steps middleware didn't work

1) create midddleware

php artisan make:middleware SuppressExceptions

2) Write it

SuppressExceptions.php

public function handle($request, Closure $next)
{
    error_reporting(0);
    return $next($request);
}

3) Register

laravel/app/Http/Kernel.php

protected $middlewareGroups = [
   'web' => [
       \App\Http\Middleware\SuppressExceptions::class,
],
online Thomas
  • 8,864
  • 6
  • 44
  • 85

8 Answers8

14

Yes you can change the error reporting. In fact, the framework provides a place to intercept the exceptions: App\Exceptions\Handler. By default the render method will convert the exception thrown to a HTML response. The APP_ENV and APP_DEBUG values will only change how this error response will render (details on the exception stack trace or not, basically).

Try changing the render method to

public function render($request, Exception $exception)
{
    if ($exception instanceof ErrorException) {
        error_reporting(0);

        $kernel = app(\Illuminate\Contracts\Http\Kernel::class);
        $response = $kernel->handle($request)->send();
        return $kernel->terminate($request, $response);
    }

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

This basically turns reporting off and then attempts to re-handle the request. In the if clause you may check for any condition you want (the class of the exception, the severity, etc.). Catching ErrorException will probably cover your needs, but notice that you may not be able to recover from a fatal error this way.

Anyway, you should take that as a "proof of concept"... For non-idempotent requests, this "re-handle" approach is not good. Instead, just create a Middleware with

public function handle($request, Closure $next)
{
    error_reporting(0);
    return $next($request);
}

Same as before, fatal errors can't be recovered this way. But you can show a custom error message combining this middleware with the exception handler approach from before:

public function render($request, Exception $exception)
{
    if ($exception instanceof FatalErrorException) {
        return view('fatal-error', ['exception' => $exception]);
    }

    return parent::render($request, $exception);
}
alepeino
  • 9,551
  • 3
  • 28
  • 48
  • @ThomasMoors what's "didn't work"? You keep seeing the "Whoops" message? What's the exception? With this method I tried and successfully ignored some errors like undefined variable or division by zero – alepeino Jul 03 '17 at 12:22
  • Yes, it does keep showing every single error. I will edit my question to explain the steps I tried from your answer. – online Thomas Jul 03 '17 at 12:33
  • @ThomasMoors saw your edit. That's exactly what I have. Are you sure the route is in the `web` group? Try doing `dd(something);` in the middleware method, just to make sure it is applying. – alepeino Jul 03 '17 at 12:50
  • Yes I'm positive, have you tested your setup in combination with the code I wrote in *somecontroller.php* using `ob_get_clean`? It might yield different results – online Thomas Jul 03 '17 at 12:55
  • @ThomasMoors wait, are you sure it's not the `require` that's failing? With `require '/old_index.php';` you are looking for a file at the root of the filesystem. Is there where you have it? – alepeino Jul 03 '17 at 13:07
  • Yes, bacause after fixing the bugs for a certain "page" it shows up as expected. – online Thomas Jul 03 '17 at 13:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/148226/discussion-between-alepeino-and-thomas-moors). – alepeino Jul 03 '17 at 13:11
  • Why not do a `if (config('app.env') === 'production') {` kill the render method. Else, return the parent render method. – Juan Pablo Jul 06 '17 at 14:46
14

Laravel debug settings is located in the .env file, in which you can set the debug option as follows:

APP_DEBUG = true

but...

Laravel also have config mechanism that located in app.php in the config folder, which defaults to:

'debug' => env('APP_DEBUG', false),

which tells Laravel to use the .env value, and defaults to false, but anyone with access to the file, can simply change it to:

'debug' => true,

so that your .env value gets ignored by Laravel.

am05mhz
  • 2,727
  • 2
  • 23
  • 37
  • 3
    If you have read the question and given answers, you could have know or deducted it's not as simple as forgetting the existence of the `.env` file. Next to that: env file has priority over the config file, the config file is the fallback value. – online Thomas Jul 04 '17 at 06:48
  • agreed, but what i told you is just that, it might be changed by someone who have access to the config file, like the last point of my statement? – am05mhz Jul 04 '17 at 07:53
  • It is **not** the case and even if it were: The .env file overrules the `app.php`. Are you satisfied now? – online Thomas Jul 04 '17 at 09:00
  • 2
    you are slightly wrong about the `.env` overrules the `app.php`, it overrules it because of the second point in my statement, and if it were changed, then the behavior would change. but if its not changed, then suits yourself, no need to be mad. i was merely assuming you are working as a team. looks like i was wrong – am05mhz Jul 05 '17 at 15:56
  • 1
    I do work in a team. The reason you agitate me is thst you give a low quality answer and you go to any lengths to defend it as a good answer. – online Thomas Jul 05 '17 at 16:43
  • I am giving you another place to check for, how is it poor quality (or good quality)? its not aimed to be, and clearly by the way you responded, you did not know how the config files are loaded, in which I gave you the information of it. – am05mhz Jul 06 '17 at 02:41
  • This solved my issue - I forgot to change the .env ;) IMHO this is the 'correct' way of disabling public error reporting. OP was looking for a hacky way to not deal with some tech debt. Real world can be a bitch. – Geoff Salmon Jan 07 '20 at 03:47
8

how i do is in

app/providers/AppServiceProvider 

in boot function

public function boot()
{
   //add error reporting level
   error_reporting(0);
}

App Service Provider runs before Laravel compiles and therefore in boot function you can set error reporting to any level. it will set for all running scripts. You can open your app/providers/AppServiceProvider.php and in boot function add error_reporting(0/1)

Erenor Paz
  • 3,061
  • 4
  • 37
  • 44
danny
  • 407
  • 1
  • 5
  • 10
  • Can you explain that further such that others can learn from it? – Nico Haase May 05 '19 at 15:55
  • App Service Provider runs before Laravel compiles and therefore in boot function you can set error reporting to any level. it will set for all running scripts. You can open your app/providers/AppServiceProvider.php and in boot function add error_reporting(0/1) – danny May 30 '19 at 18:26
4

I guess your php.ini loaded from another place. So settings still not applied. Try to find correct location of php.ini (you can see information in the phpinfo()). Anyway, you can rewrite those parameters with yours in index.php:

error_reporting(0);
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);

But as the @Davon says in the comment. Those settings will be overwritten by Laravel. So code above can be placed in your controller. But it will be dirty hack. So You have to find another way. Try to print your .env's content. Maybe some setting is incorrect.

Alex Slipknot
  • 2,439
  • 1
  • 18
  • 26
4

If the problem is that you are seeing the 'Whoops something went wrong' page, you could fix that with the answer @alepeino wrote:

https://stackoverflow.com/a/44862789/2777970

But I'd change the render method to:

public function render($request, Exception $exception)
{
    if (!config('app.debug')) {
        error_reporting(0);

        return response('nothing', 500);
    }

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

This render method (the parent) is the one that builds and returns the html for the "Whoops" page, so if you overwrite it, you should be cool.

To change de debug config, check if your config/app.php has the debug options using the ENV value APP_DEBUG, and on your production .env, check it's set to false (APP_DEBUG=false).

Juan Pablo
  • 363
  • 2
  • 9
  • And about the bug that's causing it to display an error, you should use `if (!isset($var) || !$var) ` So it checks if the variable exists before checking it's boolean value, so you won't get an error. But I think you may not wanna fix this or it's not as simple as you said, cause otherwise this question would be anotherone – Juan Pablo Jul 06 '17 at 15:04
  • 2
    I already fixed 1000+ instances of this "bug" haha, my solution btw is `$var = $var ?? null` – online Thomas Jul 06 '17 at 15:05
  • Nice, php7 features – Juan Pablo Jul 06 '17 at 15:06
  • This works partially: it stops rendering the rest of the page upon reaching the "bug". – online Thomas Jul 06 '17 at 15:27
  • But I don't get it, you still have content before? Or you get the php error? To fix the php error shouldn't you fix it with the php.ini suggestion someone told? `ini_set('display_errors', 0);` ? – Juan Pablo Jul 06 '17 at 20:41
  • Can you show me a screen or a tinypaste of the output? I think it'll help a lot. And your desired result (empty with a 500 status?) – Juan Pablo Jul 06 '17 at 20:52
  • Desired result is routing with laravel, but output as if the file(s) was / were called directly. That's why I was using ob_get_clean – online Thomas Jul 06 '17 at 22:06
  • Oh.... I don't know how to help you with that... did ob_get_clean work? Cause it looks like you are trying to undo some printing... So I guess you are migrating to laravel instead of embedding php tags as it was before? – Juan Pablo Jul 06 '17 at 23:55
  • It does work, but now every soft-error / bug like using the check `!$var` (instead of (`!isset($var)`) will trigger an exception and even when turning of the render function of the exception still prevents the rest of the page from executing – online Thomas Jul 07 '17 at 05:46
  • So what about supressing erros? `error_reporting(0)` there I think might be too late, so why don't you add that error_reporting line on your `bootstrap/app.php` and see what happens? – Juan Pablo Jul 07 '17 at 21:36
  • I would suggest to debug it by standing before the error (on the code) and testing what kind of error_reporting type best suits your problem. Check [php error-reporting](http://php.net/manual/en/function.error-reporting.php) for more options. Here you have more error configs to try out [php errorfunc.configuration](http://php.net/manual/en/errorfunc.configuration.php). If you found your desired one (I recommend not to overdoit), add it to your bootstrap/app.php. Good luck – Juan Pablo Jul 07 '17 at 21:37
3
error_reporting(0);
ini_set('display_errors', 0);

The second line changes the value of 'display_errors' in the php.ini file

EDIT: Add more code to show how this has to be environment specific...

$env = getenv('APPLICATION_ENV');

 switch ($env) {
        case 'production':
            error_reporting(0);
            $config = include __DIR__ . '/../app/config/config_prod.php';
            break;

        case 'staging':
            ini_set('display_errors', 1);
            $config = include __DIR__ . '/../app/config/config_staging.php';
            break;

        case 'development':
        case 'local':
        default:
            ini_set('display_errors', 1);
            $config = include __DIR__ . '/../app/config/config_local.php';
            break;
Pila
  • 5,460
  • 1
  • 19
  • 30
  • it has no effect for me at all, it still shows `Whoops, looks like something went wrong.` – online Thomas Jun 28 '17 at 15:19
  • can you show a little more code of what you're trying to achieve? Also, not that those that these changes have to be environment specific. See my edits – Pila Jun 28 '17 at 15:24
  • You may want to consider getting the environment with `config('app.env')` instead of calling `getenv`; if the configuration is cached, the call to `getenv` will return null instead of production, staging, etc. – Chris Forrence Jun 28 '17 at 15:29
  • 1
    This won't have an affect on Laravel since Laravel resets error_reporting when the app is booted, you'll need to modify the core framework HandleExceptions.php like shown in my example. – Devon Bessemer Jun 28 '17 at 15:49
1

Laravel emphasizes error and warning free code, so the best way to handle this is just by making sure your code doesn't produce any errors, warnings, or notices.

Update: I do not recommend the below method for recent versions of Laravel. Laravel now allows you to change exception handling in a non-vendor class: App\Exceptions\Handler as indicated by alepeino's answer. A middleware can also be a better solution to disabling error_reporting.

This previous answer is maintained for historical purposes but I don't recommend modifying vendor files.


If, however, you still decide to alter this behavior, you'll need to look in a file named HandleExceptions.php normally found at vendor/laravel/framework/src/illuminate/Foundation/Bootstrap/HandleExceptions.php:

public function bootstrap(Application $app)
{
    $this->app = $app;
    error_reporting(-1); // change this line to your desired reporting level
    set_error_handler([$this, 'handleError']);
    set_exception_handler([$this, 'handleException']);
    register_shutdown_function([$this, 'handleShutdown']);
    if (! $app->environment('testing')) {
        ini_set('display_errors', 'Off');
    }
}

Line 32 where error_reporting is currently set to -1. https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php

Of course, by modifying this code, you'll either need to prevent updates of laravel/framework or you'll need to verify this file on every update.

After updating this code, you'll need to recompile your classes:

php artisan clear-compiled; php artisan optimize
Devon Bessemer
  • 34,461
  • 9
  • 69
  • 95
0

Use this method in any function in your class as example:

try {
    // ...
} catch (\Exception $e) {
    return redirect()->intended(route('home'));
}
Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
loverphp
  • 1
  • 1