在Laravel生产环境中完全禁用错误报告?

24

我希望在生产环境中完全禁用错误报告,因为我们有一些非常老的代码仍然需要修复,但目前可以正常工作(是的,我也不喜欢它)。我们无法在几天内修复所有问题,所以我们需要像以前一样抑制警告和异常。

真正的问题是,它已经在一个简单的懒惰错误上抛出了异常(因为变量未定义)。

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

尝试过

APP_DEBUG=false

APP_LOG_LEVEL=emergency

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

但仍然显示一个ErrorException

未定义变量:script_name_vars_def

编辑:代码的工作方式如下

web.php

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

somecontroller.php

某个控制器.php
public controllerFunc() {
    ob_start();
    require '/old_index.php';
    $html = ob_get_clean();

    return response($html);
}

这样,我们可以使用Laravel路由而不必立即重写旧代码。

我知道我可以很容易地解决这个警告,但还有许多这样的错误,我们现在需要使用Laravel路由。稍后再解决问题。

想法

编辑以解释哪些步骤后中间件无效

1)创建中间件

php artisan make:middleware SuppressExceptions

2) 将其写下来

SuppressExceptions.php

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

3) 注册

laravel/app/Http/Kernel.php

protected $middlewareGroups = [
   'web' => [
       \App\Http\Middleware\SuppressExceptions::class,
],

1
你尝试过使用 APP_DEBUG=false 吗? - aynber
不,它只会显示“糟糕,似乎出了些问题。” - online Thomas
@AlexSlipknot 是的,我做了! - online Thomas
@ThomasMoors 嗯,很可能是由于env文件加载错误或者存在一些配置问题。尝试打印已加载的env设置。此外,也许你的index_old.phprequired表达式中覆盖了你的设置。 - Alex Slipknot
1
抱歉,直到周一我才能访问代码 :) - online Thomas
显示剩余10条评论
8个回答

16

Laravel调试设置位于.env文件中,您可以在其中设置调试选项,如下所示:

APP_DEBUG = true

但是...

Laravel也有一个配置机制,它位于config文件夹中的app.php中,默认情况下为:

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

这告诉 Laravel 使用 .env 的值,并默认为 false,但任何能够访问该文件的人都可以轻松地将其更改为:

告诉 Laravel 使用 .env 值,并默认为false,但是任何能够访问文件的人都可以简单地更改它为:

'debug' => true,

这样你的.env的值就会被 Laravel 忽略。


3
如果你已经阅读了问题并给出了答案,你可能已经知道或推断出这并不像忘记 .env 文件的存在那么简单。此外:.env 文件具有优先权,而配置文件是回退值。 - online Thomas
同意,但我告诉你的只是这样,可能会被有权访问配置文件的人更改,就像我陈述的最后一点一样。 - am05mhz
这种情况并不会发生,即使这样也是如此:.env文件会覆盖app.php。现在您满意了吗? - online Thomas
2
你对 .env 覆盖 app.php 的理解有些错误,它之所以覆盖是因为我陈述的第二点,如果这个点被改变了,那么行为也会随之改变。但如果没有改变,那就自己决定吧,没必要生气。我只是假设你在团队中工作,看来我错了。 - am05mhz
1
我在一个团队中工作。你激怒我的原因是你给出了低质量的答案,并且不惜一切代价为其辩护,说它是一个好答案。 - online Thomas
显示剩余2条评论

14

是的,您可以更改错误报告。实际上,框架提供了一个拦截异常的地方:App\Exceptions\Handler。默认情况下,render 方法会将抛出的异常转换为 HTML 响应。 APP_ENVAPP_DEBUG 值仅会更改此错误响应的呈现方式(基本上是关于异常堆栈跟踪的详细信息是否显示)。

尝试将 render 方法更改为

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);
}

这基本上是关闭报告,然后尝试重新处理请求。 在if语句中,您可以检查任何条件(异常类别、严重程度等)。捕获ErrorException可能已经满足您的需求,但请注意,您可能无法通过这种方式从致命错误中恢复。

无论如何,您应该将其视为“概念验证”……对于非幂等请求,这种“重新处理”的方法不太好。相反,只需创建中间件

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

与之前相同,通过这种方式无法恢复致命错误。但是,你可以将此中间件与之前的异常处理方法相结合,显示自定义错误消息:

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

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

@ThomasMoors,“没起作用”是什么意思?你一直看到“Whoops”消息吗?异常是什么?使用这种方法,我尝试并成功地忽略了一些错误,例如未定义的变量或除以零。 - alepeino
是的,它确实会显示每一个错误。我将编辑我的问题,以解释我从你的答案中尝试的步骤。 - online Thomas
@ThomasMoors 看到了你的编辑。那正是我所拥有的。你确定路由在 web 组中吗?尝试在中间件方法中执行 dd(something);,以确保它正在应用。 - alepeino
是的,我很肯定,你是否已经使用ob_get_clean测试了与我在somecontroller.php中编写的代码相结合的设置?这可能会产生不同的结果。 - online Thomas
@ThomasMoors 等等,你确定失败的不是 require 吗?使用 require '/old_index.php'; 会在文件系统根目录下查找文件。你确定它就在那里吗? - alepeino
显示剩余3条评论

