Exclude all 404 errors from monolog - symfony

Currently I have monolog sending me emails when there are errors. I found that 404 errors were just polluting my email and my provider ended up suspending my account due to the number of emails I sent myself. I decided to exclude all 404 errors because all of them were due to bots looking for vulnerabilities and not from clients.
Exclude code:
excluded_404s:
- ^/
The problem I'm seeing now is that symfony still logs 404 errors if the bots use http methods other than GET. My email is now polluted with entries like
HEAD :80/phpmyAdmin/
How can I exclude all 404 errors including those using http methods other than GET?
Edit:
Oh boy. Beginner mistake here. It seems that after my last deploy of the configuration I did not clear the prod cache and I'm figuring out that the config is cached. I'm using deployer to deploy my code updates but I guess the clear cache command is missing from it.

Symfony 4.1. upwords can can be configured to ignore HTTP Codes:
config/packages/monolog.yaml
monolog:
handlers:
main:
# ...
type: 'fingers_crossed'
excluded_http_codes: [404]
https://symfony.com/blog/new-in-symfony-4-1-ignore-specific-http-codes-from-logs

I know it is an old question, but it is the 1st one when googling.
Meanwhile I found a solution for symfony 3.4, if you need to exclude all 404 errors from your logs you can create an ExceptionListener and check if the exception is a NotFoundHttpException.
If it is the case, then just return a response so that the event is stopped and the logger will not handle the exception.
src/AppBundle/EventListener/ExceptionListener.php
namespace AppBundle\EventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ExceptionListener
{
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
if (! $exception instanceof NotFoundHttpException) {
return;
}
$response = new Response($exception->getMessage(), $exception->getStatusCode());
// returning a response stop the event propagation
$event->setResponse($response);
}
}
src/AppBundle/Resources/config/services.yml
services:
app.exception.listener:
class: AppBundle\EventListener\ExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception }

In Symfony 4/5 you can do:
<?php
declare(strict_types=1);
namespace App\EventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ExceptionListener
{
public function onKernelException(ExceptionEvent $event)
{
$exception = $event->getThrowable();
if ($exception instanceof NotFoundHttpException) {
$response = new Response($exception->getMessage(), $exception->getStatusCode());
$event->setResponse($response);
}
return;
}
}
and
App\EventListener\ExceptionListener:
tags:
- { name: kernel.event_listener, event: kernel.exception }

Related

Symfony: redirecting to homepage after encountering an error

I've recently started learning Symfony, and I've been trying to make an app that will redirect user to the homepage after encountering an error (For the sake of the question, it can be error 404) However, I had problems with finding a way to do so.
Before, I used TwigErrorRenderer as described in Symfony documentation to handle my errors, but it only explains how to redirect to new error pages created by myself. Could somebody help me with this issue?
It is generally not a good idea to do this, because you want to tell the user that their request was not processed due to an error, or that they accessed non-existing page.
But if you really want to, you can achieve it with this Event Listener.
// src/EventListener/ExceptionListener.php
<?php
declare(strict_types=1);
namespace App\EventListener;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\Routing\RouterInterface;
final class ExceptionListener
{
private RouterInterface $router;
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
public function onKernelException(ExceptionEvent $event): void
{
// You should log the exception via Logger
// You can access exception object via $event->getThrowable();
$homepageRoute = $this->router->generate('homepage', [], RouterInterface::ABSOLUTE_URL);
$response = new RedirectResponse($homepageRoute);
$event->setResponse($response);
}
}
You also need to register the Event Listener in your services.yaml.
services:
App\EventListener\ExceptionListener:
tags:
- { name: kernel.event_listener, event: kernel.exception }
Please note the following:
The Event Listener assumes that your Homepage route is called homepage;
you really should log the exception or you will lose logs about all of them;
as stated at the top of this answer, this is not a good approach to deal with exceptions.

Symfony 5 custom 404 page

I'm trying to create a custom 404 page for a Symfony 5 project that must:
Output a simple JSON-encoded string, like "Not found".
Said string must be read from a translation resource.
Have an additional Content-Type: application/json header.
There is a section in the Symfony docs, that attempts to explain how this can be achieved, but the information seems incomplete/incorrect, apparently being written for the 4.X version, even pointing to non-existent source files on GitHub.
I have managed to create an error controller, but it swallows all errors:
# config/packages/framework.yaml
framework:
error_controller: App\Controller\ErrorController::errorHandler
// src/Controller/ErrorController.php
class ErrorController extends AbstractController
{
public function errorHandler(TranslatorInterface $translator) : JsonResponse
{
return new JsonResponse($translator->trans('not_found'));
}
}
The problem is that this results in any error (including internal ones) returning a 404 page.
How can I make this controller/method handle only 404 errors and leave everything else to be handled as before by the framework itself?
For anyone else that is looking for a solution to a JSON 404 page for a Symfony application:
I was looking for a way to use a controller to handle specific error cases as it seemed the easiest option on the surface, but this does not seem to be possible, or at least I have not figured out how.
In the end, I reached a solution using events and event listeners:
Configuration:
# config/services.yaml
services:
...
# This listener handles only 404 errors in PROD mode
App\EventListener\ExceptionListener:
tags:
- { name: kernel.event_listener, event: kernel.exception }
Event listener:
// src/EventListener/ExceptionListener.php
class ExceptionListener {
public function onKernelException(ExceptionEvent $event) : void
{
if (
$_ENV['APP_ENV'] != 'prod'
|| !$event->isMasterRequest()
|| !$event->getThrowable() instanceof NotFoundHttpException
) {
return;
}
// Send a not found in JSON format
$event->setResponse(new JsonResponse($this->translator->trans('not_found')));
}
}

