Symfony 4:在非生产环境中隐藏调试堆栈跟踪
Symfony 4: hide debug stacktrace in non prod environment
我有 2 个生产环境,分别是 prod1 和 prod2 它们在数据库和业务逻辑等配置上有所不同。基本上是一种主从关系。
我想像在正常生产环境中一样对用户隐藏调试堆栈跟踪。这应该可以通过在 .env 文件中设置 APP_DEBUG=0 来实现。
APP_DEBUG=0
但我得到了调试屏幕:
但奇怪的是,这不起作用,只有当我将 APP_ENV 设置为 prod 时,才会显示调试堆栈跟踪。
我的 .env 文件如下所示:
APP_ENV=prod1
APP_DEBUG=0
APP_SECRET=xxxxxxxaxaxaxa
我检查了public/index.php中的参数,并且有正确的传输:
$env = 'prod1';
$debug = false;
$kernel = new Kernel($env, $debug);
我正在使用 Symfony 4.2.2 symfony/env。
任何人都可以重现此行为吗?这可能是 Symfony 或 symfony/env 错误?
您的配置正确。
这很可能是缓存问题:尝试 运行 php bin/console cache:clear
。
我有几个用 Symfony 4 编写的项目。为了重现您的错误,我将我的一个项目更新为 Symfony 4.2.2。所有 Symfony 依赖项:
symfony/browser-kit v4.2.2 Symfony BrowserKit Component
symfony/cache v4.2.2 Symfony Cache component with PSR-6, PSR-16, and tags
symfony/class-loader v3.4.21 Symfony ClassLoader Component
symfony/config v4.2.2 Symfony Config Component
symfony/console v4.2.2 Symfony Console Component
symfony/contracts v1.0.2 A set of abstractions extracted out of the Symfony components
symfony/css-selector v4.2.2 Symfony CssSelector Component
symfony/debug v4.2.2 Symfony Debug Component
symfony/dependency-injection v4.2.2 Symfony DependencyInjection Component
symfony/doctrine-bridge v4.2.2 Symfony Doctrine Bridge
symfony/dom-crawler v4.2.2 Symfony DomCrawler Component
symfony/dotenv v4.2.2 Registers environment variables from a .env file
symfony/event-dispatcher v4.2.2 Symfony EventDispatcher Component
symfony/filesystem v4.2.2 Symfony Filesystem Component
symfony/finder v4.2.2 Symfony Finder Component
symfony/flex v1.1.8 Composer plugin for Symfony
symfony/form v4.2.2 Symfony Form Component
symfony/framework-bundle v4.2.2 Symfony FrameworkBundle
symfony/http-foundation v4.2.2 Symfony HttpFoundation Component
symfony/http-kernel v4.2.2 Symfony HttpKernel Component
symfony/inflector v4.2.2 Symfony Inflector Component
symfony/intl v4.2.2 A PHP replacement layer for the C intl extension that includes additional data from the ICU library.
symfony/maker-bundle v1.11.3 Symfony Maker helps you create empty commands, controllers, form classes, tests and more so you can forget about writing boilerplate code.
symfony/monolog-bridge v4.2.2 Symfony Monolog Bridge
symfony/monolog-bundle v3.3.1 Symfony MonologBundle
symfony/options-resolver v4.2.2 Symfony OptionsResolver Component
symfony/orm-pack v1.0.6 A pack for the Doctrine ORM
symfony/polyfill-intl-icu v1.10.0 Symfony polyfill for intl's ICU-related data and classes
symfony/polyfill-mbstring v1.10.0 Symfony polyfill for the Mbstring extension
symfony/polyfill-php72 v1.10.0 Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions
symfony/process v4.2.2 Symfony Process Component
symfony/profiler-pack v1.0.4 A pack for the Symfony web profiler
symfony/property-access v4.2.2 Symfony PropertyAccess Component
symfony/routing v4.2.2 Symfony Routing Component
symfony/security-bundle v4.2.2 Symfony SecurityBundle
symfony/security-core v4.2.2 Symfony Security Component - Core Library
symfony/security-csrf v4.2.2 Symfony Security Component - CSRF Library
symfony/security-guard v4.2.2 Symfony Security Component - Guard
symfony/security-http v4.2.2 Symfony Security Component - HTTP Integration
symfony/stopwatch v4.2.2 Symfony Stopwatch Component
symfony/swiftmailer-bundle v3.2.5 Symfony SwiftmailerBundle
symfony/templating v4.2.2 Symfony Templating Component
symfony/translation v4.2.2 Symfony Translation Component
symfony/twig-bridge v4.2.2 Symfony Twig Bridge
symfony/twig-bundle v4.2.2 Symfony TwigBundle
symfony/validator v4.2.2 Symfony Validator Component
symfony/var-dumper v4.2.2 Symfony mechanism for exploring and dumping PHP variables
symfony/var-exporter v4.2.2 A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code
symfony/web-profiler-bundle v4.2.2 Symfony WebProfilerBundle
symfony/web-server-bundle v4.2.2 Symfony WebServerBundle
symfony/yaml v4.2.2 Symfony Yaml Component
为清楚起见 - 我在 生产 环境中 运行 宁这个项目,我使用 Apache2 来完成这项工作。
在我的项目中,我只有一个 .env
文件,没有任何带有环境变量的 *.local
文件。该文件如下所示:
APP_ENV=prod
APP_SECRET=928374923784mysecretkey92837498273
使用这些设置我看不到调试页面 - 正确的行为
APP_ENV=prod
APP_DEBUG=1
APP_SECRET=928374923784mysecretkey92837498273
如果我添加值为 1 的变量 APP_DEBUG - 显示调试页面 - 正确行为
我添加了一个名为 prod1
:
的自定义环境
APP_ENV=prod1
APP_SECRET=928374923784mysecretkey92837498273
现在调试页面默认可见 - 正确的行为
我添加了APP_DEBUG=0:
APP_ENV=prod1
APP_DEBUG=0
APP_SECRET=928374923784mysecretkey92837498273
并且没有出现调试页面 - 正确的行为
如您所见,我无法重现此错误。在 Symfony 4.2.2 中,一切似乎都正常工作。在您的项目或 Web 服务器配置中搜索错误,因为这是问题的原因。我认为您在某处覆盖了 APP_DEBUG 变量。也许在 Apache/Nginx 虚拟主机配置中:
正如Siavas所写,它也可以是一个缓存。尝试手动删除var/log
目录和运行composer install
遗憾的是我没有更多的想法,如果项目不是严格保密的,你可以分享到github,也许我可以帮助你更多
问题是,我在我的项目中配置错误 ExceptionController:
- FOSRestBundle 有自己的 ExceptionController 用于显示 json/xml 异常
你在你的 config/fos_rest.yaml:
中配置它
fos_rest
exception:
enabled: true
exception_controller: 'App\Controller\ExceptionController::handleExceptionAction'
- Twig 是 symfony 的默认异常控制器
你在你的 config/twig.yaml:
中配置它
twig:
debug: '%kernel.debug%'
exception_controller: App\Controller\ExceptionController::showException
使用的 Exception Handler 是 fos_rest,我在 services.yaml 中配置错误:
App\Controller\ExceptionController:
- '@fos_rest.view_handler.default'
- '@fos_rest.exception.messages_map'
- true <------ this should be '%kernel.debug%'
- '@templating.engine.twig'
- '@logger'
问题是,这里的第三个参数应该是%kernel.debug%。
最后,我最终得到了 2 个 ExceptionControllers,一个用于 API 和 json 格式的 Response,一个用于 Sonata Backend,标准的 Twig 异常控制器。唯一的解决方案是,将请求从一个控制器转发到另一个控制器:
<?php
namespace App\Controller;
use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController as TwigExceptionController;
class ExceptionController
{
protected $debug;
/**
* @var TwigExceptionController
*/
protected $twigExceptionController;
/**
* @param bool $debug
* @param TwigExceptionController $twigExceptionController
*/
public function __construct(
bool $debug,
TwigExceptionController $twigExceptionController
)
{
$this->debug = $debug;
$this->twigExceptionController = $twigExceptionController;
}
/**
* Converts an Exception to a Response.
*
* @param Request $request
* @param FlattenException $exception
* @param LoggerInterface $logger
*
* @return Response
*/
public function handleExceptionAction(Request $request, FlattenException $exception, LoggerInterface $logger): Response
{
if (!stristr( strtolower($request->getUri()), '/api/')) {
return $this->twigExceptionController->showAction($request, $exception, $logger);
}
$currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
if ($currentContent) {
$logger->error('current content: '.$currentContent);
}
$code = $this->getStatusCode($exception);
$response = new JsonResponse();
$response->setStatusCode($code);
$response->setData([
'message' => $exception->getMessage(),
'code' => $code
]);
return $response;
}
/**
* Determines the status code to use for the response.
*
* @param \Exception $exception
*
* @return int
*/
protected function getStatusCode($exception): int
{
if (method_exists($exception, 'getCode') && $exception->getCode() > 0) {
return $exception->getCode();
}
if (method_exists($exception, 'getStatusCode') && $exception->getStatusCode() > 0) {
return $exception->getStatusCode();
}
return 500;
}
/**
* Gets and cleans any content that was already outputted.
*
* This code comes from Symfony and should be synchronized on a regular basis
* see src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php
*
* @return string
*/
private function getAndCleanOutputBuffering($startObLevel)
{
if (ob_get_level() <= $startObLevel) {
return '';
}
Response::closeOutputBuffers($startObLevel + 1, true);
return ob_get_clean();
}
}
我有 2 个生产环境,分别是 prod1 和 prod2 它们在数据库和业务逻辑等配置上有所不同。基本上是一种主从关系。
我想像在正常生产环境中一样对用户隐藏调试堆栈跟踪。这应该可以通过在 .env 文件中设置 APP_DEBUG=0 来实现。
APP_DEBUG=0
但我得到了调试屏幕:
但奇怪的是,这不起作用,只有当我将 APP_ENV 设置为 prod 时,才会显示调试堆栈跟踪。
我的 .env 文件如下所示:
APP_ENV=prod1
APP_DEBUG=0
APP_SECRET=xxxxxxxaxaxaxa
我检查了public/index.php中的参数,并且有正确的传输:
$env = 'prod1';
$debug = false;
$kernel = new Kernel($env, $debug);
我正在使用 Symfony 4.2.2 symfony/env。
任何人都可以重现此行为吗?这可能是 Symfony 或 symfony/env 错误?
您的配置正确。
这很可能是缓存问题:尝试 运行 php bin/console cache:clear
。
我有几个用 Symfony 4 编写的项目。为了重现您的错误,我将我的一个项目更新为 Symfony 4.2.2。所有 Symfony 依赖项:
symfony/browser-kit v4.2.2 Symfony BrowserKit Component
symfony/cache v4.2.2 Symfony Cache component with PSR-6, PSR-16, and tags
symfony/class-loader v3.4.21 Symfony ClassLoader Component
symfony/config v4.2.2 Symfony Config Component
symfony/console v4.2.2 Symfony Console Component
symfony/contracts v1.0.2 A set of abstractions extracted out of the Symfony components
symfony/css-selector v4.2.2 Symfony CssSelector Component
symfony/debug v4.2.2 Symfony Debug Component
symfony/dependency-injection v4.2.2 Symfony DependencyInjection Component
symfony/doctrine-bridge v4.2.2 Symfony Doctrine Bridge
symfony/dom-crawler v4.2.2 Symfony DomCrawler Component
symfony/dotenv v4.2.2 Registers environment variables from a .env file
symfony/event-dispatcher v4.2.2 Symfony EventDispatcher Component
symfony/filesystem v4.2.2 Symfony Filesystem Component
symfony/finder v4.2.2 Symfony Finder Component
symfony/flex v1.1.8 Composer plugin for Symfony
symfony/form v4.2.2 Symfony Form Component
symfony/framework-bundle v4.2.2 Symfony FrameworkBundle
symfony/http-foundation v4.2.2 Symfony HttpFoundation Component
symfony/http-kernel v4.2.2 Symfony HttpKernel Component
symfony/inflector v4.2.2 Symfony Inflector Component
symfony/intl v4.2.2 A PHP replacement layer for the C intl extension that includes additional data from the ICU library.
symfony/maker-bundle v1.11.3 Symfony Maker helps you create empty commands, controllers, form classes, tests and more so you can forget about writing boilerplate code.
symfony/monolog-bridge v4.2.2 Symfony Monolog Bridge
symfony/monolog-bundle v3.3.1 Symfony MonologBundle
symfony/options-resolver v4.2.2 Symfony OptionsResolver Component
symfony/orm-pack v1.0.6 A pack for the Doctrine ORM
symfony/polyfill-intl-icu v1.10.0 Symfony polyfill for intl's ICU-related data and classes
symfony/polyfill-mbstring v1.10.0 Symfony polyfill for the Mbstring extension
symfony/polyfill-php72 v1.10.0 Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions
symfony/process v4.2.2 Symfony Process Component
symfony/profiler-pack v1.0.4 A pack for the Symfony web profiler
symfony/property-access v4.2.2 Symfony PropertyAccess Component
symfony/routing v4.2.2 Symfony Routing Component
symfony/security-bundle v4.2.2 Symfony SecurityBundle
symfony/security-core v4.2.2 Symfony Security Component - Core Library
symfony/security-csrf v4.2.2 Symfony Security Component - CSRF Library
symfony/security-guard v4.2.2 Symfony Security Component - Guard
symfony/security-http v4.2.2 Symfony Security Component - HTTP Integration
symfony/stopwatch v4.2.2 Symfony Stopwatch Component
symfony/swiftmailer-bundle v3.2.5 Symfony SwiftmailerBundle
symfony/templating v4.2.2 Symfony Templating Component
symfony/translation v4.2.2 Symfony Translation Component
symfony/twig-bridge v4.2.2 Symfony Twig Bridge
symfony/twig-bundle v4.2.2 Symfony TwigBundle
symfony/validator v4.2.2 Symfony Validator Component
symfony/var-dumper v4.2.2 Symfony mechanism for exploring and dumping PHP variables
symfony/var-exporter v4.2.2 A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code
symfony/web-profiler-bundle v4.2.2 Symfony WebProfilerBundle
symfony/web-server-bundle v4.2.2 Symfony WebServerBundle
symfony/yaml v4.2.2 Symfony Yaml Component
为清楚起见 - 我在 生产 环境中 运行 宁这个项目,我使用 Apache2 来完成这项工作。
在我的项目中,我只有一个 .env
文件,没有任何带有环境变量的 *.local
文件。该文件如下所示:
APP_ENV=prod
APP_SECRET=928374923784mysecretkey92837498273
使用这些设置我看不到调试页面 - 正确的行为
APP_ENV=prod
APP_DEBUG=1
APP_SECRET=928374923784mysecretkey92837498273
如果我添加值为 1 的变量 APP_DEBUG - 显示调试页面 - 正确行为
我添加了一个名为 prod1
:
APP_ENV=prod1
APP_SECRET=928374923784mysecretkey92837498273
现在调试页面默认可见 - 正确的行为
我添加了APP_DEBUG=0:
APP_ENV=prod1
APP_DEBUG=0
APP_SECRET=928374923784mysecretkey92837498273
并且没有出现调试页面 - 正确的行为
如您所见,我无法重现此错误。在 Symfony 4.2.2 中,一切似乎都正常工作。在您的项目或 Web 服务器配置中搜索错误,因为这是问题的原因。我认为您在某处覆盖了 APP_DEBUG 变量。也许在 Apache/Nginx 虚拟主机配置中:
正如Siavas所写,它也可以是一个缓存。尝试手动删除var/log
目录和运行composer install
遗憾的是我没有更多的想法,如果项目不是严格保密的,你可以分享到github,也许我可以帮助你更多
问题是,我在我的项目中配置错误 ExceptionController:
- FOSRestBundle 有自己的 ExceptionController 用于显示 json/xml 异常
你在你的 config/fos_rest.yaml:
中配置它fos_rest
exception:
enabled: true
exception_controller: 'App\Controller\ExceptionController::handleExceptionAction'
- Twig 是 symfony 的默认异常控制器
你在你的 config/twig.yaml:
中配置它twig:
debug: '%kernel.debug%'
exception_controller: App\Controller\ExceptionController::showException
使用的 Exception Handler 是 fos_rest,我在 services.yaml 中配置错误:
App\Controller\ExceptionController:
- '@fos_rest.view_handler.default'
- '@fos_rest.exception.messages_map'
- true <------ this should be '%kernel.debug%'
- '@templating.engine.twig'
- '@logger'
问题是,这里的第三个参数应该是%kernel.debug%。
最后,我最终得到了 2 个 ExceptionControllers,一个用于 API 和 json 格式的 Response,一个用于 Sonata Backend,标准的 Twig 异常控制器。唯一的解决方案是,将请求从一个控制器转发到另一个控制器:
<?php
namespace App\Controller;
use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController as TwigExceptionController;
class ExceptionController
{
protected $debug;
/**
* @var TwigExceptionController
*/
protected $twigExceptionController;
/**
* @param bool $debug
* @param TwigExceptionController $twigExceptionController
*/
public function __construct(
bool $debug,
TwigExceptionController $twigExceptionController
)
{
$this->debug = $debug;
$this->twigExceptionController = $twigExceptionController;
}
/**
* Converts an Exception to a Response.
*
* @param Request $request
* @param FlattenException $exception
* @param LoggerInterface $logger
*
* @return Response
*/
public function handleExceptionAction(Request $request, FlattenException $exception, LoggerInterface $logger): Response
{
if (!stristr( strtolower($request->getUri()), '/api/')) {
return $this->twigExceptionController->showAction($request, $exception, $logger);
}
$currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
if ($currentContent) {
$logger->error('current content: '.$currentContent);
}
$code = $this->getStatusCode($exception);
$response = new JsonResponse();
$response->setStatusCode($code);
$response->setData([
'message' => $exception->getMessage(),
'code' => $code
]);
return $response;
}
/**
* Determines the status code to use for the response.
*
* @param \Exception $exception
*
* @return int
*/
protected function getStatusCode($exception): int
{
if (method_exists($exception, 'getCode') && $exception->getCode() > 0) {
return $exception->getCode();
}
if (method_exists($exception, 'getStatusCode') && $exception->getStatusCode() > 0) {
return $exception->getStatusCode();
}
return 500;
}
/**
* Gets and cleans any content that was already outputted.
*
* This code comes from Symfony and should be synchronized on a regular basis
* see src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php
*
* @return string
*/
private function getAndCleanOutputBuffering($startObLevel)
{
if (ob_get_level() <= $startObLevel) {
return '';
}
Response::closeOutputBuffers($startObLevel + 1, true);
return ob_get_clean();
}
}