Code Monkey home page Code Monkey logo

router's Introduction

bramus/router

Build Status Source Version Downloads License

A lightweight and simple object oriented PHP Router. Built by Bram(us) Van Damme (https://www.bram.us) and Contributors

Features

Prerequisites/Requirements

Installation

Installation is possible using Composer

composer require bramus/router ~1.6

Demo

A demo is included in the demo subfolder. Serve it using your favorite web server, or using PHP 5.4+'s built-in server by executing php -S localhost:8080 on the shell. A .htaccess for use with Apache is included.

Additionally a demo of a mutilingual router is also included. This can be found in the demo-multilang subfolder and can be ran in the same manner as the normal demo.

Usage

Create an instance of \Bramus\Router\Router, define some routes onto it, and run it.

// Require composer autoloader
require __DIR__ . '/vendor/autoload.php';

// Create Router instance
$router = new \Bramus\Router\Router();

// Define routes
// ...

// Run it!
$router->run();

Routing

Hook routes (a combination of one or more HTTP methods and a pattern) using $router->match(method(s), pattern, function):

$router->match('GET|POST', 'pattern', function() { … });

bramus/router supports GET, POST, PUT, PATCH, DELETE, HEAD (see note), and OPTIONS HTTP request methods. Pass in a single request method, or multiple request methods separated by |.

When a route matches against the current URL (e.g. $_SERVER['REQUEST_URI']), the attached route handling function will be executed. The route handling function must be a callable. Only the first route matched will be handled. When no matching route is found, a 404 handler will be executed.

Routing Shorthands

Shorthands for single request methods are provided:

$router->get('pattern', function() { /* ... */ });
$router->post('pattern', function() { /* ... */ });
$router->put('pattern', function() { /* ... */ });
$router->delete('pattern', function() { /* ... */ });
$router->options('pattern', function() { /* ... */ });
$router->patch('pattern', function() { /* ... */ });

You can use this shorthand for a route that can be accessed using any method:

$router->all('pattern', function() { … });

Note: Routes must be hooked before $router->run(); is being called.

Note: There is no shorthand for match() as bramus/router will internally re-route such requrests to their equivalent GET request, in order to comply with RFC2616 (see note).

Route Patterns

Route Patterns can be static or dynamic:

  • Static Route Patterns contain no dynamic parts and must match exactly against the path part of the current URL.
  • Dynamic Route Patterns contain dynamic parts that can vary per request. The varying parts are named subpatterns and are defined using either Perl-compatible regular expressions (PCRE) or by using placeholders

Static Route Patterns

A static route pattern is a regular string representing a URI. It will be compared directly against the path part of the current URL.

Examples:

  • /about
  • /contact

Usage Examples:

// This route handling function will only be executed when visiting http(s)://www.example.org/about
$router->get('/about', function() {
    echo 'About Page Contents';
});

Dynamic PCRE-based Route Patterns

This type of Route Patterns contain dynamic parts which can vary per request. The varying parts are named subpatterns and are defined using regular expressions.

Examples:

  • /movies/(\d+)
  • /profile/(\w+)

Commonly used PCRE-based subpatterns within Dynamic Route Patterns are:

  • \d+ = One or more digits (0-9)
  • \w+ = One or more word characters (a-z 0-9 _)
  • [a-z0-9_-]+ = One or more word characters (a-z 0-9 _) and the dash (-)
  • .* = Any character (including /), zero or more
  • [^/]+ = Any character but /, one or more

Note: The PHP PCRE Cheat Sheet might come in handy.

The subpatterns defined in Dynamic PCRE-based Route Patterns are converted to parameters which are passed into the route handling function. Prerequisite is that these subpatterns need to be defined as parenthesized subpatterns, which means that they should be wrapped between parens:

// Bad
$router->get('/hello/\w+', function($name) {
    echo 'Hello ' . htmlentities($name);
});

// Good
$router->get('/hello/(\w+)', function($name) {
    echo 'Hello ' . htmlentities($name);
});

Note: The leading / at the very beginning of a route pattern is not mandatory, but is recommended.

When multiple subpatterns are defined, the resulting route handling parameters are passed into the route handling function in the order they are defined in:

$router->get('/movies/(\d+)/photos/(\d+)', function($movieId, $photoId) {
    echo 'Movie #' . $movieId . ', photo #' . $photoId;
});

Dynamic Placeholder-based Route Patterns

This type of Route Patterns are the same as Dynamic PCRE-based Route Patterns, but with one difference: they don't use regexes to do the pattern matching but they use the more easy placeholders instead. Placeholders are strings surrounded by curly braces, e.g. {name}. You don't need to add parens around placeholders.

Examples:

  • /movies/{id}
  • /profile/{username}

Placeholders are easier to use than PRCEs, but offer you less control as they internally get translated to a PRCE that matches any character (.*).

$router->get('/movies/{movieId}/photos/{photoId}', function($movieId, $photoId) {
    echo 'Movie #' . $movieId . ', photo #' . $photoId;
});

Note: the name of the placeholder does not need to match with the name of the parameter that is passed into the route handling function:

$router->get('/movies/{foo}/photos/{bar}', function($movieId, $photoId) {
    echo 'Movie #' . $movieId . ', photo #' . $photoId;
});

Optional Route Subpatterns

Route subpatterns can be made optional by making the subpatterns optional by adding a ? after them. Think of blog URLs in the form of /blog(/year)(/month)(/day)(/slug):

$router->get(
    '/blog(/\d+)?(/\d+)?(/\d+)?(/[a-z0-9_-]+)?',
    function($year = null, $month = null, $day = null, $slug = null) {
        if (!$year) { echo 'Blog overview'; return; }
        if (!$month) { echo 'Blog year overview'; return; }
        if (!$day) { echo 'Blog month overview'; return; }
        if (!$slug) { echo 'Blog day overview'; return; }
        echo 'Blogpost ' . htmlentities($slug) . ' detail';
    }
);

The code snippet above responds to the URLs /blog, /blog/year, /blog/year/month, /blog/year/month/day, and /blog/year/month/day/slug.

Note: With optional parameters it is important that the leading / of the subpatterns is put inside the subpattern itself. Don't forget to set default values for the optional parameters.

The code snipped above unfortunately also responds to URLs like /blog/foo and states that the overview needs to be shown - which is incorrect. Optional subpatterns can be made successive by extending the parenthesized subpatterns so that they contain the other optional subpatterns: The pattern should resemble /blog(/year(/month(/day(/slug)))) instead of the previous /blog(/year)(/month)(/day)(/slug):

$router->get('/blog(/\d+(/\d+(/\d+(/[a-z0-9_-]+)?)?)?)?', function($year = null, $month = null, $day = null, $slug = null) {
    // ...
});

Note: It is highly recommended to always define successive optional parameters.

To make things complete use quantifiers to require the correct amount of numbers in the URL:

$router->get('/blog(/\d{4}(/\d{2}(/\d{2}(/[a-z0-9_-]+)?)?)?)?', function($year = null, $month = null, $day = null, $slug = null) {
    // ...
});

Subrouting / Mounting Routes

Use $router->mount($baseroute, $fn) to mount a collection of routes onto a subroute pattern. The subroute pattern is prefixed onto all following routes defined in the scope. e.g. Mounting a callback $fn onto /movies will prefix /movies onto all following routes.

$router->mount('/movies', function() use ($router) {

    // will result in '/movies/'
    $router->get('/', function() {
        echo 'movies overview';
    });

    // will result in '/movies/id'
    $router->get('/(\d+)', function($id) {
        echo 'movie id ' . htmlentities($id);
    });

});

Nesting of subroutes is possible, just define a second $router->mount() in the callable that's already contained within a preceding $router->mount().

Class@Method calls

We can route to the class action like so:

$router->get('/(\d+)', '\App\Controllers\User@showProfile');

When a request matches the specified route URI, the showProfile method on the User class will be executed. The defined route parameters will be passed to the class method.

The method can be static (recommended) or non-static (not-recommended). In case of a non-static method, a new instance of the class will be created.

If most/all of your handling classes are in one and the same namespace, you can set the default namespace to use on your router instance via setNamespace()

$router->setNamespace('\App\Controllers');
$router->get('/users/(\d+)', 'User@showProfile');
$router->get('/cars/(\d+)', 'Car@showProfile');

Custom 404

The default 404 handler sets a 404 status code and exits. You can override this default 404 handler by using $router->set404(callable);

$router->set404(function() {
    header('HTTP/1.1 404 Not Found');
    // ... do something special here
});

You can also define multiple custom routes e.x. you want to define an /api route, you can print a custom 404 page:

$router->set404('/api(/.*)?', function() {
    header('HTTP/1.1 404 Not Found');
    header('Content-Type: application/json');

    $jsonArray = array();
    $jsonArray['status'] = "404";
    $jsonArray['status_text'] = "route not defined";

    echo json_encode($jsonArray);
});

Also supported are Class@Method callables:

$router->set404('\App\Controllers\Error@notFound');

The 404 handler will be executed when no route pattern was matched to the current URL.

💡 You can also manually trigger the 404 handler by calling $router->trigger404()

$router->get('/([a-z0-9-]+)', function($id) use ($router) {
    if (!Posts::exists($id)) {
        $router->trigger404();
        return;
    }

    // …
});

Before Route Middlewares

bramus/router supports Before Route Middlewares, which are executed before the route handling is processed.

Like route handling functions, you hook a handling function to a combination of one or more HTTP request methods and a specific route pattern.

$router->before('GET|POST', '/admin/.*', function() {
    if (!isset($_SESSION['user'])) {
        header('location: /auth/login');
        exit();
    }
});

Unlike route handling functions, more than one before route middleware is executed when more than one route match is found.

Before Router Middlewares

Before route middlewares are route specific. Using a general route pattern (viz. all URLs), they can become Before Router Middlewares (in other projects sometimes referred to as before app middlewares) which are always executed, no matter what the requested URL is.

$router->before('GET', '/.*', function() {
    // ... this will always be executed
});

After Router Middleware / Run Callback

Run one (1) middleware function, name the After Router Middleware (in other projects sometimes referred to as after app middlewares) after the routing was processed. Just pass it along the $router->run() function. The run callback is route independent.

$router->run(function() { … });

Note: If the route handling function has exit()ed the run callback won't be run.

Overriding the request method

Use X-HTTP-Method-Override to override the HTTP Request Method. Only works when the original Request Method is POST. Allowed values for X-HTTP-Method-Override are PUT, DELETE, or PATCH.

Subfolder support

Out-of-the box bramus/router will run in any (sub)folder you place it into … no adjustments to your code are needed. You can freely move your entry script index.php around, and the router will automatically adapt itself to work relatively from the current folder's path by mounting all routes onto that basePath.

Say you have a server hosting the domain www.example.org using public_html/ as its document root, with this little entry script index.php:

$router->get('/', function() { echo 'Index'; });
$router->get('/hello', function() { echo 'Hello!'; });
  • If your were to place this file (along with its accompanying .htaccess file or the like) at the document root level (e.g. public_html/index.php), bramus/router will mount all routes onto the domain root (e.g. /) and thus respond to https://www.example.org/ and https://www.example.org/hello.

  • If you were to move this file (along with its accompanying .htaccess file or the like) into a subfolder (e.g. public_html/demo/index.php), bramus/router will mount all routes onto the current path (e.g. /demo) and thus repsond to https://www.example.org/demo and https://www.example.org/demo/hello. There's no need for $router->mount(…) in this case.

Disabling subfolder support

In case you don't want bramus/router to automatically adapt itself to the folder its being placed in, it's possible to manually override the basePath by calling setBasePath(). This is necessary in the (uncommon) situation where your entry script and your entry URLs are not tightly coupled (e.g. when the entry script is placed into a subfolder that does not need be part of the URLs it responds to).

// Override auto base path detection
$router->setBasePath('/');

$router->get('/', function() { echo 'Index'; });
$router->get('/hello', function() { echo 'Hello!'; });

$router->run();

If you were to place this file into a subfolder (e.g. public_html/some/sub/folder/index.php), it will still mount the routes onto the domain root (e.g. /) and thus respond to https://www.example.org/ and https://www.example.org/hello (given that your .htaccess file – placed at the document root level – rewrites requests to it)

Integration with other libraries

Integrate other libraries with bramus/router by making good use of the use keyword to pass dependencies into the handling functions.

$tpl = new \Acme\Template\Template();

$router->get('/', function() use ($tpl) {
    $tpl->load('home.tpl');
    $tpl->setdata(array(
        'name' => 'Bramus!'
    ));
});

$router->run(function() use ($tpl) {
    $tpl->display();
});

Given this structure it is still possible to manipulate the output from within the After Router Middleware

A note on working with PUT

There's no such thing as $_PUT in PHP. One must fake it:

$router->put('/movies/(\d+)', function($id) {

    // Fake $_PUT
    $_PUT  = array();
    parse_str(file_get_contents('php://input'), $_PUT);

    // ...

});

A note on making HEAD requests

When making HEAD requests all output will be buffered to prevent any content trickling into the response body, as defined in RFC2616 (Hypertext Transfer Protocol -- HTTP/1.1):

The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request. This method can be used for obtaining metainformation about the entity implied by the request without transferring the entity-body itself. This method is often used for testing hypertext links for validity, accessibility, and recent modification.

To achieve this, bramus/router but will internally re-route HEAD requests to their equivalent GET request and automatically suppress all output.

Unit Testing & Code Coverage

bramus/router ships with unit tests using PHPUnit.

  • If PHPUnit is installed globally run phpunit to run the tests.

  • If PHPUnit is not installed globally, install it locally throuh composer by running composer install --dev. Run the tests themselves by calling vendor/bin/phpunit.

    The included composer.json will also install php-code-coverage which allows one to generate a Code Coverage Report. Run phpunit --coverage-html ./tests-report (XDebug required), a report will be placed into the tests-report subfolder.

Acknowledgements

bramus/router is inspired upon Klein, Ham, and JREAM/route . Whilst Klein provides lots of features it is not object oriented. Whilst Ham is Object Oriented, it's bad at separation of concerns as it also provides templating within the routing class. Whilst JREAM/route is a good starting point it is limited in what it does (only GET routes for example).

License

bramus/router is released under the MIT public license. See the enclosed LICENSE for details.

router's People

Contributors

acicali avatar artyuum avatar bramus avatar cheeseq avatar cikal avatar ilyafreer avatar jbleuzen avatar kedniko avatar khromov avatar luisrock avatar matthew-e-brown avatar mcecode avatar mjoris avatar ovflowd avatar planetthecloud avatar shanemcc avatar terah avatar tleb avatar uvulpos 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  avatar  avatar  avatar  avatar  avatar  avatar

router's Issues

Too many redirects

If we take the following code:

$router->before('GET', '/.*', function() {
    if (!isset($_SESSION['user'])) {
        header('location: /login');
        exit();
    }
});

How would one stop a redirect loop when '/login' is requested?

Any way to verify if a route is valid?

I'm hoping to be able to securely implement a redirector (ie /blah?redirect=/some/path/ type stuff). To do it securely, I need to validate if the redirect path is a valid route (doesn't start http:// or https://, and ideally is a valid route that doesn't return a 404). Is there any way to do this currently? It looks like everything is currently protected/private. If not, any chance I could get a few pointers in the right direction, and I'll work on creating a pull request?

Handle HEAD request

I see you have the standard request types, but in a monitoring / load balancer situation 'HEAD' requests are quite commonly used and need to be handled by the router.

By what I can see all you are supposed to do is send the response header back, never a body.

From what I can see I should be able to add a HEAD route into the system but I thought I should mention it.

Ability to set a different 404 handler based on the subroute

Hi,
example :

// Create Router instance
$router = new \Bramus\Router\Router();

// Set the default namespace for all controllers
$router->setNamespace('\App\Controllers');

// Define routes
$router->mount('/website', function() use ($router) {

    $router->set404('ErrorController@notFoundWebsite');

    $router->get('/', 'WebsiteController@index');

});

$router->mount('/api', function() use ($router) {

    $router->set404('ErrorController@notFoundApi');

    $router->get('/posts', 'ApiController@posts');
    $router->get('/posts/(\d+)', 'ApiController@post');

});

// Run it!
$router->run();

In this example, in case of error 404 for the api subroute, a JSON response will be returned.
For the website subroute, a simple HTML page will be returned.

Thanks for your time.

how to allow patterns with dot to work

Hi
I cant get patterns with dots to work. For example
/files/main_logo.jpg
does not work due to the dot. I have tried ([A-Za-z0-9-_/.]+), ([^/]) and a few others
but they don't work

No support CLI!

😭

PHP Notice:  Undefined index: REQUEST_METHOD in E:\...\vendor\bramus\router\src\Bramus\Router\Router.php on line 216
PHP Stack trace:
PHP   1. {main}() E:\...\web\xx\index.php:0
PHP   2. Bramus\Router\Router->run() E:\...\web\xx\index.php:234
PHP   3. Bramus\Router\Router->getRequestMethod() E:\...\vendor\bramus\router\src\Bramus\Router\Router.php:243

...

Regulation start from N segment

Need discussion about using this class in multilingual site, assumed domain.com will be redirect to domain.com/en (in english) and domain.com/id (in indonesia)

// domain.com/en/ or domain.com/id/
define('DOMAIN', app('domain') . '/' . Session::get('language', app('language')) . '/');

// detect segment
function segment($segment = null)
{
    $path = implode('/', array_slice(explode('/', $_SERVER['SCRIPT_NAME']), 0, -1)) . '/';
    $uri = mb_substr($_SERVER['REQUEST_URI'], mb_strlen($path));

    $trim = trim($uri, '/');
    $data = mb_strpos($trim, '/') ? explode('/', $trim) : [$trim];

    if (is_null($segment)) {
        return $data;
    }

    return $segment <= count($data) ? $data[$segment - 1] : '';
}

// print_r(segment()); : domain.com/en/title -> array([0] => en [1] => title)
$router = new \Bramus\Router\Router();

// before route middleware
$router->before('GET', '/(.*)', function($slug) {
    if (in_array(segment(1), ['en', 'id'])) {
        Session::set('language', segment(1));
    } else {
        redirect(DOMAIN . $slug);
    }
});

$router->all('/(.*)', function($slug) {
    echo $slug;
});

When i call domain.com/en/title, i expect $slug = 'title'; not $slug = 'en';

Actually using $router->mount($baseroute, $fn) this issue completed

$router->mount('/'. segment(1), function() use ($router) {
    $router->all('/(.*)', function($slug) {
        echo $slug;
    });
});

But i looking for some regulation to start from N segment, something like $route->startfromsegment = 1;

Any other idea ? or mount a collection is a right way ?

Before middleware inside mount() that works for / and /.*

Hey,

let's say I have the following route :

$router->get('/', 'HomepageController@index');

I would like to use the before route middleware to restrict non-logged in users from accessing the website. So I did this :

$router->before('GET', '/.*', 'AuthController@login');

The problem is that this doesn't work for the '/' route, but '/blablabla' for example.

Is there a subpattern or something else that allows my application to restrict non-logged in users using before route middleware in 1 single line rather than doing like this ?

$router->before('GET', '/', 'AuthController@login');
$router->before('GET', '/.*', 'AuthController@login');

My idea would be to add a before route middleware to the mount() method so all routes inside this method will call first AuthController@login.

How to register After Router Middleware / Run Callback before calling $router->run()

Hi
First:
Is it possible to add After Router Middleware earlier before actually calling $router->run()
If not please provide a method for doing so. I will suggest something like this or similar
$router->addAfterCallback($callback = null)
// do other stuff with router ...
//finally
$router->run()

Secondly:
The After Router callback could accept an array of callables to run since we might want to run a list of callbacks or middlewares not just one.
We could then modify the above method as such:

$router->setAfterCallback(array $callback = array())

We can then execute in the run method as such:
see line 296
} // If a route was handled, perform the finish callback (if any) else { if ($callback && is_callable($callback)) { $callback(); } }

