I have the following problem. Currently I work on a project where I should develop a new module. The problem is, that the main module just uses the onBootstrap function to validate the request (every) and if it not on the route of the main module, it returns a notfound 404 error page.
Now all my new routes on my new module just dont work cause onBootstrap() just kicks in before. Is there a way to check in the main module if the route just hit and if every module dont find routes to get the 404 error page?
Im pretty new to this framework D=.
example:
MainModule.php
class Module
{
...
onBootstrap()
{
$request = ...->getRequest();
if($request->isNotValid()) {
return new 404Response();
}
}
...
}
class SideModule
{
...
// Never triggered
public function indexAction()
{
print("Hello World");
}
...
}
You should depend on a 404 resolver later in the code, not during bootstrap of your first module. I'd suggest getting rid of the code that returns the 404 response in MainModule onBootstrap() method and instead depend on Laminas\Mvc\View\Http\RouteNotFoundStrategy that's automatically injected during Application bootstrap (see Laminas\Mvc\Application::bootstrap(), the part where defaultListeners are attached. ViewManager is one of the defaultListeners, and ViewManager on its behalf attaches HttpRouteNotFoundStrategy in the Laminas\Mvc\View\Http\ViewManager::bootstrap() method).
RouteNotFoundStrategy not only will set a 404 status code to your MvcEvent->getResponse() object, but will also render a not-found page which you can
customize any way you like. See https://docs.laminas.dev/laminas-mvc/services/ for more information.
Related
We have introduced the Twig template engine to CodeIgniter 4.
The template folder has been changed directly under the project folder(/templates).
The 404 error page has been replaced.
$routes->set404Override('App\Controllers\Template::notFound')
App\Controllers\Template
//...
class Template extends BaseController
{
// ...
public function notFound ()
{
return $this->twig->display('errors/custom404'); // <- /templates/errors/custom404.twig
}
And in production, other errors are reading the production.php file (/app/Views/errors/html/production.php).
I also want to overwrite the exception handling page, what should I do?
Specifically, I want to load the production.twig file (/templates/errors/production.twig) instead of the production.php file (/app/Views/errors/html/production.php).
Is there a way to override the exception page like a 404 page controller?
vendor/codeigniter4/framework/system/Debug/Exceptions.php
I can see that production.php is hardcoded in the method determineView, is it possible to override this method?
And is it okay to overwrite?
I created customs Twig templates for http error display to keep the site design unified by extending my base layout. (I want to keep my navigation menu and display the error, unlike the regular error messages)
It's working as expected but for the 404.
In the navigation menu of my base layout, I have a lot of is_granted('SOME_ROLES') to display the availables sections of the site depending of user's rights. When a 404 is thrown, the navigation menu is displayed as if the user is disconnected : {% if is_granted("IS_AUTHENTICATED_REMEMBERED") %} being false.
After some searches, I found that the router is executed before the firewall. Since no route is found when a 404 is thrown, the firewall isn't executed and the rights aren't send to the template.
The only workaround I found (source from 2014) is to add at the very bottom of the routes.yaml file this route definition :
pageNotFound:
path: /{path}
defaults:
_controller: App\Exception\PageNotFound::pageNotFound
Since every other routes hasn't match, this one should be the not found.
The controller :
<?php
namespace App\Exception;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class PageNotFound
{
public function pageNotFound()
{
return (new NotFoundHttpException());
}
}
Because a controller is executed, the firewall is executed and the 404 error page is shown as I expected (hooray !).
My question is : Is there any proper way to fix that issue instead of that workaround?
We had a similar issue.
We wanted to have access to an authentication token in error pages.
In the scenario where part of the website is behind a firewall, say example.com/supersecretarea/, we wanted than unauthorized users get a 403 error code when accessing any url behind example.com/supersecretarea/, even in the event that the page doesn't exist. Symfony's behavior does not allow that and checks for a 404 (either because there is no route or because the route has parameter which didn't resolve, like example.com/supersecretarea/user/198 when the is no user 198).
What we ended up doing was to override the default router in Symfony (Symfony\Bundle\FrameworkBundle\Routing\Router) to modify its behavior:
public function matchRequest(Request $request): array
{
try {
return parent::matchRequest($request);
} catch (ResourceNotFoundException $e) {
// Ignore this next line for now
// $this->targetPathSavingStatus->disableSaveTargetPath();
return [
'_controller' => 'App\Controller\CatchAllController::catchAll',
'_route' => 'catch_all'
];
}
}
CatchAllController simply renders the 404 error page:
public function catchAll(): Response
{
return new Response(
$this->templating->render('bundles/TwigBundle/Exception/error404.html.twig'),
Response::HTTP_NOT_FOUND
);
}
What happens is that during the regular process of Symfony's router, if something should trigger a 404 error, we catch that exception within the matchRequest function. This function is supposed to return information about which controller action to run to render the page, so that's what we do: we tell the router that we want to render a 404 page (with a 404 code). All the security is handled in between matchRequest returning and catchAll being called, so firewalls get to trigger 403 errors, we have an authentication token, etc.
There is at least one functional issue to this approach (that we managed to fix for now). Symfony has an optional system that remembers the last page you tried to load, so that if you get redirected to the login page and successfully log in, you'll be redirected to that page you were trying to load initially. When the firewall throws an exception, this occurs:
// Symfony\Component\Security\Http\Firewall\ExceptionListener
protected function setTargetPath(Request $request)
{
// session isn't required when using HTTP basic authentication mechanism for example
if ($request->hasSession() && $request->isMethodSafe(false) && !$request->isXmlHttpRequest()) {
$this->saveTargetPath($request->getSession(), $this->providerKey, $request->getUri());
}
}
But now that we allow non-existing pages to trigger firewall redirections to the login page (say, example.com/registered_users_only/* redirects to the loading page, and an unauthenticated user clicks on example.com/registered_users_only/page_that_does_not_exist), we absolutely don't want to save that non-existing page as the new "TargetPath" to redirect to after a successful login, otherwise the user will see a seemingly random 404 error. We decided to extend the exception listener's setTargetPath, and defined a service that toggles whether a target path should be saved by the exception listener or not.
// Our extended ExceptionListener
protected function setTargetPath(Request $request): void
{
if ($this->targetPathSavingStatus->shouldSave()) {
parent::setTargetPath($request);
}
}
That's the purpose of the commented $this->targetPathSavingStatus->disableSaveTargetPath(); line from above: to turn the default-on status of whether to save target path on firewall exceptions to off when there's a 404 (the targetPathSavingStatus variables here point to a very simple service used only to store that piece of information).
This part of the solution is not very satisfactory. I'd like to find something better. It does seem to do the job for now though.
Of course if you have always_use_default_target_path to true, then there is no need for this particular fix.
EDIT:
To make Symfony use my versions of the Router and Exception listener, I added the following code in the process() method of Kernel.php:
public function process(ContainerBuilder $container)
{
// Use our own CatchAll router rather than the default one
$definition = $container->findDefinition('router.default');
$definition->setClass(CatchAllRouter::class);
// register the service that we use to alter the targetPath saving mechanic
$definition->addMethodCall('setTargetPathSavingStatus', [new Reference('App\Routing\TargetPathSavingStatus')]);
// Use our own ExceptionListener so that we can tell it not to use saveTargetPath
// after the CatchAll router intercepts a 404
$definition = $container->findDefinition('security.exception_listener');
$definition->setClass(FirewallExceptionListener::class);
// register the service that we use to alter the targetPath saving mechanic
$definition->addMethodCall('setTargetPathSavingStatus', [new Reference('App\Routing\TargetPathSavingStatus')]);
// ...
}
I'm having problems creating error pages for my L5 app. I created a controller called BaseController which has all my CSS/JS and every other controller I have extends from it. How does one create an error 404 page which also extends BaseController?
Simply creating a view in views/errors/404.blade.php does not work since no styles are loaded. I'm using Twigbridge which is really useful when working with views.
Am assuming when you say controller has CSS/JS it means that your setting up layout using controllers.
Please note that this works for routes that you clearly define in your routes file and their respective controllers extend the Base.
For Error Pages they are not handle by your controllers. The error handlers are responsible for rendering their views and won't extend any layout. Hence you need to complete define it in your error view.
This should get you off on the right foot. Just use your standard extends syntax to extend your "default" layout.
Do a search for App::error, you will find the right spot.
App::error(function(Exception $exception, $code)
{
$params = array();
$request = Request::create('cms/noroute', 'GET', $params);
return Route::dispatch($request)->getContent();
});
There is no need to handle the errors within a controller or even the assets files. Imagine you have an error from laravel (missing a config file) so you will have the error before event the code could reach a controller. The same case goes for 404. If you do not have that route available, there is no need to let user reach a controller, this is handled by Exception Handler.
A good resource to learn more is Laravel documentation and this blog post
I'm currently migrating a project from CodeIgniter to Laravel5.
I saw in Laracasts that you can use the Request::authorize() method to authorize access before the controller is called, and it returns true or false.
This would (I think) be the ideal solution as I can contain permission checks within the request, rather than pollute the controller with permission checks and redirections / responses.
The only problem is, when I return false from authorize(), it simply loads an empty white page with forbidden written, and I can't find any documentation on laravel.com on how to template it (either there is no documentation, or I'm overlooking it)
I know I can edit the 404 page in errors/404.blade.php, but I can't work out how to customize the 403 page, which I've tried to add a custom 403.blade.php page, which doesn't get displayed. ( https://mattstauffer.co/blog/laravel-5.0-custom-error-pages )
Is placing these permission checks in the Request a good idea? Or am I missing something?
Update
I ran a backtrace from authorize(), and it looks like it throws an UnauthorizedException, which extends RuntimeException. I've tried catching both in the routes.php file, which doesn't work either.
I've also tried to create middleware, and call the middleware from a method, which doesn't work either, since the middleware's not even called at all.
Update 2
Ok, so I found out that I can only call $this->middleware() from the constructor, not individual methods, which is progress, I guess.
What i do is add a forbiddenResponse() method to Request abstract class. You can return a response object from that method to render a human readable error.
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\JsonResponse;
abstract class Request extends FormRequest {
public function forbiddenResponse()
{
return new JsonResponse('Unauthorized', 403);
// or return Response::make('Unauthorized', 403);
}
}
Check the app\Exceptions\Handler.php file. That's where you can customize your exception handling.
The 403 error launches a HttpException. By default, Laravel will look under your resources\views\errors\ directory and try to find a view that corresponds to the same status code. Since you already said that you've created a file called 403.blade.php inside that folder, it should render this page for 403 errors.
One last thing, remember to check inside your web server config file (httpd.conf for Apache, sites-available\your-host for Nginx), if you have a default behavior for any error. If you're using Homestead, you can check the Nginx config file for anything like error_page 404 /index.php;, comment the line and restart the service. That's not the ideal scenario but usually works.
Override the method within your form request object
class CreateUserRequest extends FormRequest {
public function forbiddenResponse(){
return abort(403);
}
}
I'm new to FuelPHP and I did a little coding with it! What I did was create a simple controller and created two methods. One for action_index() and the other is action_add().
the code is given below. Views are already in the app\views\ folder.
class Controller_Student extends Controller
{
public function action_index()
{
return Response::forge(View::forge('index'));
}
public function action_add()
{
return Response::forge(View::forge('select'));
}
}
I've set the root to this controller class. When I run the application the index works fine and loads the directed view. But when I give the following URL
http://localhost/project/public/add/
the method doesn't get called! A 404 error is give saying
You can see this page because the URL you are accessing cannot be found.
What Am I doing wrong here. I've gone through every documentation, tutorial I find but I shouldn't get this type of an error. Please help me.
Below is the routing file code :
return array(
'_root_' => 'student', // The default route
'_404_' => 'welcome/404', // The main 404 route
);
You've set the root to student controller, but that doesn't mean all traffic goes through that controller. Try visiting:
http://localhost/project/public/student/add/