8

我如何进入

app/providers/AppServiceProvider 

在引导函数中。
public function boot()
{
   //add error reporting level
   error_reporting(0);
}

在 Laravel 编译之前,可以通过 "App Service Provider" 在 "boot" 函数中设置错误报告级别。这将应用于所有运行的脚本。您可以打开 "app/providers/AppServiceProvider.php" 文件,在 "boot" 函数中添加 "error_reporting(0/1)" 来设置错误报告级别。


你能进一步解释一下,让其他人也能从中学习吗? - Nico Haase
应用服务提供者在 Laravel 编译之前运行,因此在 boot 函数中,您可以将错误报告设置为任何级别。它将为所有正在运行的脚本设置。您可以打开您的 app/providers/AppServiceProvider.php 文件,在 boot 函数中添加 error_reporting(0/1)。 - danny

4

我猜你的php.ini来自另一个位置。因此,设置仍未应用。尝试找到正确的php.ini位置(可以在phpinfo()中查看信息)。无论如何,你可以在index.php中使用自己的参数来重写这些参数:

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

但正如评论中@Davon所说,这些设置将被Laravel覆盖。因此,上面的代码可以放在您的控制器中,但这将是一种不好的方法。所以您必须找到另一种方法。尝试打印您的.env文件的内容。也许有一些设置是不正确的。


这不会影响Laravel,因为Laravel在应用启动时会重置error_reporting。 - Devon
@Devon 是的,确实。在 HandleExceptions 类的 bootstrap() 方法中找到了它。 - Alex Slipknot

4
如果你看到了“哎呀,出错了”的页面,可以按照@alepeino的答案进行修复: https://dev59.com/01cP5IYBdhLWcg3wJnDp#44862789 但我会将渲染方法更改为:
public function render($request, Exception $exception)
{
    if (!config('app.debug')) {
        error_reporting(0);

        return response('nothing', 500);
    }

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

该render方法(父级)是构建并返回“Whoops”页面的html的方法,因此如果您覆盖它,应该没问题。
要更改调试配置,请检查config / app.php是否具有使用ENV值APP_DEBUG的调试选项,并在您的生产.env中检查它是否设置为false(APP_DEBUG = false)。

2
我已经修复了1000多个这种“漏洞”,哈哈,我的解决方案是$var = $var ?? null - online Thomas
不错,php7的特性。 - Juan Pablo
但我不明白,你还有之前的内容吗?或者你遇到了PHP错误? 要修复PHP错误,难道不应该按照有人提供的php.ini建议进行修复吗?ini_set('display_errors', 0); - Juan Pablo
哦……我不知道如何帮助你……ob_get_clean有用吗?因为看起来你正在尝试取消某些打印输出……所以我猜你是在迁移到Laravel,而不是像以前一样嵌入PHP标记? - Juan Pablo
我建议您通过站在错误(代码)之前并测试哪种error_reporting类型最适合您的问题来调试它。请查看php error-reporting以获取更多选项。在这里,您可以尝试更多的错误配置php errorfunc.configuration。如果您找到了所需的配置(我建议不要过度使用),请将其添加到您的bootstrap/app.php中。祝你好运。 - Juan Pablo
显示剩余6条评论

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

第二行修改了php.ini文件中"display_errors"的值。
编辑:添加更多代码以显示这必须是特定于环境的... $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;

对我来说没有任何影响,它仍然显示“糟糕,似乎出了些问题。” - online Thomas
你能展示一下你想要实现的代码吗?另外,注意这些更改必须是特定于环境的。请查看我的编辑。 - Pila
你可能想考虑使用 config('app.env') 获取环境变量,而不是调用 getenv;如果配置被缓存,调用 getenv 将返回 null 而不是 production、staging 等。 - Chris Forrence
1
这不会影响Laravel,因为Laravel在启动应用程序时重置error_reporting,您需要修改核心框架HandleExceptions.php,就像我的示例一样。 - Devon

1
Laravel强调无错误和警告的代码,因此处理这个问题的最佳方法就是确保您的代码不会产生任何错误、警告或通知。
更新:我不建议使用下面的方法来处理最近版本的Laravel。Laravel现在允许您在非供应商类中更改异常处理:App\Exceptions\Handler,如alepeino的答案所示。中间件也可以是禁用error_reporting的更好解决方案。
为了历史记录而维护此前的答案,但我不建议修改供应商文件。

然而,如果您仍然决定更改这种行为,您需要查看一个名为HandleExceptions.php的文件,通常可以在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');
    }
}

第32行中,error_reporting当前设置为-1。 https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php

当然,通过修改此代码,您将需要防止laravel/framework的更新,或者每次更新都需要验证此文件。

更新此代码后,您需要重新编译您的类:

php artisan clear-compiled; php artisan optimize

我明白,但即使将其更改为E_ERROR,它仍然没有改变任何东西。 - online Thomas
你清除了应用程序缓存和编译后的类吗? - Devon
@ThomasMoors,你需要的是clear-compiled,cache:clear只与缓存对象有关,而不是编译后的类。 - Devon

0

在你的类中的任何函数中都可以使用这个示例方法:

try {
    // ...
} catch (\Exception $e) {
    return redirect()->intended(route('home'));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接