Complete refactoring

This commit is contained in:
steampixel 2018-03-13 16:01:52 +01:00
parent 47ce76fbb7
commit 2b76b40d82
4 changed files with 182 additions and 147 deletions

View File

@ -4,6 +4,7 @@ DirectoryIndex index.php
RewriteEngine on
# set your rewrite base
# Edit this in your init method too if you script lives in a subfolder
RewriteBase /
# Deliver the folder or file directly if it exists on the server

View File

@ -1,27 +1,33 @@
# Simple PHP Router
Hey! This is a simple class that can handel the whole url routing for your project.
Hey! This is a simple and small php router that can handel the whole url routing for your project.
It utilizes RegExp and PHPs anonymous functions to create a lightweight and fast routing system.
The router supports dynamic path parameters, special 404 and 405 routes as well as verification of request methods like get, post, put, delete etc...
The codebase is very small and very easy to understand. So you can use it as boilerplate for a more complex router.
Take a look in the index.php file. As you can see the ```Route::add()``` method is used to add new routes to your project.
The first argument takes the path segment. You can also use RegExp in there to parse out variables.
All matches will be pushed to the handler method. The handler is the second argument of the add function.
The second argument will match the request method. The default method is 'get'.
All matching variables will be pushed to the handler method.
Example:
## Simple example:
```
Route::add('/user/(.*)/edit',function($id){
//Do something
include('Route.php');
Route::add('/user/([0-9]*)/edit',function($id){
echo 'Edit user with id '.$id.'<br/>';
});
},'get');
Route::run('/');
```
## Testing
* Clone or download this repo
* Cd into the repo folder and run:
* ```php -S 0.0.0.0:8080```
* Than open your Webbrowser and navigate to http://localhost:8080
You will find a more complex example with a build in navigation in the index.php file.
## Use a different basepath
If your script lives in a subfolder e.g. /api/v1 set this basepath in your run method:
```Route::run('/api/v1');```
Do not forget to edit the basepath in .htaccess if you are on apache
## Something does not work?
* Dont forget to set the basepath in your index.php and .htaccess file.
* Dont forget to set the correct basepath as argument in your run method and in your .htaccess file.
* Enable mod_rewrite in your apache settings

109
Route.php
View File

