I am studying the Symfony\Component\Debug\Debug.
As far as I know the AppKernel's constructor can accept a second argument to define whether to use the debug modality or not (true/false).
What I actually don't understand is the usage and complementarity of Debug::enable() as it is indicated in the app_dev.php on the official Symfony Github's repository.
For example I tried to throw an Exception on a Controller in order to see the effect and I commented Debug::enable(); within app_dev.php but I always see the error page.
Why am I still seeing error traces in spite of commenting out Debug::enable();?
Short explanation
The Debug::enable() method registers a fallback error handler, which will be called if your application failed to handle an error.
The error page you see when kernel is booted with the $debug flag set to true, is a result of your application error handling (implemented by an exception listener). Set the flag to false to disable stack traces. If you're only after testing you can also disable error pages in development.
The page shown by the Debug component is not as nice as the one provided by the exception listener, but it's nicer than the PHP one.
Detailed explanation
The front controller calls your application kernel:
$kernel = new AppKernel('dev', true);
$response = $kernel->handle(Request::createFromGlobals());
The application kernel boots itself, creates the container and calls the http kernel to handle the request:
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if (false === $this->booted) {
$this->boot();
}
return $this->getHttpKernel()->handle($request, $type, $catch);
}
The http kernel will use the event dispatcher to trigger certain events (kernel.request, kernel.response, kernel.exception etc). When an exception is thrown while handling the request, the http kernel will catch it and trigger the kernel.exception event:
// the following code is simplified to show the point
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
try {
return $this->handleRaw($request, $type);
} catch (\Exception $e) {
return $this->handleException($e, $request, $type);
}
}
private function handleException(\Exception $e, $request, $type)
{
$event = new GetResponseForExceptionEvent($this, $request, $type, $e);
$this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event);
// ...
}
One of the listeners registered by default in the Symfony Standard Edition is the Symfony\Component\HttpKernel\EventListener\ExceptionListener. It's responsible for rendering nice error pages.
However, it will only handle exceptions thrown while handling a request in the http kernel. So if anything goes wrong outside of this call, it won't be handled (have a look at the catch blog in the previous code example).
This is where the Debug component comes in. The Debug::enable() method registers an error handler, an exception handler and a special class loader. You can use it in any PHP project without the http kernel. It is sort of a fallback error handler which will be called if your application failed to handle an error. It has no relation to the $debug constructor argument in the kernel.
Related
I know why this exception is thrown, this is not the problem, but I am not capable to catch this exception.
This exception is thrown in CORE/src/Http/Middleware/CsrfProtectionMiddleware.php line #286:
if (!$cookie || !is_string($cookie)) {
throw new InvalidCsrfTokenException(__d('cake', 'Missing or incorrect CSRF cookie type.'));
}
When I check the long list of the stack in the CakePHP error window it's clear to me I cannot start to modify the CORE files as with the next CakePHP update/upgrade my modifications are lost.
The only script I can modify and should be easily handled is webroot/index.php. It's also mentioned in the call stack in the first position:
Cake\Http\Server->run ROOT/webroot/index.php:50
And here I am stuck. What ever I tried:
try/catch ( \Exception )
try/catch ( \Cake\Http\Exception\InvalidCsrfTokenException )
Using set_exception_handler()
nothing helps, this means, I always get the below error window. In this window you can see on the left the long call stack of scripts which are called until the exception is thrown. And this are even not all scripts. So it's really nested.
My question:
How can I catch this exception in the most top PHP script webroot/index.php - below this script are another 16 scripts called until the exception is thrown. I don't want to modify the CakePHP core files.
I am running CakePHP 4.1.4
You cannot catch that exception in index.php, as it is already being catched by the error handler middleware, which presents you that nice error screen, which however you'd only see in debug mode, in case that is your concern.
Your first chance to catch that exception would be a custom middleware, which you'd have to place between the error handler middleware and the CSRF protection middleware, something along the lines of this:
// in src/Application.php
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$middlewareQueue
->add(new ErrorHandlerMiddleware(Configure::read('Error')))
// ...
->add(function (
\Psr\Http\Message\ServerRequestInterface $request,
\Psr\Http\Server\RequestHandlerInterface $handler
) {
try {
// continue with the next middleware
return $handler->handle($request);
} catch (\Cake\Http\Exception\InvalidCsrfTokenException $exception) {
// handle the catched exception
$response = new \Cake\Http\Response();
return $response->withStringBody('Oh noes, CSRF error!');
}
})
// ...
->add(new CsrfProtectionMiddleware([
'httponly' => true,
]));
return $middlewareQueue;
}
I am working on the development of a centralized authentication web app with Symfony 3.4 and I encounter a problem with the auto-management of exception that Symfony provides. The problem is that I want to catch a ConnectionException raised by the LDAP component when the connexion to the Active Directory fails. The objective is to use this exception to notice when it fails and to redirect to a specific page. But at the very moment when the Exception is raised by the LDAP component, Symfony notice a kernel.exception event and then render a debug exception page instead of letting the program go and catch the exception.
How could I do to fix that problem and be sure that the Exception is caught and use by my code and not automatically by Symfony ?
I join you the sample of code and the page rendered:
<?php
namespace App\Utils;
use App\Entity\User;
use Symfony\Component\Ldap\Ldap;
use Symfony\Component\Ldap\Exception\ConnectionException;
class ActiveDirectoryStuff
{
private $domain = 'myDomain';
private $ldapString = 'ldap://';
public function __construct()
{}
public function connection($username, $password)
{
try {
$dn = $username.'#'.$this->domain;
$ldap = Ldap::create('ext_ldap', array(
'connection_string' => $this->ldapString . $this->domain,
));
$ldap->bind($dn, $password); //where the ConnectionException is raised
return $ldap;
} catch (\ConnectionException $ce) {
throw $ce;
}
}
}
Image of the Page Rendered Automatically
You're catching the exception, doing nothing then throwing, this is the same as having no try catch at this level of code
Based on what you said use your framework to redirect to a specific page from within the catch and any other logic you want to run when this error happens, then remove throw $ce; that will stop the default error handler from running which I assume is Symfony's
I read about kernel events in Symfony documentation : http://symfony.com/doc/current/components/http_kernel.html
It's written : As you've seen, you can create and attach event listeners to any of the events dispatched during the HttpKernel::handle() cycle
No problem to do that, I can create a custom exception listener and listen the kernel events.
But how can I catch potential errors during the boot sequence (because no listeners are called):
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if (false === $this->booted) {
$this->boot(); // Error can be thrown
}
return $this->getHttpKernel()->handle($request, $type, $catch);
}
I can have this kind of errors, if I provide a wrong access to database (DriverException) for example.
In dev mode, it's ok because I have a default error handler with DebugBundle but in production it's a white screen.
How can I handle that properly ?
No need to catch errors at the booting stage within the application itself.
In general application can not intercept all possible errors. For example, out of memory. Or the PHP may be crashed by segfault and neither try/catch nor register_shutdown_function won't help.
Most common solution is error handling by the web server (Nginx, Apache, etc). If upstream falls then web server gets 500 response and nicely handles it by showing user-friendly message.
I am trying to implement exception handling in my application. For this Laravel framework has its own mechanism to handle the exception using report and render method. But to implement exception I need to track the source from where the exception has been raised e.g. specific page, route etc. For this I need to pass the url to report and render method but unable to do so. What needs to be done in order to implement this in below report and render function.
public function report(Exception $e)
{
parent::report($e);
}
public function render($request, Exception $e)
{
/* Token mismatch Exception handler start */
if ($e instanceof \Illuminate\Session\TokenMismatchException) {
return response()->view('errors.sessionExpire', [], 500);
}
/* Token mismatch Exception handler start */
return parent::render($request, $e);
}
As you can see from your own example, you have an instance of Request in the argument list. And Request has all request-specific details like current route, URL and so on.
$request->url(); // Current request URL
$request->fullUrl(); // With query parameters
$request->route(); // Get the route closure for this request path
You can also create your own exception classes that accept as many parameters as you wish!
And the less comfortable way already mentioned – you could go through the exception trace.
You need to use Exception::getTrace
var_dump($e->getTrace());
above line will give you all details regarding exception.
public function report(Exception $e){
echo '<pre>'; // add this line
print_r($e->getTrace()); // add this line
parent::report($e);
}
I am using Symfony 2.4 and am trying to create a more powerful exceptions handler that, on certain PDO / Doctrine exceptions, changes the status code of the response from 500 to 503 to display a different custom error message than our standard (in other words, it returns the error503.html.twig template rather than error500.html.twig). So far, I have created a custom Exceptions controller that extends the TwigBundle ExceptionController, I have changed the Twig exception parameter in config.yml, and I am able to catch any and all exceptions that are thrown once Symfony calls handle(...) in HttpKernel.php:185 (so it's really the second time that handle is called -- this time being on the HttpKernel rather than the AppKernel). I'll refrain from posting all that code, and instead direct the reader here to learn more about my method if they are unfamiliar. All of that code is working just fine -- I am able to modify any applications that are thrown within my application, so you can assume that I'm using the aforementioned approach properly.
The issue I am running into is that in addition to catching exceptions that are thrown within Symfony, I also want to also be able to catch exceptions that are thrown before the HttpKernel's handle method is called (an example being a PDO Access Denied exception that is thrown from improper database credentials). To give you a more specific rundown, in app_dev.php, you have:
$response = $kernel->handle($request);
which calls:
/**
* {#inheritdoc}
*
* #api
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if (false === $this->booted) {
$this->boot();
}
return $this->getHttpKernel()->handle($request, $type, $catch);
}
Now, if an exception gets thrown in $this->boot(), it doesn't look like it gets caught anywhere, and because of that, I can't see any way of gracefully handling said exception in Symfony. It's only if the exception gets thrown within the try / catch block contained in $this->getHttpKernel()->handle($request, $type, $catch) that it will be caught and gracefully handled using Symfony code. Am I wrong about that? Does anyone know of an approach to handling exceptions that are thrown in this context that utilizes Symfony? My apologies in advance if this has already been answered elsewhere.
I ran into a similar problem, I didn't see a neat way around this but was able to get nice error pages for my specific problem simply by generating a Response object and sending that. I placed the following in some code which was called by boot()
try {
someExceptionFunction();
} catch (Exception $e) {
$response = new Response('<html><body>'.$e->getMessage().'</body></html>');
$response->send();
exit;
}
You could easily add some more logic to the catch block, catching different exceptions. It's not as clean/abstract as it could be, but since the entire framework fails to boot I don't know of any option you could use it to parse an error page.
Hope this helps