Merge pull request #11 from ImMaax/master
Unified the code style across the project, fixed grammar issues, added TODOs
This commit is contained in:
commit
8e9dfc667d
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,2 +1,6 @@
|
|||
# vagrant files
|
||||
.vagrant
|
||||
# Vagrant files
|
||||
.vagrant
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
._*
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018-2019 SteamPixel and contributors
|
||||
Copyright (c) 2018 - 2020 SteamPixel and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
28
README.md
28
README.md
|
@ -5,16 +5,16 @@ It utilizes RegExp and PHP's anonymous functions to create a lightweight and fas
|
|||
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 a boilerplate for a more complex router.
|
||||
|
||||
Take a look at the index.php file. As you can see the ```Route::add()``` method is used to add new routes to your project.
|
||||
Take a look at 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 matching variables will be pushed to the handler method defined in the second argument.
|
||||
The third argument will match the request method. The default method is 'get'.
|
||||
|
||||
## Simple example:
|
||||
```
|
||||
```php
|
||||
include 'Route.php';
|
||||
|
||||
Route::add('/user/([0-9]*)/edit',function($id) {
|
||||
Route::add('/user/([0-9]*)/edit', function($id) {
|
||||
echo 'Edit user with id '.$id.'<br>';
|
||||
}, 'get');
|
||||
|
||||
|
@ -26,36 +26,38 @@ You will find a more complex example with a build in navigation in the index.php
|
|||
## 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');```
|
||||
```php
|
||||
Route::run('/api/v1');
|
||||
```
|
||||
|
||||
Do not forget to edit the basepath in .htaccess too if you are on Apache2. In order to run the test files correctly inside a basepath you should also adjust the navigation links inside the index.php.
|
||||
|
||||
## Enable case sensitive routes and trailing slashes
|
||||
The second and third parameters of ```Route::run('/', false, false);``` are both set to false by default.
|
||||
The second and third parameters of `Route::run('/', false, false);` are both set to false by default.
|
||||
You can enable case sensitive mode by setting the second parameter to true.
|
||||
By default the router will ignore trailing slashes. Set the third parameter to true to avoid this.
|
||||
|
||||
## Something does not work?
|
||||
* Dont forget to set the correct basepath as argument in your run method and in your .htaccess file.
|
||||
* Enable mod_rewrite in your Apache2 settings
|
||||
* Don't forget to set the correct basepath as the first argument in your `run()` method and in your .htaccess file.
|
||||
* Enable mod_rewrite in your Apache2 settings, in case you're using Apache2: `a2enmod apache2`
|
||||
|
||||
## Test setup with Docker
|
||||
I have created a little Docker test setup.
|
||||
|
||||
1. Build the image: ```docker build -t simplephprouter docker/image```
|
||||
1. Build the image: `docker build -t simplephprouter docker/image`
|
||||
|
||||
2. Spin up a container
|
||||
* On Linux / Mac or Windows Powershell use: ```docker run -d -p 80:80 -v $(pwd):/var/www/html --name simplephprouter simplephprouter```
|
||||
* On Windows CMD use ```docker run -d -p 80:80 -v %cd%:/var/www/html --name simplephprouter simplephprouter```
|
||||
* On Linux / Mac or Windows Powershell use: `docker run -d -p 80:80 -v $(pwd):/var/www/html --name simplephprouter simplephprouter`
|
||||
* On Windows CMD use `docker run -d -p 80:80 -v %cd%:/var/www/html --name simplephprouter simplephprouter`
|
||||
|
||||
3. Open your browser and navigate to http://localhost
|
||||
|
||||
## Test setup with Vagrant (not longer maintained)
|
||||
There is a little Vagrant test setup. Just run ```vagrant up``` to spin up an Apache2 web server on Ubuntu. Then navigate to http://router.local after adding the machine IP to your hosts file. This test setup is not longer maintained and will probably break in the future. Use the Docker test setup instead.
|
||||
## Test setup with Vagrant (no longer maintained)
|
||||
There is a little Vagrant test setup. Just run `vagrant up` to spin up an Apache2 web server on Ubuntu. Then navigate to http://router.local after adding the machine IP to your hosts file. This test setup is no longer maintained and will probably break in the future. Use the Docker test setup instead.
|
||||
|
||||
## Themes, layouts, pages and components
|
||||
If you are interested in some basic concepts on how to build a simple PHP page using this router including themes, layouts, pages and components checkout this repo: https://github.com/steampixel/simplePHPPages
|
||||
This project will give you some ideas and basics on how to get started with no dependencies.
|
||||
This project will give you some ideas and basics on how to get started without any dependencies.
|
||||
|
||||
## Todo
|
||||
* Create demo configuration for nginx
|
||||
|
|
78
Route.php
78
Route.php
|
@ -1,6 +1,5 @@
|
|||
<?PHP
|
||||
|
||||
class Route{
|
||||
<?php
|
||||
class Route {
|
||||
|
||||
private static $routes = Array();
|
||||
private static $pathNotFound = null;
|
||||
|
@ -9,38 +8,37 @@ class Route{
|
|||
/**
|
||||
* Function used to add a new route
|
||||
* @param string $expression Route string or expression
|
||||
* @param callable $function Function to call when route with allowed method is found
|
||||
* @param callable $function Function to call if route with allowed method is found
|
||||
* @param string|array $method Either a string of allowed method or an array with string values
|
||||
*
|
||||
*/
|
||||
public static function add($expression, $function, $method = 'get'){
|
||||
array_push(self::$routes,Array(
|
||||
array_push(self::$routes, Array(
|
||||
'expression' => $expression,
|
||||
'function' => $function,
|
||||
'method' => $method
|
||||
));
|
||||
}
|
||||
|
||||
public static function pathNotFound($function){
|
||||
public static function pathNotFound($function) {
|
||||
self::$pathNotFound = $function;
|
||||
}
|
||||
|
||||
public static function methodNotAllowed($function){
|
||||
public static function methodNotAllowed($function) {
|
||||
self::$methodNotAllowed = $function;
|
||||
}
|
||||
|
||||
public static function run($basepath = '/', $case_matters = false, $trailing_slash_matters = false){
|
||||
public static function run($basepath = '/', $case_matters = false, $trailing_slash_matters = false) {
|
||||
// Parse current URL
|
||||
$parsed_url = parse_url($_SERVER['REQUEST_URI']);
|
||||
|
||||
// Parse current url
|
||||
$parsed_url = parse_url($_SERVER['REQUEST_URI']);//Parse Uri
|
||||
|
||||
if(isset($parsed_url['path']) && $parsed_url['path'] != '/'){
|
||||
if($trailing_slash_matters){
|
||||
if (isset($parsed_url['path']) && $parsed_url['path'] != '/') {
|
||||
if ($trailing_slash_matters) {
|
||||
$path = $parsed_url['path'];
|
||||
}else{
|
||||
} else {
|
||||
$path = rtrim($parsed_url['path'], '/');
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
$path = '/';
|
||||
}
|
||||
|
||||
|
@ -51,12 +49,12 @@ class Route{
|
|||
|
||||
$route_match_found = false;
|
||||
|
||||
foreach(self::$routes as $route){
|
||||
foreach (self::$routes as $route) {
|
||||
|
||||
// If the method matches check the path
|
||||
|
||||
// Add basepath to matching string
|
||||
if($basepath!=''&&$basepath!='/'){
|
||||
if ($basepath != '' && $basepath != '/') {
|
||||
$route['expression'] = '('.$basepath.')'.$route['expression'];
|
||||
}
|
||||
|
||||
|
@ -66,53 +64,47 @@ class Route{
|
|||
// Add 'find string end' automatically
|
||||
$route['expression'] = $route['expression'].'$';
|
||||
|
||||
// echo $route['expression'].'<br/>';
|
||||
|
||||
// Check path match
|
||||
if(preg_match('#'.$route['expression'].'#'.($case_matters ? '':'i'),$path,$matches)){
|
||||
|
||||
if (preg_match('#'.$route['expression'].'#'.($case_matters ? '' : 'i'), $path, $matches)) {
|
||||
$path_match_found = true;
|
||||
|
||||
// Cast allowed method to array if it's not one already, then run through all methods
|
||||
foreach ((array)$route['method'] as $allowedMethod) {
|
||||
// Check method match
|
||||
if(strtolower($method) == strtolower($allowedMethod)){
|
||||
if (strtolower($method) == strtolower($allowedMethod)) {
|
||||
array_shift($matches); // Always remove first element. This contains the whole string
|
||||
|
||||
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);
|
||||
|
||||
$route_match_found = true;
|
||||
|
||||
// Do not check other routes
|
||||
break;
|
||||
if ($basepath != '' && $basepath != '/') {
|
||||
array_shift($matches); // Remove basepath
|
||||
}
|
||||
|
||||
call_user_func_array($route['function'], $matches);
|
||||
|
||||
$route_match_found = true;
|
||||
|
||||
// Do not check other routes
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No matching route was found
|
||||
if(!$route_match_found){
|
||||
|
||||
if (!$route_match_found) {
|
||||
// But a matching path exists
|
||||
if($path_match_found){
|
||||
header("HTTP/1.0 405 Method Not Allowed");
|
||||
if(self::$methodNotAllowed){
|
||||
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){
|
||||
} else {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
if (self::$pathNotFound) {
|
||||
call_user_func_array(self::$pathNotFound, Array($path));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
131
index.php
131
index.php
|
@ -1,130 +1,113 @@
|
|||
<?PHP
|
||||
|
||||
// This function just prints a simple navigation
|
||||
function navi () {
|
||||
?>
|
||||
Navigation:
|
||||
<ul>
|
||||
<li><a href="/">home</a></li>
|
||||
<li><a href="/index.php">index.php</a></li>
|
||||
<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="/contact-form">contact form</a></li>
|
||||
<li><a href="/get-post-sample">get+post example</a></li>
|
||||
<li><a href="/test.html">test.html</a></li>
|
||||
<li><a href="/aTrailingSlashDoesNotMatters">aTrailingSlashDoesNotMatters</a></li>
|
||||
<li><a href="/aTrailingSlashDoesNotMatters/">aTrailingSlashDoesNotMatters/</a></li>
|
||||
<li><a href="/theCaseDoesNotMatters">theCaseDoesNotMatters</a></li>
|
||||
<li><a href="/thecasedoesnotmatters">thecasedoesnotmatters</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
|
||||
}
|
||||
<?php
|
||||
echo <<<EOD
|
||||
Navigation:
|
||||
<ul>
|
||||
<li><a href="/">home</a></li>
|
||||
<li><a href="/index.php">index.php</a></li>
|
||||
<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="/contact-form">contact form</a></li>
|
||||
<li><a href="/get-post-sample">get+post example</a></li>
|
||||
<li><a href="/test.html">test.html</a></li>
|
||||
<li><a href="/aTrailingSlashDoesNotMatters">aTrailingSlashDoesNotMatters</a></li>
|
||||
<li><a href="/aTrailingSlashDoesNotMatters/">aTrailingSlashDoesNotMatters/</a></li>
|
||||
<li><a href="/theCaseDoesNotMatters">theCaseDoesNotMatters</a></li>
|
||||
<li><a href="/thecasedoesnotmatters">thecasedoesnotmatters</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>
|
||||
EOD;
|
||||
|
||||
// Include router class
|
||||
include('Route.php');
|
||||
include 'Route.php';
|
||||
|
||||
// Add base route (startpage)
|
||||
Route::add('/',function(){
|
||||
navi();
|
||||
Route::add('/', function() {
|
||||
echo 'Welcome :-)';
|
||||
});
|
||||
|
||||
// Another base route example
|
||||
Route::add('/index.php',function(){
|
||||
navi();
|
||||
echo 'You are not realy on index.php ;-)';
|
||||
Route::add('/index.php', function() {
|
||||
echo 'You are not really on index.php ;-)';
|
||||
});
|
||||
|
||||
// Simple test route that simulates static html file
|
||||
Route::add('/test.html',function(){
|
||||
navi();
|
||||
// TODO: Fix this for some web servers
|
||||
Route::add('/test.html', function() {
|
||||
echo 'Hello from test.html';
|
||||
});
|
||||
|
||||
// Post route example
|
||||
Route::add('/contact-form',function(){
|
||||
navi();
|
||||
echo '<form method="post"><input type="text" name="test" /><input type="submit" value="send" /></form>';
|
||||
},'get');
|
||||
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(){
|
||||
navi();
|
||||
echo 'Hey! The form has been sent:<br/>';
|
||||
Route::add('/contact-form', function() {
|
||||
echo 'Hey! The form has been sent:<br>';
|
||||
print_r($_POST);
|
||||
},'post');
|
||||
}, 'post');
|
||||
|
||||
// Get and Post route example
|
||||
Route::add('/get-post-sample',function(){
|
||||
navi();
|
||||
Route::add('/get-post-sample', function() {
|
||||
echo 'You can GET this page and also POST this form back to it';
|
||||
echo '<form method="post"><input type="text" name="input" /><input type="submit" value="send" /></form>';
|
||||
if(isset($_POST["input"])){
|
||||
echo 'I also received a POST with this data:<br/>';
|
||||
echo '<form method="post"><input type="text" name="input"><input type="submit" value="send"></form>';
|
||||
if (isset($_POST['input'])) {
|
||||
echo 'I also received a POST with this data:<br>';
|
||||
print_r($_POST);
|
||||
}
|
||||
},['get','post']);
|
||||
}, ['get','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 (.*)
|
||||
// Also users could inject SQL statements 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){
|
||||
navi();
|
||||
echo 'Edit user with id '.$id.'<br/>';
|
||||
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){
|
||||
navi();
|
||||
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){
|
||||
navi();
|
||||
echo 'This is the first match: '.$var1.' / '.$var2.' / '.$var3.' / '.$var4.'<br/>';
|
||||
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(){
|
||||
navi();
|
||||
echo 'This is the second match <br/>';
|
||||
// TODO: Fix this; it'll get triggered
|
||||
Route::add('/foo/bar/foo/bar', function() {
|
||||
echo 'This is the second match <br>';
|
||||
});
|
||||
|
||||
// Trailing slash example
|
||||
Route::add('/aTrailingSlashDoesNotMatters',function(){
|
||||
navi();
|
||||
echo 'a trailing slash does not matters<br/>';
|
||||
Route::add('/aTrailingSlashDoesNotMatter', function() {
|
||||
echo 'a trailing slash does not matter<br>';
|
||||
});
|
||||
|
||||
// Case example
|
||||
Route::add('/theCaseDoesNotMatters',function(){
|
||||
navi();
|
||||
echo 'the case does not matters<br/>';
|
||||
Route::add('/theCaseDoesNotMatter',function(){
|
||||
echo 'the case does not matter<br>';
|
||||
});
|
||||
|
||||
// 405 test
|
||||
Route::add('/this-route-is-defined',function(){
|
||||
navi();
|
||||
Route::add('/this-route-is-defined', function() {
|
||||
echo 'You need to patch this route to see this content';
|
||||
},'patch');
|
||||
}, 'patch');
|
||||
|
||||
// Add a 404 not found route
|
||||
Route::pathNotFound(function($path){
|
||||
navi();
|
||||
echo 'Error 404 :-(<br/>';
|
||||
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){
|
||||
navi();
|
||||
echo 'Error 405 :-(<br/>';
|
||||
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!';
|
||||
});
|
||||
|
||||
|
@ -138,5 +121,3 @@ Route::run('/');
|
|||
|
||||
// Enable case sensitive mode and trailing slashes by setting both to true
|
||||
// Route::run('/', true, true);
|
||||
|
||||
?>
|
||||
|
|
Loading…
Reference in New Issue
Block a user