How to set status code from service layer in Symfony 2?

I have a service that is helping me to validate some forms. I want to set HTTP status code from inside of it when it finds that form is actually invalid.
Is it OK to do so? How do I do it? Thanks!
The way I would do that (probably there's lot more solutions) is throwing some (custom) exception in your service in case your form is invalid.
Then I would create an exception listener which would listen on kernel exception event. Configuration of such listener would look something like this (services.yml)
kernel.listener.your_listener:
class: Acme\Your\Namespace\YourExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onException }
And than your onException method in YourExceptionListener class:
public function onException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
if ($exception instanceof YourCustomExceptionInterface) {
$response = new Response('', 400);
$event->setResponse($response);
}
}
This way you get nicely decoupled stuff, and your form validation service is independent of response.

Redirect to different action depending on User Status

I'm working with Symfony 2.1. I want to setup a redirect routine depending on User is logged in or not. The way I check it is $User->isLoggedIn() where User is a service.
I want to do this before a controller executes. I have few other things happening just before Controller executes. I use event: kernel.controller of kernel.event_listener to do those things. But I realized that I can not redirect to a URL using this event.
I understand I need to use event: kernel.request of kernel.event_listener to be able to redirect to a URL.
Problem.
I use the following logic to figure out whether I need to redirect or not.
if (!$controller[0] instanceof NoLogInNeededInterface) {
if (!$User->isLoggedIn()) {
//redirect here
}
}
So, in the kernel.request event, $controler[0] is not available. In the kernel.controller event, response can't be set (will be ignored).
Has anyone got same problem and solved. Or is there any better way of doing, what I'm trying to do?
I realized that what I wanted could be achieved by using kernel.exception event of kernel.event_listner.
So in Services:
my.service:
class: MyBundle\EventListner\ExceptionListner
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
arguments: [ %logoutUrl% ]
Then in the Class itself:
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
class ExceptionListner
{
protected $_url;
public function __construct($url)
{
$this->_url = $url;
}
public function onKernelException(GetResponseForExceptionEvent $event) {
$exception = $event->getException();
//dont necessarily need this condition
if ($exception instanceof RedirectException) {
$response = new RedirectResponse($this->_url);
$event->setResponse($response);
}
}
}
I'm still up for suggestion, if this is or is not better approach.
Hope this will help someone who is struggling as well.
P

Is there a symfony2 event/handler for session timeout a.k.a not logged in

Im using the FOSRestBundle to make ajax json calls within a Firewall. Everything seems to be working great, with the exception that Im not able to to handle when a session timeout has occurred. Right now it's redirecting to login_check in this scenario, returning html rather than json to the client.
Im aware, and use success_handler and failure_handler's within my app. I cannot find a built in handler for dealing with authorisation failures, such as session timeout.
Is there something within the FOSRestBundle that can help address this, or something Im not seeing within Symfony2?
Yes, Symfony offers the possibility to handle exceptions. You have to create an event listener which observes the kernel.exception event with a high priority. Create an event handler like this:
<?php
namespace Acme\Bundle\MyBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
class AjaxAuthenticationListener
{
public function onKernelException(GetResponseForExceptionEvent $event)
{
$request = $event->getRequest();
$format = $request->getRequestFormat();
$exception = $event->getException();
if ('json' !== $format || (!$exception instanceof AuthenticationException && !$exception instanceof AccessDeniedException)) {
return;
}
$response = new JsonResponse($this->translator->trans($exception->getMessage()), $exception->getCode());
$event->setResponse($response);
$event->stopPropagation();
}
}
Now you have to register your event handler in one of your service.yml's, like this:
kernel.listener.ajax_authentication_listener:
class: Acme\Bundle\MyBundle\EventListener\AjaxAuthenticationListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException, priority: 250 }
Note the priority parameter, used to tell Symfony to execute the handler before its own handlers, which have a lower priority.
And on your frontend you can register an event handler for jQuery, which reloads the page on such an error.
$(document).ready(function() {
$(document).ajaxError(function (event, jqXHR) {
if (403 === jqXHR.status) {
window.location.reload();
}
});
});
See this gist for reference.
I'm not sure if there's anything explicitly inside the FOSRest bundle, but Symfony2 itself is able to handle session timeouts.
Have you tried looking here? http://symfony.com/doc/current/components/http_foundation/session_configuration.html

Resources