PHPackages                             sdidev/router - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. sdidev/router

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

sdidev/router
=============

A lightweight and simple object oriented PHP Router

1.2.3(10y ago)0325MITPHPPHP &gt;=5.3.0

Since Feb 4Pushed 10y ago2 watchersCompare

[ Source](https://github.com/sdicgdev/router)[ Packagist](https://packagist.org/packages/sdidev/router)[ Docs](https://github.com/bramus/router)[ RSS](/packages/sdidev-router/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (3)Versions (7)Used By (0)

bramus/router
=============

[](#bramusrouter)

[![Build Status](https://camo.githubusercontent.com/4700d3503f92f6b186e7d277be2684ce1a36836ef9c4d68e246ba525e67ce995/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f6272616d75732f726f757465722e7376673f7374796c653d666c61742d737175617265)](http://travis-ci.org/bramus/router) [![Source](https://camo.githubusercontent.com/edaf1ef1602a5c57018e5356232994591b148253caabf243ed7d60625ab91e14/687474703a2f2f696d672e736869656c64732e696f2f62616467652f736f757263652d6272616d75732f726f757465722d626c75652e7376673f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/edaf1ef1602a5c57018e5356232994591b148253caabf243ed7d60625ab91e14/687474703a2f2f696d672e736869656c64732e696f2f62616467652f736f757263652d6272616d75732f726f757465722d626c75652e7376673f7374796c653d666c61742d737175617265) [![Version](https://camo.githubusercontent.com/80ff90ce89f5454e872a2040a632ea0853e37283cf52c0cdbea2ca9637c1bd38/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6272616d75732f726f757465722e7376673f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/80ff90ce89f5454e872a2040a632ea0853e37283cf52c0cdbea2ca9637c1bd38/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6272616d75732f726f757465722e7376673f7374796c653d666c61742d737175617265) [![Downloads](https://camo.githubusercontent.com/cf4f808df013571eb95c502944bbc6b548e14e1558d81d6992caf953b62e92a2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6272616d75732f726f757465722e7376673f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/cf4f808df013571eb95c502944bbc6b548e14e1558d81d6992caf953b62e92a2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6272616d75732f726f757465722e7376673f7374796c653d666c61742d737175617265) [![License](https://camo.githubusercontent.com/b421b89049dad6b712e371d443cd25269c661f36171b998aa8d492f041b1a138/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6272616d75732f726f757465722e7376673f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/b421b89049dad6b712e371d443cd25269c661f36171b998aa8d492f041b1a138/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6272616d75732f726f757465722e7376673f7374796c653d666c61742d737175617265)

A lightweight and simple object oriented PHP Router. Built by Bram(us) Van Damme -

Features
--------

[](#features)

- Static Route Patterns
- Dynamic Route Patterns
- Optional Route Subpatterns
- Supports `GET`, `POST`, `PUT`, `DELETE`, `OPTIONS`, `PATCH` and `HEAD` request methods
- Supports `X-HTTP-Method-Override` header
- Subrouting
- Custom 404 handling
- Before Route Middlewares
- Before Router Middlewares
- After Router Middleware (Finish Callback)
- Works fine in subfolders

Prerequisites/Requirements
--------------------------

[](#prerequisitesrequirements)

- PHP 5.3 or greater
- [URL Rewriting](https://gist.github.com/bramus/5332525)

Installation
------------

[](#installation)

Installation is possible using Composer

```
composer require bramus/router ~1.0

```

Demo
----

[](#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.

Usage
-----

[](#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

[](#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`, `DELETE`, and `OPTIONS` HTTP request methods. Pass in a single request method, or multiple request methods separated by `|`.

When a route matches, the attached **route handling function** will be executed. The route handling function must be a [callable](http://php.net/manual/en/language.types.callable.php). Only the first route matched will be handled. When no matching route is found, an `'HTTP/1.1 404 Not Found'` status code will be returned.

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() { /* ... */ });
```

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

### Route Patterns

[](#route-patterns)

Route patterns can be static or dynamic.

- **Static Route Patterns** are essentially URIs, e.g. `/about`.
- **Dynamic Route Patterns** are Perl-compatible regular expressions (PCRE) that resemble URIs, e.g. `/movies/(\d+)`

Commonly used 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](https://www.cs.washington.edu/education/courses/190m/12sp/cheat-sheets/php-regex-cheat-sheet.pdf) might come in handy.

The **subpatterns** defined in Dynamic 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, they 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);
});
```

### Optional Route Subpatterns

[](#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](http://www.php.net/manual/en/regexp.reference.repetition.php) 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

[](#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()`.

### Custom 404

[](#custom-404)

Override the default 404 handler using `$router->set404(function);`

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

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

### SDI Implementation - Before Route Middlewares

[](#sdi-implementation---before-route-middlewares)

The SDI fork of Bramus router will take an optional third argument in the route definition

The third method is the middleware to be run before the route funciton

```
$router->get(
   '/token/validate/'
 , 'route_function()'
 , 'middleware_function()'
);
```

### Before Route Middlewares

[](#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-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

[](#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

[](#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`.

Integration with other libraries
--------------------------------

[](#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
--------------------------

[](#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
------------------------------

[](#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)](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4): *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.*

Unit Testing &amp; Code Coverage
--------------------------------

[](#unit-testing--code-coverage)

`bramus/router` ships with unit tests using [PHPUnit](https://github.com/sebastianbergmann/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
----------------

[](#acknowledgements)

`bramus/router` is inspired upon [Klein](https://github.com/chriso/klein.php), [Ham](https://github.com/radiosilence/Ham), and [JREAM/route](https://bitbucket.org/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
-------

[](#license)

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

###  Health Score

29

—

LowBetter than 59% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 74.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~91 days

Recently: every ~49 days

Total

6

Last Release

3664d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7173f0646b0cdebf4cf99d9282707c85e92ffc1a5d06247de8cefaba619fcb8c?d=identicon)[peledies](/maintainers/peledies)

---

Top Contributors

[![bramus](https://avatars.githubusercontent.com/u/213073?v=4)](https://github.com/bramus "bramus (49 commits)")[![tleb](https://avatars.githubusercontent.com/u/7550889?v=4)](https://github.com/tleb "tleb (15 commits)")[![jbleuzen](https://avatars.githubusercontent.com/u/280681?v=4)](https://github.com/jbleuzen "jbleuzen (1 commits)")[![terah](https://avatars.githubusercontent.com/u/2120322?v=4)](https://github.com/terah "terah (1 commits)")

---

Tags

routerrouting

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/sdidev-router/health.svg)

```
[![Health](https://phpackages.com/badges/sdidev-router/health.svg)](https://phpackages.com/packages/sdidev-router)
```

###  Alternatives

[bramus/router

A lightweight and simple object oriented PHP Router

1.1k458.8k49](/packages/bramus-router)[lord/laroute

Access Laravels URL/Route helper functions, from JavaScript.

8022.0M8](/packages/lord-laroute)[watson/active

Laravel helper for recognising the current route, controller and action

3253.6M14](/packages/watson-active)[wazum/sluggi

TYPO3 extension for URL slug management with inline editing, auto-sync, locking, access control, and redirects

39488.5k](/packages/wazum-sluggi)[illuminatech/url-trailing-slash

Allows enforcing URL routes with or without trailing slash

50216.9k](/packages/illuminatech-url-trailing-slash)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
