GithubHelp home page GithubHelp logo

steampixel / simplephprouter Goto Github PK

View Code? Open in Web Editor NEW
403.0 32.0 117.0 93 KB

This is a simple and small single class PHP router that can handel the whole url routing for your project.

License: MIT License

PHP 93.79% Dockerfile 6.21%
php php-router url-parser

simplephprouter's Introduction

Simple PHP Router ⇄

Hey! This is a simple and small single class PHP router that can handle the whole URL routing for your project. It utilizes RegExp and PHP's 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 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. 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:

// Require the class
include 'src\Steampixel\Route.php';

// Use this namespace
use Steampixel\Route;

// Add the first route
Route::add('/user/([0-9]*)/edit', function($id) {
  echo 'Edit user with id '.$id.'<br>';
}, 'get');

// Run the router
Route::run('/');

You will find a more complex example with a build in navigation in the index.php file.

🎢 Installation using Composer

Just run composer require steampixel/simple-php-router Than add the autoloader to your project like this:

// Autoload files using composer
require_once __DIR__ . '/vendor/autoload.php';

// Use this namespace
use Steampixel\Route;

// Add your first route
Route::add('/', function() {
  echo 'Welcome :-)';
});

// Run the router
Route::run('/');

β›Ί 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 too if you are on Apache2.

⏎ Use return instead of echo

You don't have to use echo to output your content. You can also use the return statement. Everything that gets returned is echoed automatically.

// Add your first route
Route::add('/', function() {
  return 'Welcome :-)';
});

β‡’ Use arrow functions

Since PHP 7.4 you can also use arrow functions to output your content. So you can easily use variables from outside and you can write shorter code. Please be aware that an Arrow function must always return a value. Therefore you cannot use echo directly in here. You can find an example in index.php. However, this is deactivated, as it only works from PHP 7.4.

Route::add('/arrow/([a-z-0-9-]*)', fn($foo) => 'This is a working arrow function example. Parameter: '.$foo );

πŸ“– Return all known routes

This is useful, for example, to automatically generate test routes or help pages.

$routes = Route::getAll();
foreach($routes as $route) {
  echo $route['expression'].' ('.$route['method'].')';
}

On top of that you could use a library like https://github.com/hoaproject/Regex to generate working example links for the different expressions.

🧰 Enable case sensitive routes, trailing slashes and multi match mode

The second, third and fourth parameters of Route::run('/', false, false, false); are set to false by default. Using this parameters you can switch on and off several options:

  • Second parameter: You can enable case sensitive mode by setting the second parameter to true.
  • Third parameter: By default the router will ignore trailing slashes. Set this parameter to true to avoid this.
  • Fourth parameter: By default the router will only execute the first matching route. Set this parameter to true to enable multi match mode.

⁉ Something does not work?

  • 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
  • Does Apache2 even load the .htaccess file? Check whether the AllowOverride All option is set in the Apache2 configuration like in this example:
<VirtualHost *:80>
    ServerName mysite.com
    DocumentRoot /var/www/html/mysite.com
    <Directory "/var/www/html/mysite.com">
        AllowOverride All
    </Directory>
</VirtualHost>

πŸš€ Pages, Templates, Themes, Components

This is a simple router. So there is no templating at all. But it works perfectly together with simplePHPComponents and simplePHPPortals. There is a complete boilerplate project including these dependencies and this router called simplePHPPages. You can use it for you next project.

πŸŽ“ What skills do you need?

Please be aware that for this router you need a basic understanding of PHP. Many problems stem from people lacking basic programming knowledge. You should therefore have the following skills:

Please note that we are happy to help you if you have problems with this router. Unfortunately, we don't have a lot of time, so we can't help you learn PHP basics.

🚒 Test setup with Docker

I have created a little Docker test setup.

  1. Build the image: docker build -t simplephprouter docker/image-php-7.2

  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
  3. Open your browser and navigate to http://localhost

πŸͺŸ Test Setup in Windows using IIS

With IIS now fully supporting PHP, this example can be run using the included web.config. The web.config has a rewrite rule, similar to the .htaccess rewrite rule, but specifically for IIS. The rewrite rule will send all incoming requests to index.php in your root. The rest is done by the simple php router.