becomes:
} // If a route was handled, perform the finish callback (if any) else { foreach ($this->callbacks as $callback) { if ($callback && is_callable($callback)) { $callback(); } } }
thanks

$_POST problem

$_POST is not working. I can't retrieve post variable with that or not even $_REQUEST.
$router->post('/', function () { ; });
Let me know, how to detect post variables?
Like if I wanna get the value of $_POST['Key'] or wanna see all the key, value of $_POST; what to do?

Conditional Route Pattern

This is a feature request, but not sure if it is possible or beneficial. Would it be possible to add a conditional route pattern?

// Require composer autoloader
require __DIR__ . '/vendor/autoload.php';
// Create Router instance
$router = new \Bramus\Router\Router();
// Conditional GET
$router->get([ '/users/', '/users/(\w+)/' ], function() { /* ... */ });

In the GET example above, it is conditional based on number of records and page offset to determine if there is pagination. If its the first page, then return /users/. If we navigate to the second page, then the pattern would match /users/2/. Again, I don't know if this is possible, but would love to see this feature.

Domain/subdomain routing feature

Hi,

is there any chance for this feature to be implemented in a near future ?

Simple example :

$router->mount(['domain' => 'website.com'], function() use ($router) {
    $router->get('/', 'HomepageController@index');
});

