Please consider the following very rudimentary "controllers" (functions in this case, for simplicity):
function Index() {
var_dump(__FUNCTION__); // show the "Index" page
}
function Send($n) {
var_dump(__FUNCTION__, func_get_args()); // placeholder controller
}
function Receive($n) {
var_dump(__FUNCTION__, func_get_args()); // placeholder controller
}
function Not_Found() {
var_dump(__FUNCTION__); // show a "404 - Not Found" page
}
And the following regex-based Route()
function:
function Route($route, $function = null)
{
$result = rtrim(preg_replace('~/+~', '/', substr($_SERVER['PHP_SELF'], strlen($_SERVER['SCRIPT_NAME']))), '/');
if (preg_match('~' . rtrim(str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $route), '/') . '$~i', $result, $matches) > 0)
{
exit(call_user_func_array($function, array_slice($matches, 1)));
}
return false;
}
Now I want to map the following URLs (trailing slashes are ignored) to the corresponding "controllers":
/index.php -> Index()
/index.php/send/:NUM -> Send()
/index.php/receive/:NUM -> Receive()
/index.php/NON_EXISTENT -> Not_Found()
This is the part where things start to get tricky, I've two problems I'm not able to solve... I figure I'm not the first person to have this problem, so someone out there should have the solution.
Catching 404's (Solved!)
I can't find a way to distinguish between requests to the root (index.php
) and requests that shouldn't exist like (index.php/notHere
). I end up serving the default index.php
route for URLs that should otherwise be served a 404 - Not Found
error page. How can I solve this?
EDIT - The solution just flashed in my mind:
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route('/:any', 'Not_Found'); // use :any here, see the problem bellow
Route('/', 'Index');
Ordering of the Routes
If I set up the routes in a "logical" order, like this:
Route('/', 'Index');
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route(':any', 'Not_Found');
All URL requests are catched by the Index()
controller, since the empty regex (remember: trailing slashes are ignored) matches everything. However, if I define the routes in a "hacky" order, like this:
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route('/:any', 'Not_Found');
Route('/', 'Index');
Everything seems to work like it should. Is there an elegant way of solving this problem?
The routes may not always be hard-coded (pulled from a DB or something), and I need to make sure that it won't be ignoring any routes due to the order they were defined. Any help is appreciated!