{"id":13492048,"url":"https://github.com/skipperbent/simple-php-router","last_synced_at":"2025-05-14T04:05:33.505Z","repository":{"id":1379334,"uuid":"42732400","full_name":"skipperbent/simple-php-router","owner":"skipperbent","description":"Simple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the way Laravel handles routing, with both simplicity and expand-ability in mind.","archived":false,"fork":false,"pushed_at":"2024-11-10T22:20:16.000Z","size":1182,"stargazers_count":667,"open_issues_count":45,"forks_count":123,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-04-10T20:55:52.281Z","etag":null,"topics":["cms","csrf-protection","easy-to-use","input-handler","library","lightweight","middleware","module","php","php-router","php-router-standalone","request-handler","rewrite-urls","router","routing","routing-engine","url-handler"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skipperbent.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-09-18T16:03:49.000Z","updated_at":"2025-04-04T13:32:35.000Z","dependencies_parsed_at":"2024-06-18T12:16:30.179Z","dependency_job_id":"52483c22-584f-41dc-a2bd-8dd45a9c9be1","html_url":"https://github.com/skipperbent/simple-php-router","commit_stats":{"total_commits":621,"total_committers":18,"mean_commits":34.5,"dds":"0.13204508856682773","last_synced_commit":"b98d40b84b6e862bf250b179c0229efb7344a7bb"},"previous_names":[],"tags_count":262,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skipperbent%2Fsimple-php-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skipperbent%2Fsimple-php-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skipperbent%2Fsimple-php-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skipperbent%2Fsimple-php-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skipperbent","download_url":"https://codeload.github.com/skipperbent/simple-php-router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254067272,"owners_count":22009128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cms","csrf-protection","easy-to-use","input-handler","library","lightweight","middleware","module","php","php-router","php-router-standalone","request-handler","rewrite-urls","router","routing","routing-engine","url-handler"],"created_at":"2024-07-31T19:01:02.650Z","updated_at":"2025-05-14T04:05:33.454Z","avatar_url":"https://github.com/skipperbent.png","language":"PHP","readme":"# simple-router\n\nSimple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the way Laravel handles routing, with both simplicity and expand-ability in mind.\n\nWith simple-router you can create a new project fast, without depending on a framework.\n\n**It only takes a few lines of code to get started:**\n\n```php\nSimpleRouter::get('/', function() {\n    return 'Hello world';\n});\n```\n\n### Support the project\n\nIf you like simple-router and wish to see the continued development and maintenance of the project, please consider showing your support by buying me a coffee. Supporters will be listed under the credits section of this documentation.\n\nYou can donate any amount of your choice by [clicking here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=NNX4D2RUSALCN).\n\n## Table of Contents\n\n- [Getting started](#getting-started)\n\t- [Notes](#notes-1)\n\t- [Requirements](#requirements)\n\t- [Features](#features)\n\t- [Installation](#installation)\n\t\t- [Setting up Apache](#setting-up-apache)\n\t\t- [Setting up Nginx](#setting-up-nginx)\n\t\t- [Setting up IIS](#setting-up-iis)\n\t\t- [Configuration](#configuration)\n\t\t- [Helper functions](#helper-functions)\n- [Routes](#routes)\n\t- [Basic routing](#basic-routing)\n\t\t- [Class hinting](#class-hinting)\n\t\t- [Available methods](#available-methods)\n\t\t- [Multiple HTTP-verbs](#multiple-http-verbs)\n\t- [Route parameters](#route-parameters)\n        - [Required parameters](#required-parameters)\n        - [Optional parameters](#optional-parameters)\n        - [Including slash in parameters](#including-slash-in-parameters)\n        - [Regular expression constraints](#regular-expression-constraints)\n        - [Regular expression route-match](#regular-expression-route-match)\n        - [Custom regex for matching parameters](#custom-regex-for-matching-parameters)\n\t- [Named routes](#named-routes)\n\t\t- [Generating URLs To Named Routes](#generating-urls-to-named-routes)\n\t- [Router groups](#router-groups)\n\t\t- [Middleware](#middleware)\n\t\t- [Namespaces](#namespaces)\n\t\t- [Subdomain-routing](#subdomain-routing)\n\t\t- [Route prefixes](#route-prefixes)\n\t- [Partial groups](#partial-groups)\n\t- [Form Method Spoofing](#form-method-spoofing)\n\t- [Accessing The Current Route](#accessing-the-current-route)\n\t- [Other examples](#other-examples)\n- [CSRF-protection](#csrf-protection)\n\t- [Adding CSRF-verifier](#adding-csrf-verifier)\n\t- [Getting CSRF-token](#getting-csrf-token)\n\t- [Custom CSRF-verifier](#custom-csrf-verifier)\n\t- [Custom Token-provider](#custom-token-provider)\n- [Middlewares](#middlewares)\n\t- [Example](#example-1)\n- [ExceptionHandlers](#exceptionhandlers)\n    - [Handling 404, 403 and other errors](#handling-404-403-and-other-errors)\n\t- [Using custom exception handlers](#using-custom-exception-handlers)\n\t\t- [Prevent merge of parent exception-handlers](#prevent-merge-of-parent-exception-handlers)\n- [Urls](#urls)\n    - [Get the current url](#get-the-current-url)\n \t- [Get by name (single route)](#get-by-name-single-route)\n \t- [Get by name (controller route)](#get-by-name-controller-route)\n \t- [Get by class](#get-by-class)\n \t- [Using custom names for methods on a controller/resource route](#using-custom-names-for-methods-on-a-controllerresource-route)\n \t- [Getting REST/resource controller urls](#getting-restresource-controller-urls)\n \t- [Manipulating url](#manipulating-url)\n \t- [Useful url tricks](#useful-url-tricks)\n- [Input \u0026 parameters](#input--parameters)\n    - [Using the Input class to manage parameters](#using-the-input-class-to-manage-parameters)\n\t    - [Get single parameter value](#get-single-parameter-value)\n\t    - [Get parameter object](#get-parameter-object)\n\t    - [Managing files](#managing-files)\n\t    - [Get all parameters](#get-all-parameters)\n\t    - [Check if parameters exists](#check-if-parameters-exists)\n- [Events](#events)\n    - [Available events](#available-events)\n    - [Registering new event](#registering-new-event)\n    - [Custom EventHandlers](#custom-eventhandlers)\n- [Advanced](#advanced)\n\t- [Multiple route rendering](#multiple-route-rendering)\n\t- [Restrict access to IP](#restrict-access-to-ip)\n\t- [Setting custom base path](#setting-custom-base-path)\n\t- [Url rewriting](#url-rewriting)\n\t\t- [Changing current route](#changing-current-route)\n\t\t- [Bootmanager: loading routes dynamically](#bootmanager-loading-routes-dynamically)\n\t\t- [Adding routes manually](#adding-routes-manually)\n\t- [Custom class-loader](#custom-class-loader)\n\t  - [Integrating with php-di](#Integrating-with-php-di)\n\t- [Parameters](#parameters)\n\t- [Extending](#extending)\n- [Help and support](#help-and-support)\n    - [Common issues and fixes](#common-issues-and-fixes)\n        - [Multiple routes matches? Which one has the priority?](#multiple-routes-matches-which-one-has-the-priority)\n        - [Parameters won't match or route not working with special characters](#parameters-wont-match-or-route-not-working-with-special-characters)\n        - [Using the router on sub-paths](#using-the-router-on-sub-paths)\n    - [Debugging](#debugging)\n        - [Creating unit-tests](#creating-unit-tests) \n        - [Debug information](#debug-information)\n        - [Benchmark and log-info](#benchmark-and-log-info)\n    - [Reporting a new issue](#reporting-a-new-issue)\n        - [Procedure for reporting a new issue](#procedure-for-reporting-a-new-issue)\n        - [Issue template](#issue-template)\n    - [Feedback and development](#feedback-and-development)\n   \t    - [Contribution development guidelines](#contribution-development-guidelines)\n- [Credits](#credits)\n\t- [Sites](#sites)\n\t- [License](#license)\n\n___\n\n# Getting started\n\nAdd the latest version of the simple-router project running this command.\n\n```\ncomposer require pecee/simple-router\n```\n\n## Notes\n\nThe goal of this project is to create a router that is more or less 100% compatible with the Laravel documentation, while remaining as simple as possible, and as easy to integrate and change without compromising either speed or complexity. Being lightweight is the #1 priority.\n\nWe've included a simple demo project for the router which can be found [here](https://github.com/skipperbent/simple-router-demo). This project should give you a basic understanding of how to setup and use simple-php-router project.\n\nPlease note that the demo-project only covers how to integrate the `simple-php-router` in a project without an existing framework. If you are using a framework in your project, the implementation might vary.\n\nYou can find the demo-project here: [https://github.com/skipperbent/simple-router-demo](https://github.com/skipperbent/simple-router-demo)\n\n**What we won't cover:**\n\n- How to setup a solution that fits your need. This is a basic demo to help you get started.\n- Understanding of MVC; including Controllers, Middlewares or ExceptionHandlers.\n- How to integrate into third party frameworks.\n\n**What we cover:**\n\n- How to get up and running fast - from scratch.\n- How to get ExceptionHandlers, Middlewares and Controllers working.\n- How to setup your webservers.\n\n## Requirements\n\n- PHP 7.1 or greater (version 3.x and below supports PHP 5.5+)\n- PHP JSON extension enabled.\n\n## Features\n\n- Basic routing (`GET`, `POST`, `PUT`, `PATCH`, `UPDATE`, `DELETE`) with support for custom multiple verbs.\n- Regular Expression Constraints for parameters.\n- Named routes.\n- Generating url to routes.\n- Route groups.\n- Middleware (classes that intercepts before the route is rendered).\n- Namespaces.\n- Route prefixes.\n- CSRF protection.\n- Optional parameters\n- Sub-domain routing\n- Custom boot managers to rewrite urls to \"nicer\" ones.\n- Input manager; easily manage `GET`, `POST` and `FILE` values.\n- IP based restrictions.\n- Easily extendable.\n\n## Installation\n\n1. Navigate to your project folder in terminal and run the following command:\n\n```php\ncomposer require pecee/simple-router\n```\n\n### Setting up Nginx\n\nIf you are using Nginx please make sure that url-rewriting is enabled.\n\nYou can easily enable url-rewriting by adding the following configuration for the Nginx configuration-file for the demo-project.\n\n```\nlocation / {\n    try_files $uri $uri/ /index.php?$query_string;\n}\n```\n\n### Setting up Apache\n\nNothing special is required for Apache to work. We've include the `.htaccess` file in the `public` folder. If rewriting is not working for you, please check that the `mod_rewrite` module (htaccess support) is enabled in the Apache configuration.\n\n#### .htaccess example\n\nBelow is an example of an working `.htaccess` file used by simple-php-router.\n\nSimply create a new `.htaccess` file in your projects `public` directory and paste the contents below in your newly created file. This will redirect all requests to your `index.php` file (see Configuration section below).\n\n```\nRewriteEngine on\nRewriteCond %{SCRIPT_FILENAME} !-f\nRewriteCond %{SCRIPT_FILENAME} !-d\nRewriteCond %{SCRIPT_FILENAME} !-l\nRewriteRule ^(.*)$ index.php/$1\n```\n\n### Setting up IIS\n\nOn IIS you have to add some lines your `web.config` file in the `public` folder or create a new one. If rewriting is not working for you, please check that your IIS version have included the `url rewrite` module or download and install them from Microsoft web site.\n\n#### web.config example\n\nBelow is an example of an working `web.config` file used by simple-php-router.\n\nSimply create a new `web.config` file in your projects `public` directory and paste the contents below in your newly created file. This will redirect all requests to your `index.php` file (see Configuration section below). If the `web.config` file already exists, add the `\u003crewrite\u003e` section inside the `\u003csystem.webServer\u003e` branch.\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cconfiguration\u003e\n    \u003csystem.webServer\u003e\n\t\u003crewrite\u003e\n\t  \u003crules\u003e\n\t\t\u003c!-- Remove slash '/' from the en of the url --\u003e\n\t\t\u003crule name=\"RewriteRequestsToPublic\"\u003e\n\t\t  \u003cmatch url=\"^(.*)$\" /\u003e\n\t\t  \u003cconditions logicalGrouping=\"MatchAll\" trackAllCaptures=\"false\"\u003e\n\t\t  \u003c/conditions\u003e\n\t\t  \u003caction type=\"Rewrite\" url=\"/{R:0}\" /\u003e\n\t\t\u003c/rule\u003e\n\n\t\t\u003c!-- When requested file or folder don't exists, will request again through index.php --\u003e\n\t\t\u003crule name=\"Imported Rule 1\" stopProcessing=\"true\"\u003e\n\t\t  \u003cmatch url=\"^(.*)$\" ignoreCase=\"true\" /\u003e\n\t\t  \u003cconditions logicalGrouping=\"MatchAll\"\u003e\n\t\t\t\u003cadd input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" /\u003e\n\t\t\t\u003cadd input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" /\u003e\n\t\t  \u003c/conditions\u003e\n\t\t  \u003caction type=\"Rewrite\" url=\"/index.php/{R:1}\" appendQueryString=\"true\" /\u003e\n\t\t\u003c/rule\u003e\n\t  \u003c/rules\u003e\n\t\u003c/rewrite\u003e\n    \u003c/system.webServer\u003e\n\u003c/configuration\u003e\n```\n\n#### Troubleshooting\n\nIf you do not have a `favicon.ico` file in your project, you can get a `NotFoundHttpException` (404 - not found).\n\nTo add `favicon.ico` to the IIS ignore-list, add the following line to the `\u003cconditions\u003e` group:\n\n```\n\u003cadd input=\"{REQUEST_FILENAME}\" negate=\"true\" pattern=\"favicon.ico\" ignoreCase=\"true\" /\u003e\n```\n\nYou can also make one exception for files with some extensions:\n\n```\n\u003cadd input=\"{REQUEST_FILENAME}\" pattern=\"\\.ico|\\.png|\\.css|\\.jpg\" negate=\"true\" ignoreCase=\"true\" /\u003e\n```\n\nIf you are using `$_SERVER['ORIG_PATH_INFO']`, you will get `\\index.php\\` as part of the returned value. \n\n**Example:**\n\n```\n/index.php/test/mypage.php\n```\n\n### Configuration\n\nCreate a new file, name it `routes.php` and place it in your library folder. This will be the file where you define all the routes for your project.\n\n**WARNING: NEVER PLACE YOUR ROUTES.PHP IN YOUR PUBLIC FOLDER!**\n\nIn your ```index.php``` require your newly-created ```routes.php``` and call the ```SimpleRouter::start()``` method. This will trigger and do the actual routing of the requests.\n\nIt's not required, but you can set `SimpleRouter::setDefaultNamespace('\\Demo\\Controllers');` to prefix all routes with the namespace to your controllers. This will simplify things a bit, as you won't have to specify the namespace for your controllers on each route.\n\n**This is an example of a basic ```index.php``` file:**\n\n```php\n\u003c?php\nuse Pecee\\SimpleRouter\\SimpleRouter;\n\n/* Load external routes file */\nrequire_once 'routes.php';\n\n/**\n * The default namespace for route-callbacks, so we don't have to specify it each time.\n * Can be overwritten by using the namespace config option on your routes.\n */\n\nSimpleRouter::setDefaultNamespace('\\Demo\\Controllers');\n\n// Start the routing\nSimpleRouter::start();\n```\n\n### Helper functions\n\nWe recommend that you add these helper functions to your project. These will allow you to access functionality of the router more easily.\n\nTo implement the functions below, simply copy the code to a new file and require the file before initializing the router or copy the `helpers.php` we've included in this library.\n\n```php\nuse Pecee\\SimpleRouter\\SimpleRouter as Router;\nuse Pecee\\Http\\Url;\nuse Pecee\\Http\\Response;\nuse Pecee\\Http\\Request;\n\n/**\n * Get url for a route by using either name/alias, class or method name.\n *\n * The name parameter supports the following values:\n * - Route name\n * - Controller/resource name (with or without method)\n * - Controller class name\n *\n * When searching for controller/resource by name, you can use this syntax \"route.name@method\".\n * You can also use the same syntax when searching for a specific controller-class \"MyController@home\".\n * If no arguments is specified, it will return the url for the current loaded route.\n *\n * @param string|null $name\n * @param string|array|null $parameters\n * @param array|null $getParams\n * @return \\Pecee\\Http\\Url\n * @throws \\InvalidArgumentException\n */\nfunction url(?string $name = null, $parameters = null, ?array $getParams = null): Url\n{\n    return Router::getUrl($name, $parameters, $getParams);\n}\n\n/**\n * @return \\Pecee\\Http\\Response\n */\nfunction response(): Response\n{\n    return Router::response();\n}\n\n/**\n * @return \\Pecee\\Http\\Request\n */\nfunction request(): Request\n{\n    return Router::request();\n}\n\n/**\n * Get input class\n * @param string|null $index Parameter index name\n * @param string|mixed|null $defaultValue Default return value\n * @param array ...$methods Default methods\n * @return \\Pecee\\Http\\Input\\InputHandler|array|string|null\n */\nfunction input($index = null, $defaultValue = null, ...$methods)\n{\n    if ($index !== null) {\n        return request()-\u003egetInputHandler()-\u003evalue($index, $defaultValue, ...$methods);\n    }\n\n    return request()-\u003egetInputHandler();\n}\n\n/**\n * @param string $url\n * @param int|null $code\n */\nfunction redirect(string $url, ?int $code = null): void\n{\n    if ($code !== null) {\n        response()-\u003ehttpCode($code);\n    }\n\n    response()-\u003eredirect($url);\n}\n\n/**\n * Get current csrf-token\n * @return string|null\n */\nfunction csrf_token(): ?string\n{\n    $baseVerifier = Router::router()-\u003egetCsrfVerifier();\n    if ($baseVerifier !== null) {\n        return $baseVerifier-\u003egetTokenProvider()-\u003egetToken();\n    }\n\n    return null;\n}\n```\n\n---\n\n# Routes\n\nRemember the ```routes.php``` file you required in your ```index.php```? This file be where you place all your custom rules for routing.\n\n## Basic routing\n\nBelow is a very basic example of setting up a route. First parameter is the url which the route should match - next parameter is a `Closure` or callback function that will be triggered once the route matches.\n\n```php\nSimpleRouter::get('/', function() {\n    return 'Hello world';\n});\n```\n\n### Class hinting\n\nYou can use class hinting to load a class \u0026 method like this:\n\n```php\nSimpleRouter::get('/', [MyClass::class, 'myMethod']);\n```\n\n### Available methods\n\nHere you can see a list over all available routes:\n\n```php\nSimpleRouter::get($url, $callback, $settings);\nSimpleRouter::post($url, $callback, $settings);\nSimpleRouter::put($url, $callback, $settings);\nSimpleRouter::patch($url, $callback, $settings);\nSimpleRouter::delete($url, $callback, $settings);\nSimpleRouter::options($url, $callback, $settings);\n```\n\n### Multiple HTTP-verbs\n\nSometimes you might need to create a route that accepts multiple HTTP-verbs. If you need to match all HTTP-verbs you can use the `any` method.\n\n```php\nSimpleRouter::match(['get', 'post'], '/', function() {\n    // ...\n});\n\nSimpleRouter::any('foo', function() {\n    // ...\n});\n```\n\nWe've created a simple method which matches `GET` and `POST` which is most commonly used:\n\n```php\nSimpleRouter::form('foo', function() {\n    // ...\n});\n```\n\n## Route parameters\n\n### Required parameters\n\nYou'll properly wondering by know how you parse parameters from your urls. For example, you might want to capture the users id from an url. You can do so by defining route-parameters.\n\n```php\nSimpleRouter::get('/user/{id}', function ($userId) {\n    return 'User with id: ' . $userId;\n});\n```\n\nYou may define as many route parameters as required by your route:\n\n```php\nSimpleRouter::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) {\n    // ...\n});\n```\n\n**Note:** Route parameters are always encased within `{` `}` braces and should consist of alphabetic characters. Route parameters can only contain certain characters like `A-Z`, `a-z`, `0-9`, `-` and `_`.\nIf your route contain other characters, please see  [Custom regex for matching parameters](#custom-regex-for-matching-parameters).\n\n### Optional parameters\n\nOccasionally you may need to specify a route parameter, but make the presence of that route parameter optional. You may do so by placing a ? mark after the parameter name. Make sure to give the route's corresponding variable a default value:\n\n```php\nSimpleRouter::get('/user/{name?}', function ($name = null) {\n    return $name;\n});\n\nSimpleRouter::get('/user/{name?}', function ($name = 'Simon') {\n    return $name;\n});\n```\n\n### Including slash in parameters\n\nIf you're working with WebDAV services the url could mean the difference between a file and a folder.\n\nFor instance `/path` will be considered a file - whereas `/path/` will be considered a folder.\n\nThe router can add the ending slash for the last parameter in your route based on the path. So if `/path/` is requested the parameter will contain the value of `path/` and visa versa.\n\nTo ensure compatibility with older versions, this feature is disabled by default and has to be enabled by setting \nthe `setSettings(['includeSlash' =\u003e true])` or by using setting `setSlashParameterEnabled(true)` for your route.\n\n**Example**\n\n```php\nSimpleRouter::get('/path/{fileOrFolder}', function ($fileOrFolder) {\n\treturn $fileOrFolder;\n})-\u003esetSettings(['includeSlash' =\u003e true]);\n```\n\n- Requesting `/path/file` will return the `$fileOrFolder` value: `file`.\n- Requesting `/path/folder/` will return the `$fileOrFolder` value: `folder/`.\n\n### Regular expression constraints\n\nYou may constrain the format of your route parameters using the where method on a route instance. The where method accepts the name of the parameter and a regular expression defining how the parameter should be constrained:\n\n```php\nSimpleRouter::get('/user/{name}', function ($name) {\n    \n    // ... do stuff\n    \n})-\u003ewhere([ 'name' =\u003e '[A-Za-z]+' ]);\n\nSimpleRouter::get('/user/{id}', function ($id) {\n    \n    // ... do stuff\n    \n})-\u003ewhere([ 'id' =\u003e '[0-9]+' ]);\n\nSimpleRouter::get('/user/{id}/{name}', function ($id, $name) {\n    \n    // ... do stuff\n    \n})-\u003ewhere(['id' =\u003e '[0-9]+', 'name' =\u003e '[a-z]+']);\n```\n\n### Regular expression route-match\n\nYou can define a regular-expression match for the entire route if you wish.\n\nThis is useful if you for example are creating a model-box which loads urls from ajax.\n\nThe example below is using the following regular expression: `/ajax/([\\w]+)/?([0-9]+)?/?` which basically just matches `/ajax/` and exspects the next parameter to be a string - and the next to be a number (but optional).\n\n**Matches:** `/ajax/abc/`, `/ajax/abc/123/`\n\n**Won't match:** `/ajax/`\n\nMatch groups specified in the regex will be passed on as parameters:\n\n```php\nSimpleRouter::all('/ajax/abc/123', function($param1, $param2) {\n\t// param1 = abc\n\t// param2 = 123\n})-\u003esetMatch('/\\/ajax\\/([\\w]+)\\/?([0-9]+)?\\/?/is');\n```\n\n### Custom regex for matching parameters\n\nBy default simple-php-router uses the `[\\w\\-]+` regular expression. It will match `A-Z`, `a-z`, `0-9`, `-` and `_` characters in parameters.\nThis decision was made with speed and reliability in mind, as this match will match both letters, number and most of the used symbols on the internet.\n\nHowever, sometimes it can be necessary to add a custom regular expression to match more advanced characters like foreign letters `æ ø å` etc.\n\nYou can test your custom regular expression by using on the site [Regex101.com](https://www.regex101.com).\n\nInstead of adding a custom regular expression to all your parameters, you can simply add a global regular expression which will be used on all the parameters on the route.\n\n**Note:** If you the regular expression to be available across, we recommend using the global parameter on a group as demonstrated in the examples below.\n\n#### Example\n\nThis example will ensure that all parameters use the `[\\w\\-\\æ\\ø\\å]+` (`a-z`, `A-Z`, `-`, `_`, `0-9`, `æ`, `ø`, `å`) regular expression when parsing.\n\n```php\nSimpleRouter::get('/path/{parameter}', 'VideoController@home', ['defaultParameterRegex' =\u003e '[\\w\\-\\æ\\ø\\å]+']);\n```\n\nYou can also apply this setting to a group if you need multiple routes to use your custom regular expression when parsing parameters.\n\n```php\nSimpleRouter::group(['defaultParameterRegex' =\u003e '[\\w\\-\\æ\\ø\\å]+'], function() {\n\n    SimpleRouter::get('/path/{parameter}', 'VideoController@home');\n\n});\n```\n\n## Named routes\n\nNamed routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route by chaining the name method onto the route definition:\n\n```php\nSimpleRouter::get('/user/profile', function () {\n    // Your code here\n})-\u003ename('profile');\n```\n\nYou can also specify names for Controller-actions:\n\n```php\nSimpleRouter::get('/user/profile', 'UserController@profile')-\u003ename('profile');\n```\n\n### Generating URLs To Named Routes\n\nOnce you have assigned a name to a given route, you may use the route's name when generating URLs or redirects via the global `url` helper-function (see helpers section):\n\n```php\n// Generating URLs...\n$url = url('profile');\n```\n\nIf the named route defines parameters, you may pass the parameters as the second argument to the `url` function. The given parameters will automatically be inserted into the URL in their correct positions:\n\n```php\nSimpleRouter::get('/user/{id}/profile', function ($id) {\n    //\n})-\u003ename('profile');\n\n$url = url('profile', ['id' =\u003e 1]);\n```\n\nFor more information on urls, please see the [Urls](#urls) section.\n\n## Router groups\n\nRoute groups allow you to share route attributes, such as middleware or namespaces, across a large number of routes without needing to define those attributes on each individual route. Shared attributes are specified in an array format as the first parameter to the `SimpleRouter::group` method.\n\n### Middleware\n\nTo assign middleware to all routes within a group, you may use the middleware key in the group attribute array. Middleware are executed in the order they are listed in the array:\n\n```php\nSimpleRouter::group(['middleware' =\u003e \\Demo\\Middleware\\Auth::class], function () {\n    SimpleRouter::get('/', function ()    {\n        // Uses Auth Middleware\n    });\n\n    SimpleRouter::get('/user/profile', function () {\n        // Uses Auth Middleware\n    });\n});\n```\n\n### Namespaces\n\nAnother common use-case for route groups is assigning the same PHP namespace to a group of controllers using the `namespace` parameter in the group array:\n\n#### Note\nGroup namespaces will only be added to routes with relative callbacks.\nFor example if your route has an absolute callback like `\\Demo\\Controller\\DefaultController@home`, the namespace from the route will not be prepended.\nTo fix this you can make the callback relative by removing the `\\` in the beginning of the callback.\n\n```php\nSimpleRouter::group(['namespace' =\u003e 'Admin'], function () {\n    // Controllers Within The \"App\\Http\\Controllers\\Admin\" Namespace\n});\n```\n\nYou can add parameters to the prefixes of your routes.\n\nParameters from your previous routes will be injected \ninto your routes after any route-required parameters, starting from oldest to newest.\n\n```php\nSimpleRouter::group(['prefix' =\u003e '/lang/{lang}'], function ($language) {\n    \n    SimpleRouter::get('/about', function($language) {\n    \t\n    \t// Will match /lang/da/about\n    \t\n    });\n    \n});\n```\n\n### Subdomain-routing\n\nRoute groups may also be used to handle sub-domain routing. Sub-domains may be assigned route parameters just like route urls, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the `domain` key on the group attribute array:\n\n```php\nSimpleRouter::group(['domain' =\u003e '{account}.myapp.com'], function () {\n    SimpleRouter::get('/user/{id}', function ($account, $id) {\n        //\n    });\n});\n```\n\n### Route prefixes\n\nThe `prefix` group attribute may be used to prefix each route in the group with a given url. For example, you may want to prefix all route urls within the group with `admin`:\n\n```php\nSimpleRouter::group(['prefix' =\u003e '/admin'], function () {\n    SimpleRouter::get('/users', function ()    {\n        // Matches The \"/admin/users\" URL\n    });\n});\n```\n\nYou can also use parameters in your groups:\n\n```php\nSimpleRouter::group(['prefix' =\u003e '/lang/{language}'], function ($language) {\n    SimpleRouter::get('/users', function ($language)    {\n        // Matches The \"/lang/da/users\" URL\n    });\n});\n```\n\n## Partial groups\n\nPartial router groups has the same benefits as a normal group, but **are only rendered once the url has matched** \nin contrast to a normal group which are always rendered in order to retrieve it's child routes.\nPartial groups are therefore more like a hybrid of a traditional route with the benefits of a group.\n\nThis can be extremely useful in situations where you only want special routes to be added, but only when a certain criteria or logic has been met.\n\n**NOTE:** Use partial groups with caution as routes added within are only rendered and available once the url of the partial-group has matched. \nThis can cause `url()` not to find urls for the routes added within before the partial-group has been matched and is rendered.\n\n**Example:**\n\n```php\nSimpleRouter::partialGroup('/plugin/{name}', function ($plugin) {\n\n    // Add routes from plugin\n\n});\n```\n\n## Form Method Spoofing\n\nHTML forms do not support `PUT`, `PATCH` or `DELETE` actions. So, when defining `PUT`, `PATCH` or `DELETE` routes that are called from an HTML form, you will need to add a hidden `_method` field to the form. The value sent with the `_method` field will be used as the HTTP request method:\n\n```php\n\u003cinput type=\"hidden\" name=\"_method\" value=\"PUT\" /\u003e\n```\n\n## Accessing The Current Route\n\nYou can access information about the current route loaded by using the following method:\n\n```php\nSimpleRouter::request()-\u003egetLoadedRoute();\nrequest()-\u003egetLoadedRoute();\n```\n\n## Other examples\n\nYou can find many more examples in the `routes.php` example-file below:\n\n```php\n\u003c?php\nuse Pecee\\SimpleRouter\\SimpleRouter;\n\n/* Adding custom csrfVerifier here */\nSimpleRouter::csrfVerifier(new \\Demo\\Middlewares\\CsrfVerifier());\n\nSimpleRouter::group(['middleware' =\u003e \\Demo\\Middlewares\\Site::class, 'exceptionHandler' =\u003e \\Demo\\Handlers\\CustomExceptionHandler::class], function() {\n\n\n    SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show', ['where' =\u003e ['id' =\u003e '[0-9]+']]);\n\n\t/**\n     * Class hinting is supported too\n     */\n     \n     SimpleRouter::get('/answers/{id}', [ControllerAnswers::class, 'show'], ['where' =\u003e ['id' =\u003e '[0-9]+']]);\n\n    /**\n     * Restful resource (see IRestController interface for available methods)\n     */\n\n    SimpleRouter::resource('/rest', ControllerResource::class);\n\n\n    /**\n     * Load the entire controller (where url matches method names - getIndex(), postIndex(), putIndex()).\n     * The url paths will determine which method to render.\n     *\n     * For example:\n     *\n     * GET  /animals         =\u003e getIndex()\n     * GET  /animals/view    =\u003e getView()\n     * POST /animals/save    =\u003e postSave()\n     *\n     * etc.\n     */\n\n    SimpleRouter::controller('/animals', ControllerAnimals::class);\n\n});\n\nSimpleRouter::get('/page/404', 'ControllerPage@notFound', ['as' =\u003e 'page.notfound']);\n```\n\n---\n\n# CSRF Protection\n\nAny forms posting to `POST`, `PUT` or `DELETE` routes should include the CSRF-token. We strongly recommend that you enable CSRF-verification on your site to maximize security.\n\nYou can use the `BaseCsrfVerifier` to enable CSRF-validation on all request. If you need to disable verification for specific urls, please refer to the \"Custom CSRF-verifier\" section below.\n\nBy default simple-php-router will use the `CookieTokenProvider` class. This provider will store the security-token in a cookie on the clients machine.\nIf you want to store the token elsewhere, please refer to the \"Creating custom Token Provider\" section below.\n\n## Adding CSRF-verifier\n\nWhen you've created your CSRF-verifier you need to tell simple-php-router that it should use it. You can do this by adding the following line in your `routes.php` file:\n\n```php\nSimpleRouter::csrfVerifier(new \\Demo\\Middlewares\\CsrfVerifier());\n```\n\n## Getting CSRF-token\n\nWhen posting to any of the urls that has CSRF-verification enabled, you need post your CSRF-token or else the request will get rejected.\n\nYou can get the CSRF-token by calling the helper method:\n\n```php\ncsrf_token();\n```\n\nYou can also get the token directly:\n\n```php\nreturn SimpleRouter::router()-\u003egetCsrfVerifier()-\u003egetTokenProvider()-\u003egetToken();\n```\n\nThe default name/key for the input-field is `csrf_token` and is defined in the `POST_KEY` constant in the `BaseCsrfVerifier` class.\nYou can change the key by overwriting the constant in your own CSRF-verifier class.\n\n**Example:**\n\nThe example below will post to the current url with a hidden field \"`csrf_token`\".\n\n```html\n\u003cform method=\"post\" action=\"\u003c?= url(); ?\u003e\"\u003e\n    \u003cinput type=\"hidden\" name=\"csrf_token\" value=\"\u003c?= csrf_token(); ?\u003e\"\u003e\n    \u003c!-- other input elements here --\u003e\n\u003c/form\u003e\n```\n\n## Custom CSRF-verifier\n\nCreate a new class and extend the `BaseCsrfVerifier` middleware class provided by default with the simple-php-router library.\n\nAdd the property `except` with an array of the urls to the routes you want to exclude/whitelist from the CSRF validation.\nUsing ```*``` at the end for the url will match the entire url.\n\n**Here's a basic example on a CSRF-verifier class:**\n\n```php\nnamespace Demo\\Middlewares;\n\nuse Pecee\\Http\\Middleware\\BaseCsrfVerifier;\n\nclass CsrfVerifier extends BaseCsrfVerifier\n{\n\t/**\n\t * CSRF validation will be ignored on the following urls.\n\t */\n\tprotected $except = ['/api/*'];\n}\n```\n\n## Custom Token Provider\n\nBy default the `BaseCsrfVerifier` will use the `CookieTokenProvider` to store the token in a cookie on the clients machine.\n\nIf you need to store the token elsewhere, you can do that by creating your own class and implementing the `ITokenProvider` class.\n\n```php\nclass SessionTokenProvider implements ITokenProvider\n{\n\n    /**\n     * Refresh existing token\n     */\n    public function refresh(): void\n    {\n        // Implement your own functionality here...\n    }\n\n    /**\n     * Validate valid CSRF token\n     *\n     * @param string $token\n     * @return bool\n     */\n    public function validate($token): bool\n    {\n        // Implement your own functionality here...\n    }\n    \n    /**\n     * Get token token\n     *\n     * @param string|null $defaultValue\n     * @return string|null\n     */\n    public function getToken(?string $defaultValue = null): ?string \n    {\n        // Implement your own functionality here...\n    }\n\n}\n```\n\nNext you need to set your custom `ITokenProvider` implementation on your `BaseCsrfVerifier` class in your routes file:\n\n```php\n$verifier = new \\Demo\\Middlewares\\CsrfVerifier();\n$verifier-\u003esetTokenProvider(new SessionTokenProvider());\n\nSimpleRouter::csrfVerifier($verifier);\n```\n\n---\n\n# Middlewares\n\nMiddlewares are classes that loads before the route is rendered. A middleware can be used to verify that a user is logged in - or to set parameters specific for the current request/route. Middlewares must implement the `IMiddleware` interface.\n\n## Example\n\n```php\nnamespace Demo\\Middlewares;\n\nuse Pecee\\Http\\Middleware\\IMiddleware;\nuse Pecee\\Http\\Request;\n\nclass CustomMiddleware implements IMiddleware {\n\n    public function handle(Request $request): void \n    {\n    \n        // Authenticate user, will be available using request()-\u003euser\n        $request-\u003euser = User::authenticate();\n\n        // If authentication failed, redirect request to user-login page.\n        if($request-\u003euser === null) {\n            $request-\u003esetRewriteUrl(url('user.login'));\n        }\n\n    }\n}\n```\n\n---\n\n# ExceptionHandlers\n\nExceptionHandler are classes that handles all exceptions. ExceptionsHandlers must implement the `IExceptionHandler` interface.\n\n## Handling 404, 403 and other errors\n\nIf you simply want to catch a 404 (page not found) etc. you can use the `SimpleRouter::error($callback)` static helper method.\n\nThis will add a callback method which is fired whenever an error occurs on all routes.\n\nThe basic example below simply redirect the page to `/not-found` if an `NotFoundHttpException` (404) occurred.\nThe code should be placed in the file that contains your routes.\n\n```php\nSimpleRouter::get('/not-found', 'PageController@notFound');\nSimpleRouter::get('/forbidden', 'PageController@notFound');\n\nSimpleRouter::error(function(Request $request, \\Exception $exception) {\n\n    switch($exception-\u003egetCode()) {\n        // Page not found\n        case 404:\n            response()-\u003eredirect('/not-found');\n        // Forbidden\n        case 403:\n            response()-\u003eredirect('/forbidden');\n    }\n    \n});\n```\n\nThe example above will redirect all errors with http-code `404` (page not found) to `/not-found` and `403` (forbidden) to `/forbidden`.\n\nIf you do not want a redirect, but want the error-page rendered on the current-url, you can tell the router to execute a rewrite callback like so:\n\n```php\n$request-\u003esetRewriteCallback('ErrorController@notFound');\n```\n\nIf you will set the correct status for the browser error use:\n\n```php\nSimpleRouter::response()-\u003ehttpCode(404);\n```\n\n## Using custom exception handlers\n\nThis is a basic example of an ExceptionHandler implementation (please see \"[Easily overwrite route about to be loaded](#easily-overwrite-route-about-to-be-loaded)\" for examples on how to change callback).\n\n```php\nnamespace Demo\\Handlers;\n\nuse Pecee\\Http\\Request;\nuse Pecee\\SimpleRouter\\Handlers\\IExceptionHandler;\nuse Pecee\\SimpleRouter\\Exceptions\\NotFoundHttpException;\n\nclass CustomExceptionHandler implements IExceptionHandler\n{\n\tpublic function handleError(Request $request, \\Exception $error): void\n\t{\n\n\t\t/* You can use the exception handler to format errors depending on the request and type. */\n\n\t\tif ($request-\u003egetUrl()-\u003econtains('/api')) {\n\n\t\t\tresponse()-\u003ejson([\n\t\t\t\t'error' =\u003e $error-\u003egetMessage(),\n\t\t\t\t'code'  =\u003e $error-\u003egetCode(),\n\t\t\t]);\n\n\t\t}\n\n\t\t/* The router will throw the NotFoundHttpException on 404 */\n\t\tif($error instanceof NotFoundHttpException) {\n\n\t\t\t// Render custom 404-page\n\t\t\t$request-\u003esetRewriteCallback('Demo\\Controllers\\PageController@notFound');\n\t\t\treturn;\n\t\t\t\n\t\t}\n\t\t\n\t\t/* Other error */\n\t\tif($error instanceof MyCustomException) {\n\n\t\t\t$request-\u003esetRewriteRoute(\n\t\t\t\t// Add new route based on current url (minus query-string) and add custom parameters.\n\t\t\t\t(new RouteUrl(url(null, null, []), 'PageController@error'))-\u003esetParameters(['exception' =\u003e $error])\n\t\t\t);\n\t\t\treturn;\n\t\t\t\n\t\t}\n\n\t\tthrow $error;\n\n\t}\n\n}\n```\n\nYou can add your custom exception-handler class to your group by using the `exceptionHandler` settings-attribute.\n`exceptionHandler` can be either class-name or array of class-names.\n\n```php\nSimpleRouter::group(['exceptionHandler' =\u003e \\Demo\\Handlers\\CustomExceptionHandler::class], function() {\n\n    // Your routes here\n\n});\n```\n\n### Prevent merge of parent exception-handlers\n\nBy default the router will merge exception-handlers to any handlers provided by parent groups, and will be executed in the order of newest to oldest.\n\nIf you want your groups exception handler to be executed independently, you can add the `mergeExceptionHandlers` attribute and set it to `false`.\n\n```php\nSimpleRouter::group(['prefix' =\u003e '/', 'exceptionHandler' =\u003e \\Demo\\Handlers\\FirstExceptionHandler::class, 'mergeExceptionHandlers' =\u003e false], function() {\n\n\tSimpleRouter::group(['prefix' =\u003e '/admin', 'exceptionHandler' =\u003e \\Demo\\Handlers\\SecondExceptionHandler::class], function() {\n\t\n\t\t// Both SecondExceptionHandler and FirstExceptionHandler will trigger (in that order).\n\t\n\t});\n\t\n\tSimpleRouter::group(['prefix' =\u003e '/user', 'exceptionHandler' =\u003e \\Demo\\Handlers\\SecondExceptionHandler::class, 'mergeExceptionHandlers' =\u003e false], function() {\n\t\n\t\t// Only SecondExceptionHandler will trigger.\n\t\n\t});\n\n});\n```\n\n---\n\n# Urls\n\nBy default all controller and resource routes will use a simplified version of their url as name.\n\nYou easily use the `url()` shortcut helper function to retrieve urls for your routes or manipulate the current url.\n\n`url()` will return a `Url` object which will return a `string` when rendered, so it can be used safely in templates etc. but \ncontains all the useful helpers methods in the `Url` class like `contains`, `indexOf` etc. \nCheck the [Useful url tricks](#useful-url-tricks) below.\n\n### Get the current url\n\nIt has never been easier to get and/or manipulate the current url.\n\nThe example below shows you how to get the current url:\n\n```php\n# output: /current-url\nurl();\n```\n\n### Get by name (single route)\n\n```php\nSimpleRouter::get('/product-view/{id}', 'ProductsController@show', ['as' =\u003e 'product']);\n\n# output: /product-view/22/?category=shoes\nurl('product', ['id' =\u003e 22], ['category' =\u003e 'shoes']);\n\n# output: /product-view/?category=shoes\nurl('product', null, ['category' =\u003e 'shoes']);\n```\n\n### Get by name (controller route)\n\n```php\nSimpleRouter::controller('/images', ImagesController::class, ['as' =\u003e 'picture']);\n\n# output: /images/view/?category=shows\nurl('picture@getView', null, ['category' =\u003e 'shoes']);\n\n# output: /images/view/?category=shows\nurl('picture', 'getView', ['category' =\u003e 'shoes']);\n\n# output: /images/view/\nurl('picture', 'view');\n```\n\n### Get by class\n\n```php\nSimpleRouter::get('/product-view/{id}', 'ProductsController@show', ['as' =\u003e 'product']);\nSimpleRouter::controller('/images', 'ImagesController');\n\n# output: /product-view/22/?category=shoes\nurl('ProductsController@show', ['id' =\u003e 22], ['category' =\u003e 'shoes']);\n\n# output: /images/image/?id=22\nurl('ImagesController@getImage', null, ['id' =\u003e 22]);\n```\n\n### Using custom names for methods on a controller/resource route\n\n```php\nSimpleRouter::controller('gadgets', GadgetsController::class, ['names' =\u003e ['getIphoneInfo' =\u003e 'iphone']]);\n\nurl('gadgets.iphone');\n\n# output\n# /gadgets/iphoneinfo/\n```\n\n### Getting REST/resource controller urls\n\n```php\nSimpleRouter::resource('/phones', PhonesController::class);\n\n# output: /phones/\nurl('phones');\n\n# output: /phones/\nurl('phones.index');\n\n# output: /phones/create/\nurl('phones.create');\n\n# output: /phones/edit/\nurl('phones.edit');\n```\n\n### Manipulating url\n\nYou can easily manipulate the query-strings, by adding your get param arguments.\n\n```php\n# output: /current-url?q=cars\n\nurl(null, null, ['q' =\u003e 'cars']);\n```\n\nYou can remove a query-string parameter by setting the value to `null`. \n\nThe example below will remove any query-string parameter named `q` from the url but keep all others query-string parameters:\n\n```php\n$url = url()-\u003eremoveParam('q');\n```\n\nFor more information please check the [Useful url tricks](#useful-url-tricks) section of the documentation.\n\n### Useful url tricks\n\nCalling `url` will always return a `Url` object. Upon rendered it will return a `string` of the relative `url`, so it's safe to use in templates etc.\n\nHowever this allow us to use the useful methods on the `Url` object like `indexOf` and `contains` or retrieve specific parts of the url like the path, querystring parameters, host etc. You can also manipulate the url like removing- or adding parameters, changing host and more.\n\nIn the example below, we check if the current url contains the `/api` part.\n\n```php\nif(url()-\u003econtains('/api')) {\n    // ... do stuff\n}\n```\n\nAs mentioned earlier, you can also use the `Url` object to show specific parts of the url or control what part of the url you want.\n\n```php\n# Grab the query-string parameter id from the current-url.\n$id = url()-\u003egetParam('id');\n\n# Get the absolute url for the current url.\n$absoluteUrl = url()-\u003egetAbsoluteUrl();\n```\n\nFor more available methods please check the `Pecee\\Http\\Url` class.\n\n# Input \u0026 parameters\n\nsimple-router offers libraries and helpers that makes it easy to manage and manipulate input-parameters like `$_POST`, `$_GET` and `$_FILE`.\n\n## Using the Input class to manage parameters\n\nYou can use the `InputHandler` class to easily access and manage parameters from your request. The `InputHandler` class offers extended features such as copying/moving uploaded files directly on the object, getting file-extension, mime-type etc.\n\n### Get single parameter value\n\n```input($index, $defaultValue, ...$methods);```\n\nTo quickly get a value from a parameter, you can use the `input` helper function.\n\nThis will automatically trim the value and ensure that it's not empty. If it's empty the `$defaultValue` will be returned instead.\n\n**Note:** \nThis function returns a `string` unless the parameters are grouped together, in that case it will return an `array` of values.\n\n**Example:**\n\nThis example matches both POST and GET request-methods and if name is empty the default-value \"Guest\" will be returned. \n\n```php\n$name = input('name', 'Guest', 'post', 'get');\n```\n\n### Get parameter object\n\nWhen dealing with file-uploads it can be useful to retrieve the raw parameter object.\n\n**Search for object with default-value across multiple or specific request-methods:**\n\nThe example below will return an `InputItem` object if the parameter was found or return the `$defaultValue`. If parameters are grouped, it will return an array of `InputItem` objects.\n\n```php\n$object = input()-\u003efind($index, $defaultValue = null, ...$methods);\n```\n\n**Getting specific `$_GET` parameter as `InputItem` object:**\n\nThe example below will return an `InputItem` object if the parameter was found or return the `$defaultValue`. If parameters are grouped, it will return an array of `InputItem` objects.\n\n```php\n$object = input()-\u003eget($index, $defaultValue = null);\n```\n\n**Getting specific `$_POST` parameter as `InputItem` object:**\n\nThe example below will return an `InputItem` object if the parameter was found or return the `$defaultValue`. If parameters are grouped, it will return an array of `InputItem` objects.\n\n```php\n$object = input()-\u003epost($index, $defaultValue = null);\n```\n\n**Getting specific `$_FILE` parameter as `InputFile` object:**\n\nThe example below will return an `InputFile` object if the parameter was found or return the `$defaultValue`. If parameters are grouped, it will return an array of `InputFile` objects.\n\n```php\n$object = input()-\u003efile($index, $defaultValue = null);\n```\n\n### Managing files\n\n```php\n/**\n * Loop through a collection of files uploaded from a form on the page like this\n * \u003cinput type=\"file\" name=\"images[]\" /\u003e\n */\n\n/* @var $image \\Pecee\\Http\\Input\\InputFile */\nforeach(input()-\u003efile('images', []) as $image)\n{\n    if($image-\u003egetMime() === 'image/jpeg') \n    {\n        $destinationFilname = sprintf('%s.%s', uniqid(), $image-\u003egetExtension());\n        $image-\u003emove(sprintf('/uploads/%s', $destinationFilename));\n    }\n}\n\n```\n\n### Get all parameters\n\n```php\n# Get all\n$values = input()-\u003eall();\n\n# Only match specific keys\n$values = input()-\u003eall([\n    'company_name',\n    'user_id'\n]);\n```\n\nAll object implements the `IInputItem` interface and will always contain these methods:\n\n- `getIndex()` - returns the index/key of the input.\n- `setIndex()` - set the index/key of the input.\n- `getName()` - returns a human friendly name for the input (company_name will be Company Name etc).\n- `setName()` - sets a human friendly name for the input (company_name will be Company Name etc).\n- `getValue()` - returns the value of the input.\n- `setValue()` - sets the value of the input.\n\n`InputFile` has the same methods as above along with some other file-specific methods like:\n\n- `getFilename` - get the filename.\n- `getTmpName()` - get file temporary name.\n- `getSize()` - get file size.\n- `move($destination)` - move file to destination.\n- `getContents()` - get file content.\n- `getType()` - get mime-type for file.\n- `getError()` - get file upload error.\n- `hasError()` - returns `bool` if an error occurred while uploading (if `getError` is not 0).\n- `toArray()` - returns raw array\n\n---\n\n### Check if parameters exists\n\nYou can easily if multiple items exists by using the `exists` method. It's simular to `value` as it can be used \nto filter on request-methods and supports both `string` and `array` as parameter value.\n\n**Example:**\n\n```php\nif(input()-\u003eexists(['name', 'lastname'])) {\n\t// Do stuff\n}\n\n/* Similar to code above */\nif(input()-\u003eexists('name') \u0026\u0026 input()-\u003eexists('lastname')) {\n\t// Do stuff\n}\n```\n\n# Events\n\nThis section will help you understand how to register your own callbacks to events in the router.\nIt will also cover the basics of event-handlers; how to use the handlers provided with the router and how to create your own custom event-handlers.\n\n## Available events\n\nThis section contains all available events that can be registered using the `EventHandler`.\n\nAll event callbacks will retrieve a `EventArgument` object as parameter. This object contains easy access to event-name, router- and request instance and any special event-arguments related to the given event. You can see what special event arguments each event returns in the list below.  \n\n| Name                        | Special arguments | Description               | \n| -------------               |-----------      | ----                      | \n| `EVENT_ALL`                 | - | Fires when a event is triggered. |\n| `EVENT_INIT`                | - | Fires when router is initializing and before routes are loaded. |\n| `EVENT_LOAD`                | `loadedRoutes` | Fires when all routes has been loaded and rendered, just before the output is returned. |\n| `EVENT_ADD_ROUTE`           | `route`\u003cbr\u003e`isSubRoute` | Fires when route is added to the router. `isSubRoute` is true when sub-route is rendered. |\n| `EVENT_REWRITE`             | `rewriteUrl`\u003cbr\u003e`rewriteRoute` | Fires when a url-rewrite is and just before the routes are re-initialized. |\n| `EVENT_BOOT`                | `bootmanagers` | Fires when the router is booting. This happens just before boot-managers are rendered and before any routes has been loaded. |\n| `EVENT_RENDER_BOOTMANAGER`  | `bootmanagers`\u003cbr\u003e`bootmanager` | Fires before a boot-manager is rendered. |\n| `EVENT_LOAD_ROUTES`         | `routes` | Fires when the router is about to load all routes. |\n| `EVENT_FIND_ROUTE`          | `name` | Fires whenever the `findRoute` method is called within the `Router`. This usually happens when the router tries to find routes that contains a certain url, usually after the `EventHandler::EVENT_GET_URL` event. |\n| `EVENT_GET_URL`             | `name`\u003cbr\u003e`parameters`\u003cbr\u003e`getParams` | Fires whenever the `SimpleRouter::getUrl` method or `url`-helper function is called and the router tries to find the route. |\n| `EVENT_MATCH_ROUTE`         | `route` | Fires when a route is matched and valid (correct request-type etc). and before the route is rendered. |\n| `EVENT_RENDER_ROUTE`        | `route` | Fires before a route is rendered. |\n| `EVENT_LOAD_EXCEPTIONS`     | `exception`\u003cbr\u003e`exceptionHandlers` | Fires when the router is loading exception-handlers. |\n| `EVENT_RENDER_EXCEPTION`    | `exception`\u003cbr\u003e`exceptionHandler`\u003cbr\u003e`exceptionHandlers` | Fires before the router is rendering a exception-handler. |\n| `EVENT_RENDER_MIDDLEWARES`  | `route`\u003cbr\u003e`middlewares` | Fires before middlewares for a route is rendered. |\n| `EVENT_RENDER_CSRF`         | `csrfVerifier` | Fires before the CSRF-verifier is rendered. |\n\n## Registering new event\n\nTo register a new event you need to create a new instance of the `EventHandler` object. On this object you can add as many callbacks as you like by calling the `registerEvent` method.\n\nWhen you've registered events, make sure to add it to the router by calling \n`SimpleRouter::addEventHandler()`. We recommend that you add your event-handlers within your `routes.php`.\n\n**Example:**\n\n```php\nuse Pecee\\SimpleRouter\\Handlers\\EventHandler;\nuse Pecee\\SimpleRouter\\Event\\EventArgument;\n\n// --- your routes goes here ---\n\n$eventHandler = new EventHandler();\n\n// Add event that fires when a route is rendered\n$eventHandler-\u003eregister(EventHandler::EVENT_RENDER_ROUTE, function(EventArgument $argument) {\n   \n   // Get the route by using the special argument for this event.\n   $route = $argument-\u003eroute;\n   \n   // DO STUFF...\n    \n});\n\nSimpleRouter::addEventHandler($eventHandler);\n\n```\n\n## Custom EventHandlers\n\n`EventHandler` is the class that manages events and must inherit from the `IEventHandler` interface. The handler knows how to handle events for the given handler-type. \n\nMost of the time the basic `\\Pecee\\SimpleRouter\\Handler\\EventHandler` class will be more than enough for most people as you simply register an event which fires when triggered.\n\nLet's go over how to create your very own event-handler class.\n\nBelow is a basic example of a custom event-handler called `DatabaseDebugHandler`. The idea of the sample below is to logs all events to the database when triggered. Hopefully it will be enough to give you an idea on how the event-handlers work.\n\n```php\nnamespace Demo\\Handlers;\n\nuse Pecee\\SimpleRouter\\Event\\EventArgument;\nuse Pecee\\SimpleRouter\\Router;\n\nclass DatabaseDebugHandler implements IEventHandler\n{\n\n    /**\n     * Debug callback\n     * @var \\Closure\n     */\n    protected $callback;\n\n    public function __construct()\n    {\n        $this-\u003ecallback = function (EventArgument $argument) {\n            // todo: store log in database\n        };\n    }\n\n    /**\n     * Get events.\n     *\n     * @param string|null $name Filter events by name.\n     * @return array\n     */\n    public function getEvents(?string $name): array\n    {\n        return [\n            $name =\u003e [\n                $this-\u003ecallback,\n            ],\n        ];\n    }\n\n    /**\n     * Fires any events registered with given event-name\n     *\n     * @param Router $router Router instance\n     * @param string $name Event name\n     * @param array ...$eventArgs Event arguments\n     */\n    public function fireEvents(Router $router, string $name, ...$eventArgs): void\n    {\n        $callback = $this-\u003ecallback;\n        $callback(new EventArgument($router, $eventArgs));\n    }\n\n    /**\n     * Set debug callback\n     *\n     * @param \\Closure $event\n     */\n    public function setCallback(\\Closure $event): void\n    {\n        $this-\u003ecallback = $event;\n    }\n\n}\n```\n\n---\n\n# Advanced\n\n## Multiple route rendering\n\nIf you need multiple routes to be executed on the same url, you can enable this feature by setting `SimpleRouter::enableMultiRouteRendering(true)`\nin your `routes.php` file.\n\nThis is most commonly used in advanced cases, for example in CMS systems where multiple routes needs to be rendered.\n\n## Restrict access to IP\n\nYou can white and/or blacklist access to IP's using the build in `IpRestrictAccess` middleware.\n\nCreate your own custom Middleware and extend the `IpRestrictAccess` class.\n\nThe `IpRestrictAccess` class contains two properties `ipBlacklist` and `ipWhitelist` that can be added to your middleware to change which IP's that have access to your routes.\n\nYou can use `*` to restrict access to a range of ips.\n\n```php\nuse \\Pecee\\Http\\Middleware\\IpRestrictAccess;\n\nclass IpBlockerMiddleware extends IpRestrictAccess \n{\n\n    protected $ipBlacklist = [\n        '5.5.5.5',\n        '8.8.*',\n    ];\n\n    protected $ipWhitelist = [\n        '8.8.2.2',\n    ];\n\n}\n```\n\nYou can add the middleware to multiple routes by adding your [middleware to a group](#middleware).\n\n## Setting custom base path\n\nSometimes it can be useful to add a custom base path to all of the routes added.\n\nThis can easily be done by taking advantage of the [Event Handlers](#events) support of the project.\n\n```php\n$basePath = '/basepath';\n\n$eventHandler = new EventHandler();\n$eventHandler-\u003eregister(EventHandler::EVENT_ADD_ROUTE, function(EventArgument $event) use($basePath) {\n\n\t$route = $event-\u003eroute;\n\n\t// Skip routes added by group as these will inherit the url\n\tif(!$event-\u003eisSubRoute) {\n\t\treturn;\n\t}\n\t\n\tswitch (true) {\n\t\tcase $route instanceof ILoadableRoute:\n\t\t\t$route-\u003eprependUrl($basePath);\n\t\t\tbreak;\n\t\tcase $route instanceof IGroupRoute:\n\t\t\t$route-\u003eprependPrefix($basePath);\n\t\t\tbreak;\n\n\t}\n\t\n});\n\nSimpleRouter::addEventHandler($eventHandler);\n```\n\nIn the example shown above, we create a new `EVENT_ADD_ROUTE` event that triggers, when a new route is added.\nWe skip all subroutes as these will inherit the url from their parent. Then, if the route is a group, we change the prefix  \notherwise we change the url.\n\n## Url rewriting\n\n### Changing current route\n\nSometimes it can be useful to manipulate the route about to be loaded.\nsimple-php-router allows you to easily manipulate and change the routes which are about to be rendered.\nAll information about the current route is stored in the `\\Pecee\\SimpleRouter\\Router` instance's `loadedRoute` property.\n\nFor easy access you can use the shortcut helper function `request()` instead of calling the class directly `\\Pecee\\SimpleRouter\\SimpleRouter::router()`.\n\n\n```php\nrequest()-\u003esetRewriteCallback('Example\\MyCustomClass@hello');\n\n// -- or you can rewrite by url --\n\nrequest()-\u003esetRewriteUrl('/my-rewrite-url');\n```\n\n### Bootmanager: loading routes dynamically\n\nSometimes it can be necessary to keep urls stored in the database, file or similar. In this example, we want the url ```/my-cat-is-beatiful``` to load the route ```/article/view/1``` which the router knows, because it's defined in the ```routes.php``` file.\n\nTo interfere with the router, we create a class that implements the ```IRouterBootManager``` interface. This class will be loaded before any other rules in ```routes.php``` and allow us to \"change\" the current route, if any of our criteria are fulfilled (like coming from the url ```/my-cat-is-beatiful```).\n\n```php\nuse Pecee\\Http\\Request;\nuse Pecee\\SimpleRouter\\IRouterBootManager;\nuse Pecee\\SimpleRouter\\Router;\n\nclass CustomRouterRules implement IRouterBootManager \n{\n\n    /**\n     * Called when router is booting and before the routes is loaded.\n     *\n     * @param \\Pecee\\SimpleRouter\\Router $router\n     * @param \\Pecee\\Http\\Request $request\n     */\n    public function boot(\\Pecee\\SimpleRouter\\Router $router, \\Pecee\\Http\\Request $request): void\n    {\n\n        $rewriteRules = [\n            '/my-cat-is-beatiful' =\u003e '/article/view/1',\n            '/horses-are-great'   =\u003e '/article/view/2',\n        ];\n\n        foreach($rewriteRules as $url =\u003e $rule) {\n\n            // If the current url matches the rewrite url, we use our custom route\n\n            if($request-\u003egetUrl()-\u003econtains($url)) {\n                $request-\u003esetRewriteUrl($rule);\n            }\n        }\n\n    }\n\n}\n```\n\nThe above should be pretty self-explanatory and can easily be changed to loop through urls store in the database, file or cache.\n\nWhat happens is that if the current route matches the route defined in the index of our ```$rewriteRules``` array, we set the route to the array value instead.\n\nBy doing this the route will now load the url ```/article/view/1``` instead of ```/my-cat-is-beatiful```.\n\nThe last thing we need to do, is to add our custom boot-manager to the ```routes.php``` file. You can create as many bootmanagers as you like and easily add them in your ```routes.php``` file.\n\n```php\nSimpleRouter::addBootManager(new CustomRouterRules());\n```\n\n### Adding routes manually\n\nThe ```SimpleRouter``` class referenced in the previous example, is just a simple helper class that knows how to communicate with the ```Router``` class.\nIf you are up for a challenge, want the full control or simply just want to create your own ```Router``` helper class, this example is for you.\n\n```php\nuse \\Pecee\\SimpleRouter\\Router;\nuse \\Pecee\\SimpleRouter\\Route\\RouteUrl;\n\n/* Create new Router instance */\n$router = new Router();\n\n$route = new RouteUrl('/answer/1', function() {\n\n    die('this callback will match /answer/1');\n\n});\n\n$route-\u003eaddMiddleware(\\Demo\\Middlewares\\AuthMiddleware::class);\n$route-\u003esetNamespace('\\Demo\\Controllers');\n$route-\u003esetPrefix('v1');\n\n/* Add the route to the router */\n$router-\u003eaddRoute($route);\n```\n\n## Custom class loader\n\nYou can easily extend simple-router to support custom injection frameworks like php-di by taking advantage of the ability to add your custom class-loader.\n\nClass-loaders must inherit the `IClassLoader` interface.\n\n**Example:**\n\n```php\nclass MyCustomClassLoader implements IClassLoader\n{\n    /**\n     * Load class\n     *\n     * @param string $class\n     * @return object\n     * @throws NotFoundHttpException\n     */\n    public function loadClass(string $class)\n    {\n        if (\\class_exists($class) === false) {\n            throw new NotFoundHttpException(sprintf('Class \"%s\" does not exist', $class), 404);\n        }\n\n        return new $class();\n    }\n    \n    /**\n     * Called when loading class method\n     * @param object $class\n     * @param string $method\n     * @param array $parameters\n     * @return object\n     */\n    public function loadClassMethod($class, string $method, array $parameters)\n    {\n        return call_user_func_array([$class, $method], array_values($parameters));\n    }\n\n    /**\n     * Load closure\n     *\n     * @param Callable $closure\n     * @param array $parameters\n     * @return mixed\n     */\n    public function loadClosure(Callable $closure, array $parameters)\n    {\n        return \\call_user_func_array($closure, array_values($parameters));\n    }\n\n}\n```\n\nNext, we need to configure our `routes.php` so the router uses our `MyCustomClassLoader` class for loading classes. This can be done by adding the following line to your `routes.php` file.\n\n```php\nSimpleRouter::setCustomClassLoader(new MyCustomClassLoader());\n```\n\n### Integrating with php-di\n\nphp-di support was discontinued by version 4.3, however you can easily add it again by creating your own class-loader like the example below:\n\n```php\nuse Pecee\\SimpleRouter\\ClassLoader\\IClassLoader;\nuse Pecee\\SimpleRouter\\Exceptions\\ClassNotFoundHttpException;\n\nclass MyCustomClassLoader implements IClassLoader\n{\n\n    protected $container;\n\n    public function __construct()\n    {\n        // Create our new php-di container\n        $this-\u003econtainer = (new \\DI\\ContainerBuilder())\n                    -\u003euseAutowiring(true)\n                    -\u003ebuild();\n    }\n\n    /**\n     * Load class\n     *\n     * @param string $class\n     * @return object\n     * @throws ClassNotFoundHttpException\n     */\n    public function loadClass(string $class)\n    {\n        if ($this-\u003econtainer-\u003ehas($class) === false) {\n            throw new ClassNotFoundHttpException($class, null, sprintf('Class \"%s\" does not exist', $class), 404, null);\n        }\n        return $this-\u003econtainer-\u003eget($class);\n    }\n    \n    /**\n     * Called when loading class method\n     * @param object $class\n     * @param string $method\n     * @param array $parameters\n     * @return string\n     */\n    public function loadClassMethod($class, string $method, array $parameters)\n    {\n        return (string)$this-\u003econtainer-\u003ecall([$class, $method], $parameters);\n    }\n\n    /**\n     * Load closure\n     *\n     * @param Callable $closure\n     * @param array $parameters\n     * @return string\n     */\n    public function loadClosure(callable $closure, array $parameters)\n    {\n        return (string)$this-\u003econtainer-\u003ecall($closure, $parameters);\n    }\n}\n```\n\n## Parameters\n\nThis section contains advanced tips \u0026 tricks on extending the usage for parameters.\n\n## Extending\n\nThis is a simple example of an integration into a framework.\n\nThe framework has it's own ```Router``` class which inherits from the ```SimpleRouter``` class. This allows the framework to add custom functionality like loading a custom `routes.php` file or add debugging information etc.\n\n```php\nnamespace Demo;\n\nuse Pecee\\SimpleRouter\\SimpleRouter;\n\nclass Router extends SimpleRouter {\n\n    public static function start() {\n\n        // change this to whatever makes sense in your project\n        require_once 'routes.php';\n\n        // change default namespace for all routes\n        parent::setDefaultNamespace('\\Demo\\Controllers');\n\n        // Do initial stuff\n        parent::start();\n\n    }\n\n}\n```\n\n---\n\n# Help and support\n\nThis section will go into details on how to debug the router and answer some of the commonly asked questions- and issues.\n\n## Common issues and fixes\n\nThis section will go over common issues and how to resolve them.\n\n### Parameters won't match or route not working with special characters\n\nOften people experience this issue when one or more parameters contains special characters. The router uses a sparse regular-expression that matches letters from a-z along with numbers when matching parameters, to improve performance. \n\nAll other characters has to be defined via the `defaultParameterRegex` option on your route.\n\nYou can read more about adding your own custom regular expression for matching parameters by [clicking here](#custom-regex-for-matching-parameters).\n\n### Multiple routes matches? Which one has the priority?\n\nThe router will match routes in the order they're added and will render multiple routes, if they match.\n\nIf you want the router to stop when a route is matched, you simply return a value in your callback or stop the execution manually (using `response()-\u003ejson()` etc.) or simply by returning a result.\n\nAny returned objects that implements the `__toString()` magic method will also prevent other routes from being rendered. \n\nIf you want the router only to execute one route per request, you can [disabling multiple route rendering](#disable-multiple-route-rendering).\n\n### Using the router on sub-paths\n\nPlease refer to [Setting custom base path](#setting-custom-base-path) part of the documentation.\n\n## Debugging\n\nThis section will show you how to write unit-tests for the router, view useful debugging information and answer some of the frequently asked questions. \n\nIt will also covers how to report any issue you might encounter. \n\n### Creating unit-tests\n\nThe easiest and fastest way to debug any issues with the router, is to create a unit-test that represents the issue you are experiencing.\n\nUnit-tests use a special `TestRouter` class, which simulates a request-method and requested url of a browser.\n\nThe `TestRouter` class can return the output directly or render a route silently.\n\n```php\npublic function testUnicodeCharacters()\n{\n    // Add route containing two optional paramters with special spanish characters like \"í\".\n    TestRouter::get('/cursos/listado/{listado?}/{category?}', 'DummyController@method1', ['defaultParameterRegex' =\u003e '[\\w\\p{L}\\s-]+']);\n    \n    // Start the routing and simulate the url \"/cursos/listado/especialidad/cirugía local\".\n    TestRouter::debugNoReset('/cursos/listado/especialidad/cirugía local', 'GET');\n    \n    // Verify that the url for the loaded route matches the expected route.\n    $this-\u003eassertEquals('/cursos/listado/{listado?}/{category?}/', TestRouter::router()-\u003egetRequest()-\u003egetLoadedRoute()-\u003egetUrl());\n    \n    // Start the routing and simulate the url \"/test/Dermatología\" using \"GET\" as request-method.\n    TestRouter::debugNoReset('/test/Dermatología', 'GET');\n\n    // Another route containing one parameter with special spanish characters like \"í\".\n    TestRouter::get('/test/{param}', 'DummyController@method1', ['defaultParameterRegex' =\u003e '[\\w\\p{L}\\s-\\í]+']);\n\n    // Get all parameters parsed by the loaded route.\n    $parameters = TestRouter::request()-\u003egetLoadedRoute()-\u003egetParameters();\n\n    // Check that the parameter named \"param\" matches the exspected value.\n    $this-\u003eassertEquals('Dermatología', $parameters['param']);\n\n    // Add route testing danish special characters like \"ø\".\n    TestRouter::get('/category/økse', 'DummyController@method1', ['defaultParameterRegex' =\u003e '[\\w\\ø]+']);\n    \n    // Start the routing and simulate the url \"/kategory/økse\" using \"GET\" as request-method.\n    TestRouter::debugNoReset('/category/økse', 'GET');\n    \n    // Validate that the URL of the loaded-route matches the expected url.\n    $this-\u003eassertEquals('/category/økse/', TestRouter::router()-\u003egetRequest()-\u003egetLoadedRoute()-\u003egetUrl());\n\n    // Reset the router, so other tests wont inherit settings or the routes we've added.\n    TestRouter::router()-\u003ereset();\n}\n```\n\n#### Using the TestRouter helper\n\nDepending on your test, you can use the methods below when rendering routes in your unit-tests.\n\n\n| Method        | Description  |\n| ------------- |-------------|\n| ```TestRouter::debug($url, $method)``` | Will render the route without returning anything. Exceptions will be thrown and the router will be reset automatically. |\n| ```TestRouter::debugOutput($url, $method)``` | Will render the route and return any value that the route might output. Manual reset required by calling `TestRouter::router()-\u003ereset()`. |\n| ```TestRouter::debugNoReset($url, $method);```  | Will render the route without resetting the router. Useful if you need to get loaded route, parameters etc. from the router. Manual reset required by calling `TestRouter::router()-\u003ereset()`. |\n\n### Debug information\n\nThe library can output debug-information, which contains information like loaded routes, the parsed request-url etc. It also contains info which are important when reporting a new issue like PHP-version, library version, server-variables, router debug log etc.\n\nYou can activate the debug-information by calling the alternative start-method. \n\nThe example below will start the routing an return array with debugging-information\n\n**Example:**\n\n```php\n$debugInfo = SimpleRouter::startDebug();\necho sprintf('\u003cpre\u003e%s\u003c/pre\u003e', var_export($debugInfo));\nexit;\n```\n\n**The example above will provide you with an output containing:**\n\n| Key               | Description  |\n| -------------     |------------- |\n| `url`             | The parsed request-uri. This url should match the url in the browser.|\n| `method`          | The browsers request method (example: `GET`, `POST`, `PUT`, `PATCH`, `DELETE` etc).|\n| `host`            | The website host (example: `domain.com`).|\n| `loaded_routes`   | List of all the routes that matched the `url` and that has been rendered/loaded. |\n| `all_routes`      | All available routes |\n| `boot_managers`   | All available BootManagers |\n| `csrf_verifier`   | CsrfVerifier class |\n| `log`             | List of debug messages/log from the router. |\n| `router_output`   | The rendered callback output from the router. |\n| `library_version` | The version of simple-php-router you are using. |\n| `php_version`     | The version of PHP you are using. |\n| `server_params`   | List of all `$_SERVER` variables/headers. | \n\n#### Benchmark and logging\n\nYou can activate benchmark debugging/logging by calling `setDebugEnabled` method on the `Router` instance.\n\nYou have to enable debugging BEFORE starting the routing.\n\n**Example:**\n\n```php\nSimpleRouter::router()-\u003esetDebugEnabled(true);\nSimpleRouter::start();\n```\n\nWhen the routing is complete, you can get the debug-log by calling the `getDebugLog()` on the `Router` instance. This will return an `array` of log-messages each containing execution time, trace info and debug-message.\n\n**Example:**\n\n```php\n$messages = SimpleRouter::router()-\u003egetDebugLog();\n```\n\n## Reporting a new issue\n\n**Before reporting your issue, make sure that the issue you are experiencing aren't already answered in the [Common errors](#common-errors) section or by searching the [closed issues](https://github.com/skipperbent/simple-php-router/issues?q=is%3Aissue+is%3Aclosed) page on GitHub.**\n\nTo avoid confusion and to help you resolve your issue as quickly as possible, you should provide a detailed explanation of the problem you are experiencing.\n\n### Procedure for reporting a new issue\n\n1. Go to [this page](https://github.com/skipperbent/simple-php-router/issues/new) to create a new issue.\n2. Add a title that describes your problems in as few words as possible.\n3. Copy and paste the template below in the description of your issue and replace each step with your own information. If the step is not relevant for your issue you can delete it.\n\n### Issue template\n\nCopy and paste the template below into the description of your new issue and replace it with your own information.\n\nYou can check the [Debug information](#debug-information) section to see how to generate the debug-info.\n\n\u003cpre\u003e\n### Description\n\nThe library fails to render the route `/user/æsel` which contains one parameter using a custom regular expression for matching special foreign characters. Routes without special characters like `/user/tom` renders correctly.\n\n### Steps to reproduce the error\n\n1. Add the following route:\n\n```php\nSimpleRouter::get('/user/{name}', 'UserController@show')-\u003ewhere(['name' =\u003e '[\\w]+']);\n```\n\n2. Navigate to `/user/æsel` in browser.\n\n3. `NotFoundHttpException` is thrown by library.\n\n### Route and/or callback for failing route\n\n*Route:*\n\n```php\nSimpleRouter::get('/user/{name}', 'UserController@show')-\u003ewhere(['name' =\u003e '[\\w]+']);\n```\n\n*Callback:*\n\n```php\npublic function show($username) {\n    return sprintf('Username is: %s', $username);\n}\n```\n\n### Debug info\n\n```php\n\n[PASTE YOUR DEBUG-INFO HERE]\n\n```\n\u003c/pre\u003e\n\nRemember that a more detailed issue- description and debug-info might suck to write, but it will help others understand- and resolve your issue without asking for the information.\n\n**Note:** please be as detailed as possible in the description when creating a new issue. This will help others to more easily understand- and solve your issue. Providing the necessary steps to reproduce the error within your description, adding useful debugging info etc. will help others quickly resolve the issue you are reporting.\n\n## Feedback and development\n\nIf the library is missing a feature that you need in your project or if you have feedback, we'd love to hear from you. \nFeel free to leave us feedback by [creating a new issue](https://github.com/skipperbent/simple-php-router/issues/new).\n\n**Experiencing an issue?**\n\nPlease refer to our [Help and support](#help-and-support) section in the documentation before reporting a new issue.\n\n### Contribution development guidelines\n\n- Please try to follow the PSR-2 codestyle guidelines.\n\n- Please create your pull requests to the development base that matches the version number you want to change.\nFor example when pushing changes to version 3, the pull request should use the `v3-development` base/branch.\n\n- Create detailed descriptions for your commits, as these will be used in the changelog for new releases.\n\n- When changing existing functionality, please ensure that the unit-tests working.\n\n- When adding new stuff, please remember to add new unit-tests for the functionality.\n\n---\n\n# Credits\n\n## Sites\n\nThis is some sites that uses the simple-router project in production.\n\n- [holla.dk](http://www.holla.dk)\n- [ninjaimg.com](http://ninjaimg.com)\n- [bookandbegin.com](https://bookandbegin.com)\n- [dscuz.com](https://www.dscuz.com)\n\n## License\n\n### The MIT License (MIT)\n\nCopyright (c) 2016 Simon Sessingø / simple-php-router\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","funding_links":["https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=NNX4D2RUSALCN"],"categories":["PHP"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskipperbent%2Fsimple-php-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskipperbent%2Fsimple-php-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskipperbent%2Fsimple-php-router/lists"}