Setup

This setup tutorial assumes you have the knowledge to create sites in IIS and set up bindings for http/https and custom DNS. If you need more information, this article will help you with that part.

  1. If you haven't done so yet, install php on windows. This article Install IIS and PHP | Microsoft Docs will guide you to install the required php dependencies on your windows machine.
  2. In IIS Manager, create a site and point the physical location to root of the simplePHPRouter folder. It is recommended you connect to the the physical location with an account that has "Read/Write" rights to that folder.
  3. (Optional) Create a DNS entry in your hosts file pointing 127.0.0.1 to the domain name you have used to set up the site.
  4. Browse to the newly created website and the sample site should display now.

βœ… Todo

  • Create demo configuration for nginx

πŸ“ƒ License

This project is licensed under the MIT License. See LICENSE for further information.

simplephprouter's People

Contributors

beopuppy avatar immaax avatar mrjk990 avatar mzaini30 avatar steampixel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

simplephprouter's Issues

How i can rewrite /api/ to api.php in htaccess

I have file api.php like that. How i setting up this on htaccess?

route::add('/test', function(){
	echo 1;
},'GET');
// Run the router
Route::run('/api');

I tried like that but doesnt work

RewriteRule ^/api/(.*)$ api.php [QSA]

Not working for php5.2

I'm calling the route class as follows

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require('./src/Route/Route.php');
Route::run('/ebilling-eis');

Route::add('/', function(){
	print('Welcome');
});

Route::add('/test', function(){
	print('Welcome Test');
});

when i go to both of these routes, a blank screen shows up without the printed string

Grouping/Sub-Route Request.

Create a group name, which becomes the Prefix for every route inside it.

Or is this already possible somehow?

Route::group('/prefix', function() {

    Route::add('/', function () {
        echo "This Route is: /prefix";
    });

    Route::add('/user', function() {
        echo "This Route is: /prefix/user";
    });
    
});

Routing to URL with query strings

Hey steampixel, is there any creative way you're dealing with routing to files with query strings appended?

e.g.
Route::add('/orders/new', function () { require_once (__DIR__ . '/views/orders.php?status=new'); });

The above example does not work of course but maybe it will help explain my issue. The require_once() and include() functions are for directly linking to a file on the filesystem, so it thinks the query string is a part of the file name, whereas the web server will interpret it as a normal query string to pass to our file in the request

Question: How to disable automatic file redirect

Hello @steampixel

In fact what I want to do is the following:
Use you router to include my header / footer / sidebar files automatically without including them on every page. For this it is crucial that every URL request passes to the index and get the right route path that is configured.

Sadly somehow this is not working when I just remove your HTACCESS rewriteConditions.

Could you provide some explanations here?

Can't access data in GET query

Hello, while trying to do

Route::add('/greet?([a-z]*)', function ($who) use($pug)
{
    echo $pug->renderFile('index.pug', [
        'title' => 'Hello ' . $who,
    ]);
});

I get only rendered 'Hello'
URL: /greet?World

haeder Problems

Hello,

first the Router is very good and easy to handle, but there is a Problem when I include a file and in this file I like to change the header to download or display a file this doesn't work, because you have to change the haeder before you output some code / HTML.
Are there any solutions for that problem?

Some ToDos are still open

Hi @mzaini30 @ImMaax @sanderaido,

inside the index.php file there are some ToDos open. Does any of you have an idea what it was about?

// Simple test route that simulates static html file
// TODO: Fix this for some web servers
Route::add('/blog/([a-z-0-9-]*)', function($slug) {
  navi();
  include('include-example.php');
});

// This example shows how to include files and how to push data to them
// TODO: Fix this for some web servers
Route::add('/test.html', function() {
  navi();
  echo 'Hello from test.html';
});

I think the second todo is my fault. Because i stupidly copied and pasted that block from the above one.

Question about Page Title and Page Description (SEO)

I really like this class. I am testing at the moment and I am successful at getting the content to appear in the body of the page, but wondering about the best method of populating the Page Title and Page Description, as I am calling the script in the body, maybe this is the wrong way.