@ -3,84 +3,99 @@
class Route{
private static $routes = Array();
private static $routes404 = Array();
private static $path;
private static $basepath = '/';
private static $pathNotFound = null;
private static $methodNotAllowed = null;
public static function init($basepath = '/'){
public static function add($expression, $function, $method = 'get'){
array_push(self::$routes,Array(
'expression' => $expression,
'function' => $function,
'method' => $method
));
}
self::$basepath = $basepath;
public static function pathNotFound($function){
self::$pathNotFound = $function;
}
public static function methodNotAllowed($function){
self::$methodNotAllowed = $function;
}
public static function run($basepath = '/'){
// Parse current url
$parsed_url = parse_url($_SERVER['REQUEST_URI']);//Parse Uri
if(isset($parsed_url['path'])){
self::$path = $parsed_url['path'];
$path = $parsed_url['path'];
}else{
self::$path = '/';
$path = '/';
}
}
// Get current request method
$method = $_SERVER['REQUEST_METHOD'];
public static function add($expression,$function){
$path_match_found = false;
array_push(self::$routes,Array(
'expression'=>$expression,
'function'=>$function
));
}
public static function add404($function){
array_push(self::$routes404,$function);
}
public static function run(){
$route_found = false;
$route_match_found = false;
foreach(self::$routes as $route){
// If the method matches check the path
// Add basepath to matching string
if(self::$basepath!=''&&self::$basepath!='/'){
$route['expression'] = '('.self::$basepath.')'.$route['expression'];
}
if($basepath!=''&&$basepath!='/'){
$route['expression'] = '('.$basepath.')'.$route['expression'];
}
// Add 'find string start' automatically
$route['expression'] = '^'.$route['expression'];
// Add 'find string start' automatically
$route['expression'] = '^'.$route['expression'];
// Add 'find string end' automatically
$route['expression'] = $route['expression'].'$';
// Add 'find string end' automatically
$route['expression'] = $route['expression'].'$';
// echo $route['expression'].'<br/>';
// Check match
if(preg_match('#'.$route['expression'].'#',self::$path,$matches)){
// Check path match
if(preg_match('#'.$route['expression'].'#',$path,$matches)){
array_shift($matches);// Always remove first element. This contains the whole string
$path_match_found = true;
if(self::$basepath!=''&&self::$basepath!='/'){
// Check method match
if(strtolower($method) == strtolower($route['method'])){
array_shift($matches);// Remove Basepath
array_shift($matches);// Always remove first element. This contains the whole string
}
if($basepath!=''&&$basepath!='/'){
array_shift($matches);// Remove basepath
}
call_user_func_array($route['function'], $matches);
call_user_func_array($route['function'], $matches);
$route_found = true;
$route_match_found = true;
// Do not check other routes
break;
}
}
}
if(!$route_found){
// No matching route was found
if(!$route_match_found){
foreach(self::$routes404 as $route404){
call_user_func_array($route404, Array(self::$path));
}
// But a matching path exists
if($path_match_found){
header("HTTP/1.0 405 Method Not Allowed");
if(self::$methodNotAllowed){
call_user_func_array(self::$methodNotAllowed, Array($path,$method));
}
}else{
header("HTTP/1.0 404 Not Found");
if(self::$pathNotFound){
call_user_func_array(self::$pathNotFound, Array($path));
}
}
}

159
index.php
View File

@ -1,76 +1,4 @@
<?PHP
// Include needed files
include('Route.php');
// Init routing and configure basepath
// If your script lives in the web root folder use a / , leave it empty or do not define this config
Route::init('/');
// If your script lives in a subfolder you can use the following example
// Route::init('/api/v1');
// Base route (startpage)
Route::add('/',function(){
// Do something
echo 'Welcome :-)';
});
// Another base route example
Route::add('/index.php',function(){
// Do something
echo 'You are not realy on index.php ;-)';
});
// Simple route
Route::add('/test.html',function(){
// Do something
echo 'Hello from test.html';
});
// Complex route with parameter
// Be aware that (.*) will match / too. For example: /user/foo/bar/edit
// Also users could inject mysql-code or other unchecked data if you use (.*)
// You should better use a saver expression like /user/([0-9]*)/edit or /user/([A-Za-z]*)/edit
Route::add('/user/(.*)/edit',function($id){
// Do something
echo 'Edit user with id '.$id.'<br/>';
});
// Accept only numbers as the second parameter. Other characters will result in a 404
Route::add('/foo/([0-9]*)/bar',function($var1){
// Do something
echo $var1.' is a great number!';
});
// Long route example
Route::add('/foo/bar/foo/bar',function(){
// Do something
echo 'hehe :-)<br/>';
});
// Crazy route with parameters (Will be triggered on the route pattern above too because it matches too)
Route::add('/(.*)/(.*)/(.*)/(.*)',function($var1,$var2,$var3,$var4){
// Do something
echo 'You have entered: '.$var1.' / '.$var2.' / '.$var3.' / '.$var4.'<br/>';
});
// Add a 404 not found route
Route::add404(function($url){
// Send 404 Header
header("HTTP/1.0 404 Not Found");
echo '404 :-(<br/>';
echo $url.' not found!';
});
// Check if any of the defined routes will match and execute them
Route::run();
?>
<hr/>
Navigation:
<ul>
<li><a href="/">home</a></li>
@ -78,5 +6,90 @@ Navigation:
<li><a href="/user/3/edit">edit user 3</a></li>
<li><a href="/foo/5/bar">foo 5 bar</a></li>
<li><a href="/foo/bar/foo/bar">long route example</a></li>
<li><a href="/test.html">test.html</a> (May not work with PHPs built in webserver. Try apache webserver.)</li>
<li><a href="/contact-form">contact form</a></li>
<li><a href="/test.html">test.html</a></li>
<li><a href="/this-route-is-not-defined">404 Test</a></li>
<li><a href="/this-route-is-defined">405 Test</a></li>
</ul>
<?PHP
// Include router class
include('Route.php');
// Add base route (startpage)
Route::add('/',function(){
echo 'Welcome :-)';
});
// Another base route example
Route::add('/index.php',function(){
echo 'You are not realy on index.php ;-)';
});
// Simple test route that simulates static html file
Route::add('/test.html',function(){
echo 'Hello from test.html';
});
// Post route example
Route::add('/contact-form',function(){
echo '<form method="post"><input type="text" name="test" /><input type="submit" value="send" /></form>';
},'get');
// Post route example
Route::add('/contact-form',function(){
echo 'Hey! The form has been sent:<br/>';
print_r($_POST);
},'post');
// Route with regexp parameter
// Be aware that (.*) will match / (slash) too. For example: /user/foo/bar/edit
// Also users could inject mysql-code or other untrusted data if you use (.*)
// You should better use a saver expression like /user/([0-9]*)/edit or /user/([A-Za-z]*)/edit
Route::add('/user/(.*)/edit',function($id){
echo 'Edit user with id '.$id.'<br/>';
});
// Accept only numbers as parameter. Other characters will result in a 404 error
Route::add('/foo/([0-9]*)/bar',function($var1){
echo $var1.' is a great number!';
});
// Crazy route with parameters
Route::add('/(.*)/(.*)/(.*)/(.*)',function($var1,$var2,$var3,$var4){
echo 'This is the first match: '.$var1.' / '.$var2.' / '.$var3.' / '.$var4.'<br/>';
});
// Long route example
// This route gets never triggered because the route before matches too
Route::add('/foo/bar/foo/bar',function(){
echo 'This is the second match <br/>';
});
// 405 test
Route::add('/this-route-is-defined',function(){
echo 'You need to patch this route to see this content';
},'patch');
// Add a 404 not found route
Route::pathNotFound(function($path){
echo 'Error 404 :-(<br/>';
echo 'The requested path "'.$path.'" was not found!';
});
// Add a 405 method not allowed route
Route::methodNotAllowed(function($path, $method){
echo 'Error 405 :-(<br/>';
echo 'The requested path "'.$path.'" exists. But the request method "'.$method.'" is not allowed on this path!';
});
// Run the Router with the given Basepath
// If your script lives in the web root folder use a / or leave it empty
Route::run('/');
// If your script lives in a subfolder you can use the following example
// Do not forget to edit the basepath in .htaccess if you are on apache
// Route::run('/api/v1');
?>