Codeigniter Routes Regex - Using Dashes in Controller/Method Names

Codeigniter Routes regex - using dashes in controller/method names

That is exactly my requirement too and I was using routes like

$route['logued/presse-access'] = "logued/presse_access";

In my previous project I needed to create 300-400 routing rules, most of them are due to dash to underscore conversion.

For my next project I eagerly want to avoid it. I have done some quick hack and tested it, though have not used in any live server, its working for me. Do the following..

Make sure the subclass_prefix is as follows in your system/application/config/config.php

$config['subclass_prefix'] = 'MY_';

Then upload a file named MY_Router.php in system/application/libraries directory.

<?php

class MY_Router extends CI_Router {
function set_class($class)
{
//$this->class = $class;
$this->class = str_replace('-', '_', $class);
//echo 'class:'.$this->class;
}

function set_method($method)
{
// $this->method = $method;
$this->method = str_replace('-', '_', $method);
}

function _validate_request($segments)
{
// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $segments[0]).EXT))
{
return $segments;
}
// Is the controller in a sub-folder?
if (is_dir(APPPATH.'controllers/'.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($segments[0]);
$segments = array_slice($segments, 1);

if (count($segments) > 0)
{
// Does the requested controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().str_replace('-', '_', $segments[0]).EXT))
{
show_404($this->fetch_directory().$segments[0]);
}
}
else
{
$this->set_class($this->default_controller);
$this->set_method('index');

// Does the default controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
{
$this->directory = '';
return array();
}

}

return $segments;
}

// Can't find the requested controller...
show_404($segments[0]);
}
}

Now you can freely use url like http://example.com/logued/presse-access and it will call the proper controller and function by automatically converting dash to underscore.

Edit:
Here is our Codeigniter 2 solution which overrides the new CI_Router functions:

<?php

class MY_Router extends CI_Router {
function set_class($class)
{
$this->class = str_replace('-', '_', $class);
}

function set_method($method)
{
$this->method = str_replace('-', '_', $method);
}

function set_directory($dir) {
$this->directory = $dir.'/';
}

function _validate_request($segments)
{
if (count($segments) == 0)
{
return $segments;
}

// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $segments[0]).'.php'))
{
return $segments;
}

// Is the controller in a sub-folder?
if (is_dir(APPPATH.'controllers/'.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($segments[0]);
$segments = array_slice($segments, 1);

while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($this->directory . $segments[0]);
$segments = array_slice($segments, 1);
}

if (count($segments) > 0)
{
// Does the requested controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().str_replace('-', '_', $segments[0]).'.php'))
{
if ( ! empty($this->routes['404_override']))
{
$x = explode('/', $this->routes['404_override']);

$this->set_directory('');
$this->set_class($x[0]);
$this->set_method(isset($x[1]) ? $x[1] : 'index');

return $x;
}
else
{
show_404($this->fetch_directory().$segments[0]);
}
}
}
else
{
// Is the method being specified in the route?
if (strpos($this->default_controller, '/') !== FALSE)
{
$x = explode('/', $this->default_controller);

$this->set_class($x[0]);
$this->set_method($x[1]);
}
else
{
$this->set_class($this->default_controller);
$this->set_method('index');
}

// Does the default controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php'))
{
$this->directory = '';
return array();
}

}

return $segments;
}

// If we've gotten this far it means that the URI does not correlate to a valid
// controller class. We will now see if there is an override
if ( ! empty($this->routes['404_override']))
{
$x = explode('/', $this->routes['404_override']);

$this->set_class($x[0]);
$this->set_method(isset($x[1]) ? $x[1] : 'index');

return $x;
}

// Nothing else to do at this point but show a 404
show_404($segments[0]);
}
}

Now one has to place this file like application/core/MY_Router.php and make sure he has subclass_prefix is defined as $config['subclass_prefix'] = 'MY_'; in application/config/config.php

Few extra lines of code has been added in method _validate_request():

while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($this->directory . $segments[0]);
$segments = array_slice($segments, 1);
}

It is used so that one can make use of multi-level subdirectory inside controllers directory, whereas normally we can use single level subdirectory inside controllers folder and can call it in url. One can remove this code if it not necessary but it has no harm on the normal flow.

CodeIgniter routing - change underscores to dashes

As per the Codeigniter Specifications, changing the following line to TRUE in routes.php will translate underscores to dashes.

$route['translate_uri_dashes'] = TRUE;

Codeigniter API Docs - Routing

Regex for URL routing - match alphanumeric and dashes except words in this list

Alright, let's pick this apart.

Ignore CodeIgniter's reserved routes.

The default_controller and 404_override portions of your route are unnecessary. Routes are compared to the requested URI to see if there's a match. It is highly unlikely that those two items will ever be in your URI, since they are special reserved routes for CodeIgniter. So let's forget about them.

$route['(?!home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254}'] = 'view/slug/$1';

Capture everything!