Can anyone advise?

Managing Header code before the server is sending the default header response

hi all,

Love your router, basic but do his job very well - Congrats!

Just a question: Since your route already manage when an url isn't found in the route (error404 that we have to manage ourself), and you already manage error 503 (method not allowed)... Couldn't be awesome to manage all headers too? Per example be able the get the Header Code so we can display a proper error page (ex: error 400 Bad Request, etc.)?

thx in advance !

File protection from direct access

Hello dev.

I love using your script, im was and still am curious on how to prevent the direct access on let's say: about.php.
I am loding this page via '/about', but anytime i type the extension also, the same result view pops up!

It would be awesome if I could somehow prevent the direct access of the files, and make them accessable only via the routing system.

Best regards.

Https

When I go to my site with https, it goes to the home page as normal, but all the bottom pages cannot be called up, normal?

Missing js/css files while using double routes

Hello,
In my web project I have in the file javascripts.php all js plugins stored same as css.php for the styles. When I use this code:
Route::add('/product/([0-9]*)/edit', function($id) { require_once('product.php'); }, 'get');
The browser is looking up to the non existing folder '/product/js/owl.carousel.js'.
But indeed there is no folder called '/product/'. The real path is just '/js/owl.carousel.js'.
The same problem is happening to all included files.

localhost/myweb

how i set the site if my code in subfolder in my webserver ?

Not really a problem but a question

if i have a route like this
Route::add('member/([0-9]*)', function($v) { include('member.php'); }, ['get','post']);
i cant use var $v in member.php, how can i use it there?

Using different subdirectory

Hi, my project has the main folder with index.php file, then I would like to use the api subdirectory with an other index.php in order to manage the different routes with different files. I've tried to create the subdirectory, add an index, change the base path and write my routes. I've also add a location /app/api/ to my Nginx server configuration but it doesn't work, How can I do that? (the main routing system works perfectly)

PUT Request CORS Error

While building the middleware, I managed to do the GET, POST request but PUT request seems not to work as it should, It's showing CORS Error. Has anyone tested this case, what is the problem here!?

all routes should return the full url of the page and its title

With help of allroutes code, we need to get the entire list of routes with its full url and name or title of the page.
If we pass additional parameter title to the Route:: add and get it working with name of the link, which is fine to organize them.

How to use Views with this Router?

Hello,
I really like this Router so I used it in my project. Now I have one question:

Router::add('/login', function() {
    View::make('Login');
}, ['get','post']);

View is just a function to require a specific php file.
But how can I use the $_POST request in this file?
For example In the Login.php which is used in the /login Route, I want to process the Input made in the form.

How can I achieve this?
Greetings

Include PHP file with variables in index.php , undefined in routed pages

Hello,

The routing works, but I am having PHP variable problems when echoing from routed pages. They are undefined.

When I echo $tag_line from index.php it works, but not from home.php. Why is this?

Example of what i have:

index.php

//INC php Variables
require DIR . '/src/inc/company-info.php';
require DIR . '/config.php';

// Use this namespace
use Steampixel\Route;

// Include route class
include 'src/inc/Route.php';

// Define a global basepath
define('BASEPATH','/');

Route::add('/', function() {
require DIR . '/src/views/home.php';
});

company-info.php

$tag_line = "Demo Tag Line";

home.php

echo $tag_line;


Route to a php page

Hello, I'd like to use it for my site. I have an index.php which is a mix of html and .
so I need something like in my index.php... In the examples: there are only php function calls like echo ...;
will this work?

Route::add('/)',function(){
include index.php;
},'get');

Override all Routes/Maintenance Mode

Would it be possible to create a maintenance mode route that would over write all other routes while enabled?

Including the new route in Index.php would supersede all other routes and return whatever you want. Commenting it out, or removing would restore function of the existing routes.

Thanks for this project! Super simple to use and learn from, especially for newer developers like myself.

BasePath not working

I have the project in a subfolder and I changed the Route::run('/'); to Route::run('/myfolder'); and I also
changed the RewriteBase from / to /myfolder but its not working for me somehow...
Hope you can help thanks!

