I have a controller and action which I'm accessing through a custom URL. The original route is still accessible though at the default location
zend.com/controller/action
How can I change this to simulate a "Page not found" when the user tries to access this URL? Is it possible?
If the action handler is used to respond to both URLs, you would first have to detect which URL is being requested (using $this->_request->getRequestUri()). If the default URL is detected I think the easiest way to create a "page not found" would be to use
$this->_redirect("/path/to/simulated/404/page")
and set up a controller and action to respond.
This won't actually send an HTTP 404, though. To do that, I think you would have to raise an exception within your action handler. I don't know what the official "zendy" way of doing this is, but this seems to work:
throw new Zend_Controller_Action_Exception('Not Found', 404);
You could change the main controller script to redirect a certain controller name and action name to a new page. But it's probably easier to add a new rule to the .htaccess file, indicating that this specific URL should be redirected to an error page. Example:
RewriteRule ^controller/action/?$ / [R=404,L]
Or redirect the page to an error page within your site:
RewriteRule ^controller/action/?$ /error/page-not-found/ [L]
You need to use:
$this->getResponse()->setHttpResponseCode(404);
And build your own 404 view
$this->view->message = 'Page not found';
Or you could forward to an error controller for example
$this->_forward('page-not-found', 'error');
Finally, if you have in your error controller
//...
switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// 404 error -- controller or action not found
$this->getResponse()->setHttpResponseCode(404);
$this->view->message = 'Page not found';
break;
//...
You can just do as #bogeymin said:
throw new Zend_Controller_Action_Exception('Not Found', 404);
If you are looking other solutions than mod_rewrite based, you may create a Regex Route to match the actions you need to hide.
The other solution is to restrict access to Actions using Zend_Acl, treating each action as an ACL resource.
But the simplest and most lightweight solution is still mod_rewrite in .htaccess.
Edit:
As you can see, this may be done in numerous ways. But probably, you will need some kind of the switch, to still allow somehow to access the "hidden" action. In this case, use:
mod_rewrite for quick implementation (switching requires the person to know the .htaccess rules)
Zend_Router - the person who knows the right route can still access the feature
Zend_Acl + Zend_Auth for scalable and secure solution.
If you don't need to have authenticated users, Zend_Acl combined with Zend_Router might be the solution.
For smart handling the exceptions and building ACL's, see this (and other posts on this blog):
Handling errors in Zend Framework | CodeUtopia - The blog of Jani Hartikainen
By default the router includes default routes for :module/:controller/:action/ and :controller/:action/. You can disable these with:
$router->removeDefaultRoutes();
then only routes you setup will work. If you still want to use the default routes for some other things, you'll either have to go with one of the other answers posted or add your own 'default' routes which will match all but the modules/controllers you have custom routes for.
If you don't want to remove the default route as #Tim Fountain suggests, you should do something like this in your controller (either preDispatch or whateverAction methods)
$router = $this->getFrontController()->getRouter();
$route = $router->getCurrentRouteName();
// if we reached this controller/action from the default route, 404
if ($route == 'default')
{
throw new Zend_Controller_Action_Exception('Not Found', 404);
}
I think, all answers above are incorrect. Those show ways to achieve the same thing, but present logic at the wrong place in your application, which eventually can cause trouble later on.
The correct part of your route logic is, how extremely simple, in the routes. What is missing is that the default route Zend_Controller_Router_Route_Module does not allow you to add exceptions to specific routes. So what you need to do, is remove the default route from your routes, and add a new custom route (which should function exactly as the default route, but allows excludes) at it's place.
You can write the new route by extending the class of the default route.
class My_Custom_Route extends Zend_Controller_Router_Route_Module
{
protected $_excludes = array();
public function exclude($abc)
{
//add to $_excludes here the controller/action you want to exclude
}
public function match($abc)
{
//add functionality here that denies if the mod/contr/action is in $_excludes
//you can also add this in a separate method
//re-use parent code
}
}
You can now add add the excludes for example in a config file, and load + add the excludes at the place you initiate the new Route (and add it to the router). Off you go.
Related
I have the following (basic) route set up in a CI-based web app:
$route['sms/resend/(:num)/(:any)'] = 'sms/resend/$1/$2';
The controller + 'resend' method:
class Sms extends CI_Controller {
public function resend($to, $message) {
// my code
}
}
Logically speaking, anything that doesn't fit the route should be directed to a 404 page instead of the resend() method within the sms controller. This isn't the case, however. The following URL, for example, isn't redirected correctly, it goes to the same controller+method:
http://myapp/sms/resend/uuuu/WhateverMessage
What could be the problem?
After a bit of digging, I've come to understand that CI's default routing does not get deactivated when a default route related to a specific controller/method pair is added. That being said, if a URL does not fit the route $route['sms/resend/(:num)/(:any)'] = 'sms/resend/$1/$2', then the same URL is run through CI's default routing mechanism as a fallback, so it still takes me to the resend method of the sms controller. To prevent this from happening, I needed to add another custom route that follows all others related to the sms resending, that redirects any other url to a different controller+method. If this controller doesn't exist, you get the default 404 page.
So the final /config/routes.php file:
$route['sms/resend/(:num)/(:any)'] = 'sms/resend/$1/$2';
$route['sms/checkoperator/(:num)'] = 'sms/checkoperator/$1';
$route['sms/(:any)'] = 'somewhereovertherainbow';
I think the rout file is just for rerouting. Your URL don't fits the routing Conditions so it don't gets rerouted! So it goes the normal way wich is the same (in this case!)
Something like this could work!
(! :num) /(:any) '] = error page (or not existing page)
So every request wich doesn't start with a number gets redirected to the error page!
The syntax might be wrong!
This would work great :
$route['sms/resend/[^0-9]/(:any)'] = 'errorpage';
You have to replace the error page by something ;)
Is it possible to turn off the automatic routing in CodeIgniter and have it only process requests if a route for that request exists? Thanks.
Keep in mind that Dale's solution:
$route['(:any)'] = "some/default/controller/$1";
only works for one-segment URLs, like:
example.com/foo
but not for:
example.com/foo/bar
You can get around this by using a regular expression instead of the CI wildcard. And by routing to a non-existing class drops a show_404() indeed:
$route['(.*)'] = "none";
AFAIK you can't turn off CI's automatic routing, but there is a work around:
// you specific routes
$route['admin/(:any)'] = "admin/$1";
$route['search/(:any)'] = "search/$1";
// the catch all route
$route['(:any)'] = "some/default/controller/$1";
Which doesn't actually turn off CI's routing but routes all unmatched uri's to the default controller.
Alternatively you could route to a non-existent controller which I believe will throw the in built 404 error
Well, another solution could be extends the Router.
Create a class name MY_Route at /application/core/MY_Router declared as class MY_Router extends CI_Router.
You could override the method _set_routing():
This function determines what should be served based on the URI request, as well as any "routes" that have been set in the routing config file.
It should be more complex, but at least can guide you to another solution.
Codeigniter 4 solution:
app/config/Routes.php at line 24 set value true to false
$routes->setAutoRoute(false);
No, it's not possible turn off the automatic routing convention in CodeIgniter as far as I know, but you can put entries in your .htaccess file to redirect de default routes to the routes you've created.
If I have a controller called articles, which has a method called view_articles, a user can type in http://example.com/articles/view_articles/some-post and have it return a page.
I have specified a route to be http://example.com/article/post-name. How can I make it so that only the URL specified in the route is visible? Is there a way for articles/view_articles/some-post to show a 404 instead of showing the same page as the route URL?
I am trying to prevent duplication for SEO purposes.
You can always make default routing to a 404 page by correctly defining routes in your routes.php file:
$routes['article/(:any)'] = 'articles/view_articles/$1';
$routes['(:any)'] = 'main/e404';
As stated by CodeIgniter user guide:
Routes will run in the order they are defined. Higher routes will always take precedence over lower ones.
So you can basically define all you want to be seen at the beginning of the file and block everything else on the last line.
As for your main(can be any other) controller's 404 method -
function e404() {
show_404();
}
Use $this->uri->segment(n) as part of the URI class inside of view_articles to redirect traffic to your route if the URI contains view_articles as it's second segment.
I'v done that in other tricky way, first of all you should add some code to __construct function in sys/core/Controller.php
you can check whether the requested url is in routes or not by this code
if(!isset($this->router->routes[uri_string()])){
show_404(); // Or whatever you want ...
}
In config/routes.php
<?php
return array(
'account/profile/change_password' => 'users/account/change_password',
);
I can access site.com/users/account/change_password and site.com/users/account/change_password in the browser.
Is there a way to restrict it to the left side only (i.e. site.com/users/account/change_password)?
Only by routing it specificly, for example by routing it to the same place as your _404_ controller. Of course you could also do it for the entire controller:
'users/account(/:any)' => 'my/404/route',
That way a direct call on this controller would always go to your 404.
Of course if your routes end in a wild-card route like ':any' => 'catch/everything/$1' you don't need to do this.
To be complete: if you want to allow only HMVC calls, but no URI access, you can also capture it in the controller itself. Either in the before() method (for the entire controller) or in the individual methods:
// throw a 404 if accessed via the URI
if ( ! \Request::active()->is_hmvc())
{
throw new \HttpNotFoundException();
}
I've been playing with Codeigniter lately, and I came to know that you can remap a function inside a Controller so that you can have dynamic pretty URL.
I just want to know can the same be done with controllers? I mean If I call http://example.com/stack, it'll look for a controller named stack and if not found, it'll call a fixed/remapped controller where I can take care of it.
Can this be done?
Maybe this can help you:
function _remap( $method )
{
/// $method contains the second segment of your URI
switch( $method )
{
case 'about-me':
$this->about_me();
break;
case 'successful':
$this->display_successful_message();
break;
default:
$this->page_not_found();
break;
}
}
Yes, it can be done, you achieve it by using uri routing.
In your application/config/routes.php you can set your custom routes to remapping URIs.
There are already 2 provided, the default one (in case no controller is called) and the 404 error routing.
Now, if you want to add custom routes, you just add them UNDER those 2 defaults, keeping in mind that they're executed in the order they're presented.
Say, for example, you want to remap 'stack' to another controller, just use:
$routes['stack'] = 'othercontroller';
In this way, whenever you access 'stack' it will be automatically mapped to 'othercontroller', and if that doesn't exists..well, you get the same 404 error.
If you're hiding index.php from the URL with .htaccess remember to insert it into the $config['index_page'] = 'index.php';.
If what you're trying to achieve, instead, is a custom error message when a controller is not found, just override the 404 route as already suggested by #Juris Malinens, using your custom default controller to handle that situation
$route['404_override'] = 'customcontroller';
You can use .htaccess to do this or config/routes.php- Codeigniter is very flexible ;-)
If controller is not found use $route['404_override']; in config/routes.php
The application/config/routes.php file would be the appropriate place to do this. The 404_override mentioned by Juris is only available in CI 2.x just in case you have an older version (I don't know, you may be working on a legacy system, or may have to in the future).
Note, you can do more than just "remap" controllers with this. The routes accept regex patterns like htaccess rewrite rules; there are also some CI patterns which are basically just more human readable alias for regexes. Say you had an Articles controller with category, search and article functions, you might have routes that looked like:
$route["category/(:any)"] = "articles/category/$1";
$route["search/(:any)"] = "articles/search/$1";
$route["(:any)"] = "articles/article/$1';
You see how you can use routes to completely remove the controller name from you URLs? These rules would fall back to assuming the page is an article if the URL doesn't specifically say it's a category page or a search query. You could then check if you had an article for the URL and display a 404 as appropriate.