$router->mount(['domain' => 'api.website.com'], function() use ($router) {
    $router->get('/', 'ApiController@index');
});

This would be so useful and less redundant for my projects to have one single project folder for the website and the api rather than having 2 seperates project folder for each sub domains/domains.

Thanks.

Returning false runs controller method twice

I couldn't find anything mentioned about this in the documentation. Returning false from a controller method will cause it to be run twice.

For example, this route:

$router->get('/account', '\Controller\Test@method');

With this class:

Class Test {
    function method(){
        echo 'hello';
        return false;
    }
}

Will produce the output: hellohello

The reason for this is line #391:
https://github.com/bramus/router/blob/master/src/Bramus/Router/Router.php#L391

PHP's "call_user_func_array" returns the return value of the callback or FALSE on error.

Get parameters in mount function

My domains are structured like this to server different language versions of the same page:
example.com/nl/page-1 and example.com/en/page-1 for the same url in different languages.

My code looks like this:

$router->mount('/(\w+)', function($lang) use ($router){ // wrap in lang-var
    echo $lang;
        
    $router->get('/page-1', function() {
        // code
    });
        
    $router->get('/page-2', function() {
        // code
    });
});

But it gives me the following error:
Warning: Missing argument 1 for {closure}() in [path]/routes.php on line 13