Loading a file on url

Hi.

I'm trying to get my head around your php Router.

I want to load the file /wetter.php when having the url domain.com/cityX/wetter.

So I write in index.php what exactely?

Route::add('/(.*)/wetter.php',function(){
  echo 'das wΓ€re die wetterseitewetterseite';
});

I'll then a d a test link <a href ="/cityX/wetter">Test</a>

But this doesn't work The requested URL /cityX/wetter.php was not found on this server.. What do I miss?

How to define if it's a page or an index...

Nice piece of script you got there. Great job !

just one question : How do to manage to test if the giving url must be a page or a category index. Since we must hardcode the path from the beginning ?

Example:

www.domain.com/name -> could be a page
www.domain.com/name -> could be an index of a category named 'name'

Maybe by doing a Query into the database ? If that's the case, why not just parse the url into the database to see if there is a match (of course, there's a field for the match url syntax).

Load Dynamic URL with variable

Im creating a blog plugin to work with this router.

in .htaccess
DirectoryIndex index.php

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.)$ index.php [QSA]
RewriteRule ^post/([a-z]
)$ index.php [QSA]

in index.php
Route:add('/posts/([a-z]*)', function() { $slug = $_GET['get_slug']; require 'content/plugins/blogs/blogs.php?f=read&page_slug='.$slug.''; });

What I am trying to get is the contents of that blog post.
What I am getting is a 404
Error 404 :-( The requested path "/posts/the-post-title" was not found!
Any assistance would be deeply appreciated.

Fix Route::add('/test.html') in index.php

Lines 35-39, index.php:

// Simple test route that simulates static html file
// TODO: Fix this for some web servers
Route::add('/test.html', function() {
  echo 'Hello from test.html';
});

This route isn't working on some web servers, like the PHP 7.4.1 Testing Server. The server will just search for the file in the file system instead of executing the route, even though the server has been configured correctly.

proper way of a 404 error page display

hi, really love your router, simple straight to the point.
One question tho : what's the proper way of display a 404 error page when a syntax is already filled in a Route::add() without duplicating the 404 error page procedure in the Route::pathNotFound() (ie: after validating that the $path isn't a valid page/index) ?

a was thinking of returning a special code returned from the function() but it doesnt work since it's a function created 'on the fly'.

Regards,

Apache removes all $_REQUEST, $_POST, etc

Hi,

I've setup an Api with your script. My Problem is that I can only access $_POST data via file_get_contents( 'php://input' ). The downside is that I cannot write a middleware for authentication, where I would need to access headers and cookies.

That data appears to be lost during the rewrite to index.php

Would you happen to have encountered this before? I see you reference $_POST in your samples of the route implementations. Does that mean you have overcome the issue or never faced it? What could I do to pass the contents of $_POST and $_COOKIES?

Any help is much appreciated

Optional parameters

Hi, what is the orientation if we want to use optional parameters in the route definition?
Thanks

Route not match and open folder directory

Hey @steampixel

I have a Route /app/
and a folder structur begin with /app/folder/.../

the problem is when i set a route with /app/
they will open the folder app and show all in the folder
he open everytime the folder structer if i have a route or not, thats not good

putting simplePHPRouter on packagist.org?

Hi Stempixel,

Love you class, simple and neat!
Could be a great idea to put your class on Packagist don't you thing?
Also, giving it a proper namespace could be a great idea...

Keep on your great work!

everything redirects to 404

Hey buddy, firstly thank you for this script, it's amazingly fast and compact β™₯️
I'm getting all routes returning a generic 404. I have used this script before and was working fine, however since upgrading to php 8, the mentioned problem started.

I can confirm that index.php is in the main folder and src folder are exactly where they should be.
i can also confirm that .htaccess file is exactly as described.
i can confirm that simply running this:

$routes = Route::getAll();
foreach($routes as $route) {
  echo $route['expression'].' ('.$route['method'].')';
}

print out all the routes.

but trying domain/route, returns generic 404.

any idea?
p.s. im on Apache/2.4.38 (Debian) PHP 8.0.13 with mod_rewrite enabled.

Many thanks indeed.