With regular expressions, a group is created using parentheses (). This group can then be retrieved with a back reference - in our case, the $1, $2, etc. located in the second part of the route. You only had a group around the first set of items you were trying to exclude, so it would not properly capture the entire wild card. You found this out yourself already, and added a group around the entire item (good!).

$route['((?!home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254})'] = 'view/slug/$1';

Look-ahead?!

On that subject, the first group around home|activity is not actually a traditional group, due to the use of ?! at the beginning. This is called a negative look-ahead, and it's a complicated regular expression feature. And it's being used incorrectly:

Negative lookahead is indispensable if you want to match something not followed by something else.

There's a LOT more I could go into with this, but basically we don't really want or need it in the first place, so I'll let you explore if you'd like.

In order to make your life easier, I'd suggest separating the home, activity, and other existing controllers in the routes. CodeIgniter will look through the list of routes from top to bottom, and once something matches, it stops checking. So if you specify your existing controllers before the wild card, they will match, and your wild card regular expression can be greatly simplified.

$route['home'] = 'pages';
$route['activity'] = 'user/activity';
$route['([A-Za-z0-9][A-Za-z0-9_-]{2,254})'] = 'view/slug/$1';

Remember to list your routes in order from most specific to least. Wild card matches are less specific than exact matches (like home and activity), so they should come after (below).

Now, that's all the complicated stuff. A little more FYI.

Remember that dashes - have a special meaning when in between [] brackets. You should escape them if you want to match a literal dash.

$route['([A-Za-z0-9][A-Za-z0-9_\-]{2,254})'] = 'view/slug/$1';

Note that your character repetition min/max {2,254} only applies to the second set of characters, so your user names must be 3 characters at minimum, and 255 at maximum. Just an FYI if you didn't realize that already.

I saw your own answer to this problem, and it's just ugly. Sorry. The ^ and $ symbols are used improperly throughout the lookahead (which still shouldn't be there in the first place). It may "work" for a few use cases that you're testing it with, but it will just give you problems and headaches in the future.

Hopefully now you know more about regular expressions and how they're matched in the routing process.

And to answer your question, no, you should not use ^ and $ at the beginning and end of your regex -- CodeIgniter will add that for you.


Use the 404, Luke...

At this point your routes are improved and should be functional. I will throw it out there, though, that you might want to consider using the controller/method defined as the 404_override to handle your wild cards. The main benefit of this is that you don't need ANY routes to direct a wild card, or to prevent your wild card from goofing up existing controllers. You only need:

$route['404_override'] = 'view/slug';

Then, your View::slug() method would check the URI, and see if it's a valid pattern, then check if it exists as a user (same as your slug method does now, no doubt). If it does, then you're good to go. If it doesn't, then you throw a 404 error.

It may not seem that graceful, but it works great. Give it a shot if it sounds better for you.

How to replace underscores in codeigniter url with dashes?

The routes config found in

config/routes.php

is your friend here.

A simple

$route['request-guide'] = "request_guide" ;

will do this for you.

Using the regex from valid_email method in CodeIgniter to route a URL with an email in it for email verification

$route['registration/(/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix)/(:any)']

should be:

$route['registration/([\w+-]+)(\.[\w+-]+)*@([a-zA-Z\d-]+\.)+[a-zA-Z]{2,6}/(:any)']

The entire string is a regex without delimiters or modifiers. You were putting delimiters, modifiers and were also using ^ and $.

I simplified the regex, however email validation should not be done via URL. Instead your controller should be checking that segment and performing validation on it. If it does not match redirect to re-register or output error message, otherwise continue on with registration.

Btw don't re-invent the wheel when validating an email address. PHP has built-in validation via the filter_var() function.

Example:

$email = 'joe@example.com';

if (filter_var($email, FILTER_VALIDATE_EMAIL))
{
echo 'valid';
}

Use hyphen(-) instead of slash(/) or underscore( _ ) in Routes

You trying to create a dynamic routes which is not possible in codeigniter if you see the following flow chart of codeigniter you understand what i mean.

Sample Image

also you can see this chart in codeigniter official website

when you try to redirect or call some url it's work like this

Sample Image

Every request first goes to route there for you can't make it dynamic

codeigniter routing (regex)

Same effect, but Codeigniter-style:

//remember that custom routes need to go _after_ ci's default routes, as they're executed in the order you provide them
$route['default_controller'] = "welcome";
$route['404_override'] = '';
//exception 1 to your regex here
//exception 2 to your regex here
//so on...
$route['(:any)/(:any)/(:any)'] = "$2/$3/$1";

CodeIgniter - Properly formatted URLs

A PHP class cannot have a hyphen in its name. That's why naming your class About-us didn't work.

If you're set on having hyphens in your URLs, you should look at CodeIgniter's custom URI routing.

http://ellislab.com/codeigniter/user_guide/general/routing.html

See the section on regular expressions down near the bottom of the page. You can set up a regular expression to replace the hyphens in your URLs to underscores - that way, your users will see the hyphens, but CodeIgniter will use the underscores.



Related Topics



Leave a reply



Submit