Is there a way to get the baseroute in a variable here?

Cyrillics issue

Hi guys,

I have a website with Cyrillic text slugs. For example: domain.com/bg/това-е-слъг
Currently the router does not work on Cyrillic text. So I had to change your code in Route.php, 341row:

$route['pattern'] = preg_replace('/{([A-Za-z]*?)}/', '(\w+)', $route['pattern']);

to

$route['pattern'] = preg_replace('/{([A-Za-zа-яА-Я]*?)}/', '(\w+)', $route['pattern']);

I hate changing original code and it's not the best solution, so maybe you can do something about the cyrillics in the next push.

Thank you!

Troubleshooting non-matches ?

Hi,

I'm really struggling to get bramus/router to work on my setup (NGINX + PHP7), I have no problems at all with aura/router, but nothing I do seems to get bramus to match ! The only reason I'm being forced to use bramus is because of your support for "before" which aura doesn't.

What is the recommended methodology to troubleshoot the route matching process ? The bramus docs seem to make no mention of this, they simply assume everything "just works".

Thanks !

Get ID from watch.php?id=123abc

Hello,

How can I do something like this?
http://mydomain.com/watch.php?id=123abc I want to get the $id.

I tried the code below but it didn't work

$router->get('/watch.php?id=(\w+)', function($id) {
    echo $id;
});