Hello. Now working but I have another problem.

Hello. Now working but I have another problem.
I have in index.php this code:
// Crazy route with parameters Route::add('/(.*)/(.*)/(.*)/(.*)', function($var1,$var2,$var3,$var4) { navi(); echo 'This is the first match: '.$var1.' / '.$var2.' / '.$var3.' / '.$var4.'<br>'; });
I make click on this link http://localhost/simplePHPRouter/var1/var2/var3/var4 but show error 404.

Why no show this message : "echo 'This is the first match: '.$var1.' / '.$var2.' / '.$var3.' / '.$var4.'
';" ?
Can you help me. I test on xampp.

Originally posted by @florescuadrian86 in #22 (comment)

Fix Route::add('/foo/bar/foo/bar') in index.php

Lines 80-85, index.php:

// Long route example
// This route gets never triggered because the route before matches too
// TODO: Fix this; it'll get triggered
Route::add('/foo/bar/foo/bar', function() {
  echo 'This is the second match <br>';
});

This route IS working BUT it matches a pattern which it shouldn't. Tested with PHP 7.4.1 Testing Server and Apache2.4.25

multilanguage router

Hi, how can i multi language router this class?

site.com/en
site.com/tr
site.com/fr

Setup with subfolder works fine but doesn't match base path

My project lives in /report-2019. I configured this base path both in .htaccess

RewriteBase /report-2019

and on Route start

Route::run("/report-2019")

I defined some routes, which work fine, but the "/" route triggers the pathNotFound function.

use Steampixel\Route;

// should match /report-2019/, but it doesn't
Route::add('/', function () {
  die('Welcome :-)');
});

// matches /report-2019/lorem-ipsum
Route::add('/([a-zA-Z\-0-9]+)', function ($page) {
  $_GET = [ 
    "type" => "base",
    "slug" => $page 
  ];
});

// matches /report-2019/activities/lorem-ipsum
Route::add('/activities/([a-zA-Z\-0-9]+)', function ($activity) {
  $_GET = [ 
    "type" => "activity",
    "slug" => $activity 
  ];
});

Route::pathNotFound(function () {
  echo "> > > 404 < < <";
});

Route::run("/report-2019");

Hope I'm not missing something really obvious. Thanks for any help!

Header & Footer

Hi,

Is there a way to add an include/require on every single route, without actually typing it for each route? For example, I have 10 different routes that should all include a header.php file. Looking for a wildcard route I guess to respond to all routes, and then the individual route.

Thanks!

add Route by

Hi Steampixel,

thanks a lot for your great work!

I tried to list all my routes into a .yaml-file and then call the correspondending Controller. It works as it should, but as you can see below, I have to differentiate between routes with and without variables in the expression, because the function appears not to work if there is no id oder slug or so. Like you can see, the only difference in the condition is the route value. Do you have any suggestions to simplify that? Is it also possible to use an array instead of comma-seperated values for the expression vars?

Thank you in advance and kind regards,
Ben

//[...]

public function addRoutes()
    {
        foreach ($this->routes as $route)
        {
            if($route['value'])
            {
                $this->routing->add($route['expression'], function ($id) use ($route) {
                    try {
                        return $this->runControllerMethod($route['controller'], $route['method'], $id);
                    } catch (Exception $e) {
                        return 'Exception abgefangen: '. $e->getMessage() . "\n";
                    }
                }, $route['request']);
            } else {
                $this->routing->add($route['expression'], function () use ($route) {
                    try {
                        return $this->runControllerMethod($route['controller'], $route['method']);
                    } catch (Exception $e) {
                        return 'Exception abgefangen: '. $e->getMessage() . "\n";
                    }
                }, $route['request']);
            }
        }
    }

//[...]

Fixed Navigation

Hey @ImMaax,

Fyi: I added back the navi() function to the index.php
The reason for that is that nothing should be echoed before calling the run() method of the router. In some cases it will return 404 and 405 headers. This will only work if nothing was echoed before.

I will update this with my next push.

I also had the idea to completely remove the header() calls from the class. So the users can decide on their own how to handle those cases inside the callback functions. What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.