I want to use this route method as an alternative.

how to get which route is run?

Let's say I have twenty routes in my project, and I want to log every request with the route. Currently, I do

$bramus->all("/user/{id}", function () {
  logRequest("/user/{id]")
}

Of course this is grossly oversimplified. I would like to not have to send the route as a parameter and get it from bramus/router. I added $this->runRoutes[] = $route["pattern"]; to the handle() function and this is enough at the moment but I would like to know if there is already a way to get a list of matching (and running) routes from bramus/router.

Inheritance.

Please make the handle classes and other classes override-able but using protected methods instead of private.

example:
private function handle(...){ }

Cannot be overridden from a child. Make it
protected function handle(...){ }

Regexp to match the whole route not working as expected

Hi,
After reading you doc I found the following :

.* = Any character (including /), zero or more

But I have been playing with tests and I ma having trouble to understand if the following is valid or invalid...

public function testDynamicRouteValidOrNot() {

  // Create Router
  $router = new \Bramus\Router\Router();
  $router->get('/(.*)', function($name) {
      echo 'Hello ' . $name;
      });

  // Test the /hello/bramus route
  ob_start();
  $_SERVER['REQUEST_URI'] = '/hello/bramus';
  $router->run();
  $this->assertEquals('Hello hello/bramus', ob_get_contents());

  // Cleanup
  ob_end_clean();
}

I'm expecting to get the whole request but when I launch the test it fails with the following error :

Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'Hello hello/bramus'
+'Hello hello'

So here is my question, is it a bug ? Or did I misread documentation ?

And thanks by the way for router.

dont return /

And how to get with slash?

$router->get('/catalog/(.*)', function ($hurl){
return $hurl;
})

/catalog/televizoryi/
return televizoryi

/catalog/televizoryi
return televizoryi

:(

Global/Other Function marging

I'm having some problem with other functions. Let me show some code:
Type 1:

$router = new Router;
$router->post('/.*', function ($id) {
		if(isset($_POST['vid'])&&sizeof($_POST['vid'])>0){
			$ga = new App();
			$checkResult = $ga->verify($_POST['vid']);
			if($checkResult)echo 'Done!'; //$checkresult is local
		}
	});
$router->mount('/currency', function () use ($router) {
	$router->get('/', function () {
		if($checkResult)echo 'Done!';//$checkresult will not work here as its local
	});
});
$router->run();

Type 2:

$router = new Router;
$ga = new App();//generates error
$checkResult=false;//generates error

$router->post('/.*', function ($id) {
		if(isset($_POST['vid'])&&sizeof($_POST['vid'])>0){
			$checkResult = $ga->verify($_POST['vid']);//won't work
			if($checkResult)echo 'Done!';//won't work
		}
	});
$router->mount('/currency', function () use ($router) {
	$router->get('/', function () {
		if($checkResult)echo 'Done!';////won't work
	});
});
$router->run();

On a page I'm trying to verify user input with password. Trying to make it global. So, anybody who knows the password can execute all the functions. Tried the above ways but failed.

Add all Required Error Codes

  1. 301 Moved Permanently
  2. 302 Moved Temporarily
  3. 400 Bad Request
  4. 401 Authorization Required
  5. 403 Forbidden
  6. 404 Not Found (Only this is currently in the code)
  7. 405 Method Not Allowed
  8. 408 Request Timed Out
  9. 415 Unsupported Media Type
  10. 500 Internal Server Error
  11. 501 Not Implemented
  12. 502 Bad Gateway
  13. 503 Service Unavailable
  14. 504 Gateway Timeout
  15. 505 HTTP Version Not Supported
    Though some of them only implementable through htaccess only!

Method to call hooked routes (subrequest)

It would be extremely useful to be able to call a hooked route given an HTTP method and path.

For example:

$router->get('/hello/(\w+)', function ($name) {
    echo "Hello $name";
});

$router->call('GET', '/hello/Tyler'); // should echo "Hello Tyler"

The call method should work without having to do $router->run() first.
This would provide similar functionality to the subRequest() method in Slim 3 and Silex.

IMO it is an appropriate responsibility of the router to provide such a functionality as the router handles the pattern matching and callbacks.
Alternatively you can provide a getter method to return the contents of $afterRoutes to make it possible to implement such functionality in applications using this library.

Return route result

When executing the route function in Router::run method, it would be really helpful if the result of route function was available outside of run method. For instance, I was expecting to be able to

$response = $router->run();

This will allow me to implement a default view behaviour for controllers. Here is an example

$router->get('/hello/(w+)', function($name) {
  return 'Hi '. $name;
});

Or even to return a result array

$router->get('/api/users', function() { 
   return $users->findAll();
});

http/https in routes?

is it possible to have following route format /browse/1511857497/http://google.com/ or /browse/http://google.com/1511857497 (in this case timestamp is a separate entity)?

subfolder issue

I'm having a problem using bramus\router in subfolder, like that #13. The issue comes from getBasePath method, if I remove the one, the issue is fixed.

Getting a 404 header on every route

I've tried removing every route except for the homepage (which calls in a controller method), the page displays fine but looking in Chrome Inspector it's saying the status code is 404...

My index.php

<?php
	require __DIR__.'/../config.php'; //Various configs
	require __DIR__.'/../app/autoload.php'; //Loading in the Controllers and also the Bramus Router
	
	$router = new \Routing\Router();

	$router->get('/', '\app\Controllers\HomeController@display'); // The "display" method on here is just echoing "Hello World" right now

	$router->run();
?>

My .htaccess

# Charset
	AddDefaultCharset UTF-8

# Error pages
	ErrorDocument 404 /404.php
	ErrorDocument 500 /500.php

#  Redirect to router
	RewriteEngine on
	RewriteRule ^([^/]*)(.*)$ index.php

Is this something I've done wrong?

header() not working

whene i use header() function after the router it's doesnt work for example after i login and i check that i am logged in i want to redirect to the admin panels but it's doest work

serverBasePath

Hmmm...

I'm not too keen on your prescribed base path. If I don't set one (and your class doesn't seem to provide a "setter" for $this->serverBasePath !!), I don't think you should be making assumptions ?

Case in point is that on NGINX, your class ends up setting moving goalposts.

A PHP script with "implode('/', array_slice(explode('/', $_SERVER['SCRIPT_NAME']), 0, -1)) . '/';" will print /demo/hello/ for a URL suffix /demo/hello/x and /demo/ for URL suffix /demo/.

This is when NGINX is configured in-line with their recommended methods (http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files)

    location /me {
        try_files $uri @mystuff;
    }
    location @mystuff {
        fastcgi_param SCRIPT_FILENAME /path/to/mystuff.php;
        fastcgi_param SCRIPT_NAME /mystuff.php;
        fastcgi_param  PATH_INFO        $fastcgi_path_info;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_param QUERY_STRING    $args;
        include fastcgi_params;
    }

Changing
fastcgi_param SCRIPT_NAME /mystuff.php;
to
fastcgi_param SCRIPT_NAME /me/;

Has no effect.

Object not found Error 404

edit: sry everything is fine, I messed something up, thanks for your awesome script, merry Christmas and please ignore this

subfolder issue

I am having problems using bramus/router in a subfolder, I do not know if it is coming from me or a class problem:

$ mkdir router-test
$ cd router-test
$ composer require bramus/router
$ touch .htaccess
$ mkdir folder
$ touch folder/.htaccess
$ touch index.php

.htaccess:

RewriteEngine On
RewriteRule ^(.*)$ folder/$1 [L]

folder/.htaccess:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]

folder/index.php:

<?php

require '../vendor/autoload.php';

$router = new \Bramus\Router\Router;

$router->get('/about', function() {
    echo 'about page';
});

$router->run();

If I call domain.com/path/to/router-test/about, nothing happens.

POST variable

How I can call POST variable domain in $router->post callback?

$router->post("/login", function () {

});

<form action="login" method="post">
    <input type="text" name="domain">
    <input type="submit" value="Odoslať formulár">
</form>

Router always redirect to /

Hi, I installed the router
But after installing with composer, the router doesn't work, when calling "/" route it work properly but calling "/test" or whatever even wrong routes doesn't work it always redirect to "/" route.

My .htaccess

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]

My index.php

<?php
	ini_set('display_errors', 1);
	ini_set('display_startup_errors', 1);
	error_reporting(E_ALL);
	
	require __DIR__.'/../app/system.php';

	require_once __DIR__.'/../vendor/autoload.php';

	$app = new \App\Application($debug = true);

	require __DIR__.'/../app/routes.php';

	$app->run();

Route.php

<?php

$app->get('/', function () use ($app) {
	echo "Coming soon";
});

$app->get('/aze', function () use ($app) {
	echo "test";
});


$app->mount('/test', function () use ($app) {
	$app->router('test'); // include test routes
});

$app->set404(function () use ($app) {
    echo "404 error";
});

Thanks for the help

Match function doesn't work (404 error)

Hi,

created a route for my contact page

$app->match('GET|POST','/contact', function () use ($app) {
	$app->render(['src' => 'contact', 'views' => 'contact']);
});

and I get 404 error when trying GET or POST method on localhost/contact.

Other functions work fine

Im using this atm:

$app->mount('/contact', function () use ($app) {
	$app->get('/', function () use ($app) {
		$app->render(['src' => 'contact','views' => 'contact'], ['title' => 'Me contacter']);
	});

	$app->post('/validate', function () use ($app) {
		$app->render(['src' => 'contact','views' => 'contact'], ['title' => 'Me contacter']);
	});
});

Thanks for help

Router class not autoloading under Linux

Hi,

I had a problem with the Router class not autoloading under Linux (tested on Ubuntu 12.10, 32-bit). The issue was resolved by renaming src/Bramus/Router/router.php to src/Bramus/Router/Router.php. Something with case-sensitivity obviously.

Disclaimer: I have not programmed PHP for years & years and the autoloading stuff is all quite new to me, so maybe it's me who has done something wrong?

Installed using Composer via composer.json (requiring "bramus/router": "dev-master"). Composer generated the following line in vendor/composer/autoload_namespaces.php, which seems correct: 'Bramus' => $vendorDir . '/bramus/router/src'.
My index.php contains require_once 'vendor/autoload.php';
Then then namespace is imported: use \Bramus\Router\Router;
And finally a class instance is created using: $router = new Router();

It all works now, but when I change the Router class' file name back to router.php instead of Router.php, it does not get loaded anymore again.

Could you look into this or tell me what I am doing wrong? Thanks!

Integration with other libraries when using Class@Method calls

Hi, as the title says, how can I use external variables inside the method's class? The only 2 solutions I can imagine are:

  • to use global $tpl; call inside the method.
  • to use: $router->get('/', function() use ($tpl) { $c = new \App\Controllers\User($tpl); $c->showProfile(); });

There are any other option?

Some more Advanced Feature!

Can we add those 2 things direct into the Router; I think it will be good.

public static function validate($input, $filter = false)   {
		if($filter=='boolean')$variable = filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
		elseif($filter=='email')$variable = filter_var($input, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE);
		elseif($filter=='float')$variable = filter_var($input, FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE);
		elseif($filter=='int')$variable = filter_var($input, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
		elseif($filter=='ip')$variable = filter_var($input, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE);
		elseif($filter=='regexp')$variable = filter_var($input, FILTER_VALIDATE_REGEXP, FILTER_NULL_ON_FAILURE);
		elseif($filter=='url')$variable = filter_var($input, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
		else $variable = filter_var($input);
		return $variable;
    }
public static function sanitize($input, $filter = false) {
		if($filter=='email')$variable = filter_var($input, FILTER_SANITIZE_EMAIL);
		elseif($filter=='encoded')$variable = filter_var($input, FILTER_SANITIZE_ENCODED);
		elseif($filter=='magic_quotes')$variable = filter_var($input, FILTER_SANITIZE_MAGIC_QUOTES);
		elseif($filter=='float')$variable = filter_var($input, FILTER_SANITIZE_NUMBER_FLOAT);
		elseif($filter=='int')$variable = filter_var($input, FILTER_SANITIZE_NUMBER_INT);
		elseif($filter=='special')$variable = filter_var($input, FILTER_SANITIZE_SPECIAL_CHARS);
		elseif($filter=='full_special')$variable = filter_var($input, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
		elseif($filter=='string')$variable = filter_var($input, FILTER_SANITIZE_STRING);
		elseif($filter=='url')$variable = filter_var($input, FILTER_SANITIZE_URL);
		else $variable = filter_var($input);
		return $variable;
    } 

Erro in mount

I encountered a routing error when I set up a routing group.
Example:

$router->mount('/exemple', function() use ($router) {
    $router->get('/(\d+)', function($id) {
        $controll->method($id);
    });
});

On the first run I'm redirected to the 404 error page with uri without the parameter.
Example:

I requirement:
http://mysite.dev/exemple/1

I get:
http://mysite.dev/exemple/

How define route name

I want use route name and using in template. Like laravel route system.

like this;
Route::get("/path/{id}", "controller")->name("routeName");

in Template;
route("routename", ["id" => 1]);

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.