mirror of
https://github.com/skipperbent/simple-php-router.git
synced 2026-06-17 08:47:52 +00:00
@@ -7,9 +7,31 @@ Simple, fast and yet powerful PHP router that is easy to get integrated and in a
|
|||||||
|
|
||||||
The 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.
|
The 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.
|
||||||
|
|
||||||
### Ideas and issues
|
### Feedback and development
|
||||||
|
|
||||||
If you want a great new feature or experience any issues what-so-ever, please feel free to leave an issue and i'll look into it whenever possible.
|
If you are missing a feature, experience problems or have ideas or feedback that you want us to hear, please feel free to create an issue.
|
||||||
|
|
||||||
|
###### Issues guidelines
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
For example: if you are experiencing issues, you should provide the necessary steps to reproduce the error within your description.
|
||||||
|
|
||||||
|
- We love to hear out any ideas or feedback to the library.
|
||||||
|
|
||||||
|
[Create a new issue here](https://github.com/skipperbent/simple-php-router/issues/new)
|
||||||
|
|
||||||
|
###### Contribution development guidelines
|
||||||
|
|
||||||
|
- Please try to follow the PSR-2 codestyle guidelines.
|
||||||
|
|
||||||
|
- Please create your pull requests to the development base that matches the version number you want to change.
|
||||||
|
For example when pushing changes to version 3, the pull request should use the `v3-development` base/branch.
|
||||||
|
|
||||||
|
- Create detailed descriptions for your commits, as these will be used in the changelog for new releases.
|
||||||
|
|
||||||
|
- When changing existing functionality, please ensure that the unit-tests working.
|
||||||
|
|
||||||
|
- When adding new stuff, please remember to add new unit-tests for the functionality.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -51,6 +73,8 @@ If you want a great new feature or experience any issues what-so-ever, please fe
|
|||||||
- [CSRF-protection](#csrf-protection)
|
- [CSRF-protection](#csrf-protection)
|
||||||
- [Adding CSRF-verifier](#adding-csrf-verifier)
|
- [Adding CSRF-verifier](#adding-csrf-verifier)
|
||||||
- [Getting CSRF-token](#getting-csrf-token)
|
- [Getting CSRF-token](#getting-csrf-token)
|
||||||
|
- [Custom CSRF-verifier](#custom-csrf-verifier)
|
||||||
|
- [Custom Token-provider](#custom-token-provider)
|
||||||
|
|
||||||
- [Middlewares](#middlewares)
|
- [Middlewares](#middlewares)
|
||||||
- [Example](#example)
|
- [Example](#example)
|
||||||
@@ -687,11 +711,57 @@ SimpleRouter::get('/page/404', 'ControllerPage@notFound', ['as' => 'page.notfoun
|
|||||||
|
|
||||||
# CSRF Protection
|
# CSRF Protection
|
||||||
|
|
||||||
Any forms posting to `POST`, `PUT` or `DELETE` routes should include the CSRF-token. We strongly recommend that you create your enable CSRF-verification on your site.
|
Any 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.
|
||||||
|
|
||||||
Create a new class and extend the ```BaseCsrfVerifier``` middleware class provided with simple-php-router.
|
You 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.
|
||||||
|
|
||||||
Add the property ```except``` with an array of the urls to the routes you would like to exclude/whitelist from the CSRF validation. Using ```*``` at the end for the url will match the entire url.
|
By default simple-php-router will use the `CookieTokenProvider` class. This provider will store the security-token in a cookie on the clients machine.
|
||||||
|
If you want to store the token elsewhere, please refer to the "Creating custom Token Provider" section below.
|
||||||
|
|
||||||
|
## Adding CSRF-verifier
|
||||||
|
|
||||||
|
When 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:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Router::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
|
||||||
|
```
|
||||||
|
|
||||||
|
## Getting CSRF-token
|
||||||
|
|
||||||
|
When posting to any of the urls that has CSRF-verification enabled, you need post your CSRF-token or else the request will get rejected.
|
||||||
|
|
||||||
|
You can get the CSRF-token by calling the helper method:
|
||||||
|
|
||||||
|
```php
|
||||||
|
csrf_token();
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also get the token directly:
|
||||||
|
|
||||||
|
```php
|
||||||
|
return Router::router()->getCsrfVerifier()->getTokenProvider()->getToken();
|
||||||
|
```
|
||||||
|
|
||||||
|
The default name/key for the input-field is `csrf_token` and is defined in the `POST_KEY` constant in the `BaseCsrfVerifier` class.
|
||||||
|
You can change the key by overwriting the constant in your own CSRF-verifier class.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
The example below will post to the current url with a hidden field "`csrf_token`".
|
||||||
|
|
||||||
|
```html
|
||||||
|
<form method="post" action="<?= url(); ?>">
|
||||||
|
<input type="hidden" name="csrf_token" value="<?= csrf_token(); ?>">
|
||||||
|
<!-- other input elements here -->
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom CSRF-verifier
|
||||||
|
|
||||||
|
Create a new class and extend the `BaseCsrfVerifier` middleware class provided by default with the simple-php-router library.
|
||||||
|
|
||||||
|
Add the property `except` with an array of the urls to the routes you want to exclude/whitelist from the CSRF validation.
|
||||||
|
Using ```*``` at the end for the url will match the entire url.
|
||||||
|
|
||||||
**Here's a basic example on a CSRF-verifier class:**
|
**Here's a basic example on a CSRF-verifier class:**
|
||||||
|
|
||||||
@@ -709,36 +779,45 @@ class CsrfVerifier extends BaseCsrfVerifier
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Adding CSRF-verifier
|
## Custom Token Provider
|
||||||
|
|
||||||
When 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:
|
By default the `BaseCsrfVerifier` will use the `CookieTokenProvider` to store the token in a cookie on the clients machine.
|
||||||
|
|
||||||
|
If you need to store the token elsewhere, you can do that by creating your own class and implementing the `ITokenProvider` class.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
Router::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
|
class SessionTokenProvider implements ITokenProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh existing token
|
||||||
|
*/
|
||||||
|
public function refresh()
|
||||||
|
{
|
||||||
|
// Implement your own functionality here...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate valid CSRF token
|
||||||
|
*
|
||||||
|
* @param string $token
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function validate($token)
|
||||||
|
{
|
||||||
|
// Implement your own functionality here...
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getting CSRF-token
|
Next you need to set your custom `ITokenProvider` implementation on your `BaseCsrfVerifier` class in your routes file:
|
||||||
|
|
||||||
When posting to any of the urls that has CSRF-verification enabled, you need post your CSRF-token or else the request will get rejected.
|
|
||||||
|
|
||||||
You can get the CSRF-token by calling the helper method:
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
csrf_token();
|
$verifier = new \dscuz\Middleware\CsrfVerifier();
|
||||||
```
|
$verifier->setTokenProvider(new SessionTokenProvider());
|
||||||
|
|
||||||
The default name/key for the input-field is `csrf_token` and is defined in the `POST_KEY` constant in the `BaseCsrfVerifier` class.
|
Router::csrfVerifier($verifier);
|
||||||
You can change the key by overwriting the constant in your own CSRF-verifier class.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
The example below will post to the current url with a hidden field "`csrf_token`".
|
|
||||||
|
|
||||||
```html
|
|
||||||
<form method="post" action="<?= url(); ?>">
|
|
||||||
<input type="hidden" name="csrf_token" value="<?= csrf_token(); ?>">
|
|
||||||
<!-- other input elements here -->
|
|
||||||
</form>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -1034,6 +1113,7 @@ All object implements the `IInputItem` interface and will always contain these m
|
|||||||
- `getValue()` - returns the value of the input.
|
- `getValue()` - returns the value of the input.
|
||||||
|
|
||||||
`InputFile` has the same methods as above along with some other file-specific methods like:
|
`InputFile` has the same methods as above along with some other file-specific methods like:
|
||||||
|
- `getFilename` - get the filename.
|
||||||
- `getTmpName()` - get file temporary name.
|
- `getTmpName()` - get file temporary name.
|
||||||
- `getSize()` - get file size.
|
- `getSize()` - get file size.
|
||||||
- `move($destination)` - move file to destination.
|
- `move($destination)` - move file to destination.
|
||||||
@@ -1057,7 +1137,7 @@ $siteId = input('site_id', 2, ['post', 'get']);
|
|||||||
## Url rewriting
|
## Url rewriting
|
||||||
Sometimes it can be useful to manipulate the route about to be loaded.
|
Sometimes it can be useful to manipulate the route about to be loaded.
|
||||||
simple-php-router allows you to easily change the route about to be executed.
|
simple-php-router allows you to easily change the route about to be executed.
|
||||||
All information about the current route is stored in the ```\Pecee\SimpleRouter\Router``` instance's `loadedRoute` property.
|
All information about the current route is stored in the `\Pecee\SimpleRouter\Router` instance's `loadedRoute` property.
|
||||||
|
|
||||||
For easy access you can use the shortcut method `\Pecee\SimpleRouter\SimpleRouter::router()`.
|
For easy access you can use the shortcut method `\Pecee\SimpleRouter\SimpleRouter::router()`.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -73,7 +73,7 @@ function csrf_token()
|
|||||||
{
|
{
|
||||||
$baseVerifier = Router::router()->getCsrfVerifier();
|
$baseVerifier = Router::router()->getCsrfVerifier();
|
||||||
if ($baseVerifier !== null) {
|
if ($baseVerifier !== null) {
|
||||||
return $baseVerifier->getToken();
|
return $baseVerifier->getTokenProvider()->getToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class Input
|
|||||||
public function parseInputs()
|
public function parseInputs()
|
||||||
{
|
{
|
||||||
/* Parse get requests */
|
/* Parse get requests */
|
||||||
if (count($_GET) > 0) {
|
if (count($_GET) !== 0) {
|
||||||
$this->get = $this->handleGetPost($_GET);
|
$this->get = $this->handleGetPost($_GET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,12 +46,12 @@ class Input
|
|||||||
parse_str(file_get_contents('php://input'), $postVars);
|
parse_str(file_get_contents('php://input'), $postVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($postVars) > 0) {
|
if (count($postVars) !== 0) {
|
||||||
$this->post = $this->handleGetPost($postVars);
|
$this->post = $this->handleGetPost($postVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse get requests */
|
/* Parse get requests */
|
||||||
if (count($_FILES) > 0) {
|
if (count($_FILES) !== 0) {
|
||||||
$this->file = $this->parseFiles();
|
$this->file = $this->parseFiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ class Input
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$keys = [];
|
$keys = [$key];
|
||||||
|
|
||||||
$files = $this->rearrangeFiles($value['name'], $keys, $value);
|
$files = $this->rearrangeFiles($value['name'], $keys, $value);
|
||||||
|
|
||||||
@@ -87,6 +87,9 @@ class Input
|
|||||||
protected function rearrangeFiles(array $values, &$index, $original)
|
protected function rearrangeFiles(array $values, &$index, $original)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
$originalIndex = $index[0];
|
||||||
|
array_shift($index);
|
||||||
|
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
$getItem = function ($key, $property = 'name') use ($original, $index) {
|
$getItem = function ($key, $property = 'name') use ($original, $index) {
|
||||||
@@ -107,7 +110,7 @@ class Input
|
|||||||
if (is_array($getItem($key)) === false) {
|
if (is_array($getItem($key)) === false) {
|
||||||
|
|
||||||
$file = InputFile::createFromArray([
|
$file = InputFile::createFromArray([
|
||||||
'index' => $key,
|
'index' => (empty($key) === true && empty($originalIndex) === false) ? $originalIndex : $key,
|
||||||
'filename' => $getItem($key),
|
'filename' => $getItem($key),
|
||||||
'error' => $getItem($key, 'error'),
|
'error' => $getItem($key, 'error'),
|
||||||
'tmp_name' => $getItem($key, 'tmp_name'),
|
'tmp_name' => $getItem($key, 'tmp_name'),
|
||||||
@@ -128,7 +131,7 @@ class Input
|
|||||||
|
|
||||||
$files = $this->rearrangeFiles($value, $index, $original);
|
$files = $this->rearrangeFiles($value, $index, $original);
|
||||||
|
|
||||||
if (isset($output[$key])) {
|
if (isset($output[$key]) === true) {
|
||||||
$output[$key][] = $files;
|
$output[$key][] = $files;
|
||||||
} else {
|
} else {
|
||||||
$output[$key] = $files;
|
$output[$key] = $files;
|
||||||
@@ -217,15 +220,15 @@ class Input
|
|||||||
|
|
||||||
$element = null;
|
$element = null;
|
||||||
|
|
||||||
if ($methods === null || in_array('get', $methods)) {
|
if ($methods === null || in_array('get', $methods, false) === true) {
|
||||||
$element = $this->findGet($index);
|
$element = $this->findGet($index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($element === null && $methods === null) || ($methods !== null && in_array('post', $methods))) {
|
if (($element === null && $methods === null) || ($methods !== null && in_array('post', $methods, false) === true)) {
|
||||||
$element = $this->findPost($index);
|
$element = $this->findPost($index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($element === null && $methods === null) || ($methods !== null && in_array('file', $methods))) {
|
if (($element === null && $methods === null) || ($methods !== null && in_array('file', $methods, false) === true)) {
|
||||||
$element = $this->findFile($index);
|
$element = $this->findFile($index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class InputFile implements IInputItem
|
|||||||
$this->index = $index;
|
$this->index = $index;
|
||||||
|
|
||||||
// Make the name human friendly, by replace _ with space
|
// Make the name human friendly, by replace _ with space
|
||||||
$this->name = ucfirst(str_replace('_', ' ', $this->index));
|
$this->name = ucfirst(str_replace('_', ' ', strtolower($this->index)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,7 +28,7 @@ class InputFile implements IInputItem
|
|||||||
*/
|
*/
|
||||||
public static function createFromArray(array $values)
|
public static function createFromArray(array $values)
|
||||||
{
|
{
|
||||||
if (!isset($values['index'])) {
|
if (isset('index', $values) === false) {
|
||||||
throw new \InvalidArgumentException('Index key is required');
|
throw new \InvalidArgumentException('Index key is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +39,7 @@ class InputFile implements IInputItem
|
|||||||
'type' => null,
|
'type' => null,
|
||||||
'size' => null,
|
'size' => null,
|
||||||
'name' => null,
|
'name' => null,
|
||||||
|
'filename' => null,
|
||||||
'error' => null,
|
'error' => null,
|
||||||
], $values);
|
], $values);
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ class InputFile implements IInputItem
|
|||||||
->setError($values['error'])
|
->setError($values['error'])
|
||||||
->setType($values['type'])
|
->setType($values['type'])
|
||||||
->setTmpName($values['tmp_name'])
|
->setTmpName($values['tmp_name'])
|
||||||
->setFilename($values['name']);
|
->setFilename($values['filename']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,8 +268,9 @@ class InputFile implements IInputItem
|
|||||||
'tmp_name' => $this->tmpName,
|
'tmp_name' => $this->tmpName,
|
||||||
'type' => $this->type,
|
'type' => $this->type,
|
||||||
'size' => $this->size,
|
'size' => $this->size,
|
||||||
'name' => $this->filename,
|
'name' => $this->name,
|
||||||
'error' => $this->error,
|
'error' => $this->error,
|
||||||
|
'filename' => $this->filename,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class InputItem implements IInputItem
|
|||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
|
|
||||||
// Make the name human friendly, by replace _ with space
|
// Make the name human friendly, by replace _ with space
|
||||||
$this->name = ucfirst(str_replace('_', ' ', $this->index));
|
$this->name = ucfirst(str_replace('_', ' ', strtolower($this->index)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
namespace Pecee\Http\Middleware;
|
namespace Pecee\Http\Middleware;
|
||||||
|
|
||||||
use Pecee\CsrfToken;
|
|
||||||
use Pecee\Http\Middleware\Exceptions\TokenMismatchException;
|
use Pecee\Http\Middleware\Exceptions\TokenMismatchException;
|
||||||
use Pecee\Http\Request;
|
use Pecee\Http\Request;
|
||||||
|
use Pecee\Http\Security\CookieTokenProvider;
|
||||||
|
use Pecee\Http\Security\ITokenProvider;
|
||||||
|
|
||||||
class BaseCsrfVerifier implements IMiddleware
|
class BaseCsrfVerifier implements IMiddleware
|
||||||
{
|
{
|
||||||
@@ -12,15 +13,11 @@ class BaseCsrfVerifier implements IMiddleware
|
|||||||
const HEADER_KEY = 'X-CSRF-TOKEN';
|
const HEADER_KEY = 'X-CSRF-TOKEN';
|
||||||
|
|
||||||
protected $except;
|
protected $except;
|
||||||
protected $csrfToken;
|
protected $tokenProvider;
|
||||||
protected $token;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->csrfToken = new CsrfToken();
|
$this->tokenProvider = new CookieTokenProvider();
|
||||||
|
|
||||||
// Generate or get the CSRF-Token from Cookie.
|
|
||||||
$this->token = $this->csrfToken->getToken($this->generateToken());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +27,7 @@ class BaseCsrfVerifier implements IMiddleware
|
|||||||
*/
|
*/
|
||||||
protected function skip(Request $request)
|
protected function skip(Request $request)
|
||||||
{
|
{
|
||||||
if ($this->except === null || is_array($this->except) === false) {
|
if ($this->except === null || count($this->except) === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,37 +64,29 @@ class BaseCsrfVerifier implements IMiddleware
|
|||||||
$token = $request->getHeader(static::HEADER_KEY);
|
$token = $request->getHeader(static::HEADER_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->csrfToken->validate($token) === false) {
|
if ($this->tokenProvider->validate($token) === false) {
|
||||||
throw new TokenMismatchException('Invalid csrf-token.');
|
throw new TokenMismatchException('Invalid CSRF-token.');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh existing token
|
// Refresh existing token
|
||||||
$this->csrfToken->refresh();
|
$this->tokenProvider->refresh();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateToken()
|
public function getTokenProvider()
|
||||||
{
|
{
|
||||||
$token = CsrfToken::generateToken();
|
return $this->tokenProvider;
|
||||||
$this->csrfToken->setToken($token);
|
|
||||||
|
|
||||||
return $token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasToken()
|
/**
|
||||||
|
* Set token provider
|
||||||
|
* @param ITokenProvider $provider
|
||||||
|
*/
|
||||||
|
public function setTokenProvider(ITokenProvider $provider)
|
||||||
{
|
{
|
||||||
if ($this->token !== null) {
|
$this->tokenProvider = $provider;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->csrfToken->hasToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getToken()
|
|
||||||
{
|
|
||||||
return $this->token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -227,26 +227,7 @@ class Request
|
|||||||
*/
|
*/
|
||||||
public function setRewriteRoute(ILoadableRoute $route)
|
public function setRewriteRoute(ILoadableRoute $route)
|
||||||
{
|
{
|
||||||
$this->rewriteRoute = $route;
|
$this->rewriteRoute = SimpleRouter::addDefaultNamespace($route);
|
||||||
|
|
||||||
$callback = $route->getCallback();
|
|
||||||
|
|
||||||
/* Only add default namespace on relative callbacks */
|
|
||||||
if ($callback === null || $callback[0] !== '\\') {
|
|
||||||
|
|
||||||
$namespace = SimpleRouter::getDefaultNamespace();
|
|
||||||
|
|
||||||
if ($namespace !== null) {
|
|
||||||
|
|
||||||
if ($this->rewriteRoute->getNamespace() !== null) {
|
|
||||||
$namespace .= '\\' . $this->rewriteRoute->getNamespace();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->rewriteRoute->setDefaultNamespace($namespace);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Pecee;
|
namespace Pecee\Http\Security;
|
||||||
|
|
||||||
class CsrfToken
|
class CookieTokenProvider implements ITokenProvider
|
||||||
{
|
{
|
||||||
const CSRF_KEY = 'CSRF-TOKEN';
|
const CSRF_KEY = 'CSRF-TOKEN';
|
||||||
|
|
||||||
protected $token;
|
protected $token;
|
||||||
|
protected $cookieTimeoutMinutes = 120;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->token = $this->getToken();
|
||||||
|
|
||||||
|
if ($this->token === null) {
|
||||||
|
$this->token = $this->generateToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate random identifier for CSRF token
|
* Generate random identifier for CSRF token
|
||||||
@@ -14,7 +24,7 @@ class CsrfToken
|
|||||||
* @throws \RuntimeException
|
* @throws \RuntimeException
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function generateToken()
|
public function generateToken()
|
||||||
{
|
{
|
||||||
if (function_exists('random_bytes') === true) {
|
if (function_exists('random_bytes') === true) {
|
||||||
return bin2hex(random_bytes(32));
|
return bin2hex(random_bytes(32));
|
||||||
@@ -54,7 +64,7 @@ class CsrfToken
|
|||||||
public function setToken($token)
|
public function setToken($token)
|
||||||
{
|
{
|
||||||
$this->token = $token;
|
$this->token = $token;
|
||||||
setcookie(static::CSRF_KEY, $token, time() + 60 * 120, '/');
|
setcookie(static::CSRF_KEY, $token, time() + 60 * $this->cookieTimeoutMinutes, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,4 +98,22 @@ class CsrfToken
|
|||||||
return isset($_COOKIE[static::CSRF_KEY]);
|
return isset($_COOKIE[static::CSRF_KEY]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get timeout for cookie in minutes
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getCookieTimeoutMinutes()
|
||||||
|
{
|
||||||
|
return $this->cookieTimeoutMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set cookie timeout in minutes
|
||||||
|
* @param $minutes
|
||||||
|
*/
|
||||||
|
public function setCookieTimeoutMinutes($minutes)
|
||||||
|
{
|
||||||
|
$this->cookieTimeoutMinutes = $minutes;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pecee\Http\Security;
|
||||||
|
|
||||||
|
interface ITokenProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh existing token
|
||||||
|
*/
|
||||||
|
public function refresh();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate valid CSRF token
|
||||||
|
*
|
||||||
|
* @param string $token
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function validate($token);
|
||||||
|
|
||||||
|
}
|
||||||
+10
-18
@@ -6,20 +6,20 @@ class Uri
|
|||||||
{
|
{
|
||||||
private $originalUrl;
|
private $originalUrl;
|
||||||
private $data = [
|
private $data = [
|
||||||
'scheme',
|
'scheme' => '',
|
||||||
'host',
|
'host' => '',
|
||||||
'port',
|
'port' => '',
|
||||||
'user',
|
'user' => '',
|
||||||
'pass',
|
'pass' => '',
|
||||||
'path',
|
'path' => '',
|
||||||
'query',
|
'query' => '',
|
||||||
'fragment',
|
'fragment' => '',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct($url)
|
public function __construct($url)
|
||||||
{
|
{
|
||||||
$this->originalUrl = $url;
|
$this->originalUrl = $url;
|
||||||
$this->data = array_merge($this->data, $this->parseUrl(urldecode($url)));
|
$this->data = $this->parseUrl($url) + $this->data;
|
||||||
|
|
||||||
if (isset($this->data['path']) === true && $this->data['path'] !== '/') {
|
if (isset($this->data['path']) === true && $this->data['path'] !== '/') {
|
||||||
$this->data['path'] = rtrim($this->data['path'], '/') . '/';
|
$this->data['path'] = rtrim($this->data['path'], '/') . '/';
|
||||||
@@ -134,15 +134,7 @@ class Uri
|
|||||||
*/
|
*/
|
||||||
public function parseUrl($url, $component = -1)
|
public function parseUrl($url, $component = -1)
|
||||||
{
|
{
|
||||||
$encodedUrl = preg_replace_callback(
|
$parts = parse_url(urlencode($url), $component);
|
||||||
'%[^:/@?&=#]+%u',
|
|
||||||
function ($matches) {
|
|
||||||
return urlencode($matches[0]);
|
|
||||||
},
|
|
||||||
$url
|
|
||||||
);
|
|
||||||
|
|
||||||
$parts = parse_url($encodedUrl, $component);
|
|
||||||
|
|
||||||
if ($parts === false) {
|
if ($parts === false) {
|
||||||
throw new \InvalidArgumentException('Malformed URL: ' . $url);
|
throw new \InvalidArgumentException('Malformed URL: ' . $url);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
|||||||
{
|
{
|
||||||
$max = count($this->getMiddlewares());
|
$max = count($this->getMiddlewares());
|
||||||
|
|
||||||
if ($max > 0) {
|
if ($max !== 0) {
|
||||||
|
|
||||||
for ($i = 0; $i < $max; $i++) {
|
for ($i = 0; $i < $max; $i++) {
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (preg_match($this->regex, $request->getHost() . $url) > 0);
|
return (preg_match($this->regex, $request->getHost() . $url) !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,7 +74,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
|||||||
|
|
||||||
$regex = sprintf(static::PARAMETERS_REGEX_FORMAT, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
|
$regex = sprintf(static::PARAMETERS_REGEX_FORMAT, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
|
||||||
|
|
||||||
if (preg_match_all('/' . $regex . '/u', $this->url, $matches)) {
|
if (preg_match_all('/' . $regex . '/u', $this->url, $matches) === 1) {
|
||||||
$this->parameters = array_fill_keys($matches[1], null);
|
$this->parameters = array_fill_keys($matches[1], null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
|||||||
|
|
||||||
$group = $this->getGroup();
|
$group = $this->getGroup();
|
||||||
|
|
||||||
if ($group !== null && count($group->getDomains()) > 0) {
|
if ($group !== null && count($group->getDomains()) !== 0) {
|
||||||
$url = '//' . $group->getDomains()[0] . $url;
|
$url = '//' . $group->getDomains()[0] . $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ abstract class Route implements IRoute
|
|||||||
// Ensures that hostnames/domains will work with parameters
|
// Ensures that hostnames/domains will work with parameters
|
||||||
$url = '/' . ltrim($url, '/');
|
$url = '/' . ltrim($url, '/');
|
||||||
|
|
||||||
if (preg_match_all('/' . $regex . '/u', $route, $parameters)) {
|
if (preg_match_all('/' . $regex . '/u', $route, $parameters) !== 0) {
|
||||||
|
|
||||||
$urlParts = preg_split('/((\-?\/?)\{[^}]+\})/', rtrim($route, '/'));
|
$urlParts = preg_split('/((\-?\/?)\{[^}]+\})/', rtrim($route, '/'));
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ abstract class Route implements IRoute
|
|||||||
$urlRegex = preg_quote($route, '/');
|
$urlRegex = preg_quote($route, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preg_match(sprintf($this->urlRegex, $urlRegex), $url, $matches) > 0) {
|
if (preg_match(sprintf($this->urlRegex, $urlRegex), $url, $matches) === 1) {
|
||||||
|
|
||||||
$values = [];
|
$values = [];
|
||||||
|
|
||||||
@@ -361,15 +361,15 @@ abstract class Route implements IRoute
|
|||||||
$values['namespace'] = $this->namespace;
|
$values['namespace'] = $this->namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($this->requestMethods) > 0) {
|
if (count($this->requestMethods) !== 0) {
|
||||||
$values['method'] = $this->requestMethods;
|
$values['method'] = $this->requestMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($this->where) > 0) {
|
if (count($this->where) !== 0) {
|
||||||
$values['where'] = $this->where;
|
$values['where'] = $this->where;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($this->middlewares) > 0) {
|
if (count($this->middlewares) !== 0) {
|
||||||
$values['middleware'] = $this->middlewares;
|
$values['middleware'] = $this->middlewares;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,28 +389,28 @@ abstract class Route implements IRoute
|
|||||||
*/
|
*/
|
||||||
public function setSettings(array $values, $merge = false)
|
public function setSettings(array $values, $merge = false)
|
||||||
{
|
{
|
||||||
if ($this->namespace === null && isset($values['namespace'])) {
|
if ($this->namespace === null && isset($values['namespace']) === true) {
|
||||||
$this->setNamespace($values['namespace']);
|
$this->setNamespace($values['namespace']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($values['method'])) {
|
if (isset($values['method']) === true) {
|
||||||
$this->setRequestMethods(array_merge($this->requestMethods, (array)$values['method']));
|
$this->setRequestMethods(array_merge($this->requestMethods, (array)$values['method']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($values['where'])) {
|
if (isset($values['where']) === true) {
|
||||||
$this->setWhere(array_merge($this->where, (array)$values['where']));
|
$this->setWhere(array_merge($this->where, (array)$values['where']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($values['parameters'])) {
|
if (isset($values['parameters']) === true) {
|
||||||
$this->setParameters(array_merge($this->parameters, (array)$values['parameters']));
|
$this->setParameters(array_merge($this->parameters, (array)$values['parameters']));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push middleware if multiple
|
// Push middleware if multiple
|
||||||
if (isset($values['middleware'])) {
|
if (isset($values['middleware']) === true) {
|
||||||
$this->setMiddlewares(array_merge((array)$values['middleware'], $this->middlewares));
|
$this->setMiddlewares(array_merge((array)$values['middleware'], $this->middlewares));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($values['defaultParameterRegex'])) {
|
if (isset($values['defaultParameterRegex']) === true) {
|
||||||
$this->setDefaultParameterRegex($values['defaultParameterRegex']);
|
$this->setDefaultParameterRegex($values['defaultParameterRegex']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +463,7 @@ abstract class Route implements IRoute
|
|||||||
/* Sort the parameters after the user-defined param order, if any */
|
/* Sort the parameters after the user-defined param order, if any */
|
||||||
$parameters = [];
|
$parameters = [];
|
||||||
|
|
||||||
if (count($this->originalParameters) > 0) {
|
if (count($this->originalParameters) !== 0) {
|
||||||
$parameters = $this->originalParameters;
|
$parameters = $this->originalParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +482,7 @@ abstract class Route implements IRoute
|
|||||||
* If this is the first time setting parameters we store them so we
|
* If this is the first time setting parameters we store them so we
|
||||||
* later can organize the array, in case somebody tried to sort the array.
|
* later can organize the array, in case somebody tried to sort the array.
|
||||||
*/
|
*/
|
||||||
if (count($parameters) > 0 && count($this->originalParameters) === 0) {
|
if (count($parameters) !== 0 && count($this->originalParameters) === 0) {
|
||||||
$this->originalParameters = $parameters;
|
$this->originalParameters = $parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
|||||||
|
|
||||||
$group = $this->getGroup();
|
$group = $this->getGroup();
|
||||||
|
|
||||||
if ($group !== null && count($group->getDomains()) > 0) {
|
if ($group !== null && count($group->getDomains()) !== 0) {
|
||||||
$url .= '//' . $group->getDomains()[0];
|
$url .= '//' . $group->getDomains()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
|||||||
$strippedUrl = trim(str_ireplace($this->url, '/', $url), '/');
|
$strippedUrl = trim(str_ireplace($this->url, '/', $url), '/');
|
||||||
$path = explode('/', $strippedUrl);
|
$path = explode('/', $strippedUrl);
|
||||||
|
|
||||||
if (count($path) > 0) {
|
if (count($path) !== 0) {
|
||||||
|
|
||||||
$method = (isset($path[0]) === false || trim($path[0]) === '') ? $this->defaultMethod : $path[0];
|
$method = (isset($path[0]) === false || trim($path[0]) === '') ? $this->defaultMethod : $path[0];
|
||||||
$this->method = $request->getMethod() . ucfirst($method);
|
$this->method = $request->getMethod() . ucfirst($method);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class RouteGroup extends Route implements IGroupRoute
|
|||||||
|
|
||||||
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
|
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
|
||||||
|
|
||||||
if ($parameters !== null && count($parameters) > 0) {
|
if ($parameters !== null && count($parameters) !== 0) {
|
||||||
|
|
||||||
$this->parameters = $parameters;
|
$this->parameters = $parameters;
|
||||||
|
|
||||||
@@ -146,19 +146,19 @@ class RouteGroup extends Route implements IGroupRoute
|
|||||||
public function setSettings(array $values, $merge = false)
|
public function setSettings(array $values, $merge = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isset($values['prefix'])) {
|
if (isset($values['prefix']) === true) {
|
||||||
$this->setPrefix($values['prefix'] . $this->prefix);
|
$this->setPrefix($values['prefix'] . $this->prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($merge === false && isset($values['exceptionHandler'])) {
|
if ($merge === false && isset($values['exceptionHandler']) === true) {
|
||||||
$this->setExceptionHandlers((array)$values['exceptionHandler']);
|
$this->setExceptionHandlers((array)$values['exceptionHandler']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($merge === false && isset($values['domain'])) {
|
if ($merge === false && isset($values['domain']) === true) {
|
||||||
$this->setDomains((array)$values['domain']);
|
$this->setDomains((array)$values['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($values['as'])) {
|
if (isset($values['as']) === true) {
|
||||||
if ($this->name !== null && $merge !== false) {
|
if ($this->name !== null && $merge !== false) {
|
||||||
$this->name = $values['as'] . '.' . $this->name;
|
$this->name = $values['as'] . '.' . $this->name;
|
||||||
} else {
|
} else {
|
||||||
@@ -188,7 +188,7 @@ class RouteGroup extends Route implements IGroupRoute
|
|||||||
$values['as'] = $this->name;
|
$values['as'] = $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($this->parameters) > 0) {
|
if (count($this->parameters) !== 0) {
|
||||||
$values['parameters'] = $this->parameters;
|
$values['parameters'] = $this->parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ class Router
|
|||||||
if ($route->matchRoute($url, $this->request) === true) {
|
if ($route->matchRoute($url, $this->request) === true) {
|
||||||
|
|
||||||
/* Add exception handlers */
|
/* Add exception handlers */
|
||||||
if (count($route->getExceptionHandlers()) > 0) {
|
if (count($route->getExceptionHandlers()) !== 0) {
|
||||||
/** @noinspection AdditionOperationOnArraysInspection */
|
/** @noinspection AdditionOperationOnArraysInspection */
|
||||||
$exceptionHandlers += $route->getExceptionHandlers();
|
$exceptionHandlers += $route->getExceptionHandlers();
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,7 @@ class Router
|
|||||||
$this->processedRoutes[] = $route;
|
$this->processedRoutes[] = $route;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($this->routeStack) > 0) {
|
if (count($this->routeStack) !== 0) {
|
||||||
|
|
||||||
/* Pop and grab the routes added when executing group callback earlier */
|
/* Pop and grab the routes added when executing group callback earlier */
|
||||||
$stack = $this->routeStack;
|
$stack = $this->routeStack;
|
||||||
@@ -203,7 +203,7 @@ class Router
|
|||||||
public function loadRoutes()
|
public function loadRoutes()
|
||||||
{
|
{
|
||||||
/* Initialize boot-managers */
|
/* Initialize boot-managers */
|
||||||
if (count($this->bootManagers) > 0) {
|
if (count($this->bootManagers) !== 0) {
|
||||||
|
|
||||||
$max = count($this->bootManagers) - 1;
|
$max = count($this->bootManagers) - 1;
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ class Router
|
|||||||
if ($route->matchRoute($url, $this->request) === true) {
|
if ($route->matchRoute($url, $this->request) === true) {
|
||||||
|
|
||||||
/* Check if request method matches */
|
/* Check if request method matches */
|
||||||
if (count($route->getRequestMethods()) > 0 && in_array($this->request->getMethod(), $route->getRequestMethods(), false) === false) {
|
if (count($route->getRequestMethods()) !== 0 && in_array($this->request->getMethod(), $route->getRequestMethods(), false) === false) {
|
||||||
$routeNotAllowed = true;
|
$routeNotAllowed = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -363,7 +363,7 @@ class Router
|
|||||||
|
|
||||||
public function arrayToParams(array $getParams = [], $includeEmpty = true)
|
public function arrayToParams(array $getParams = [], $includeEmpty = true)
|
||||||
{
|
{
|
||||||
if (count($getParams) > 0) {
|
if (count($getParams) !== 0) {
|
||||||
|
|
||||||
if ($includeEmpty === false) {
|
if ($includeEmpty === false) {
|
||||||
$getParams = array_filter($getParams, function ($item) {
|
$getParams = array_filter($getParams, function ($item) {
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ class SimpleRouter
|
|||||||
* @param IRoute $route
|
* @param IRoute $route
|
||||||
* @return IRoute
|
* @return IRoute
|
||||||
*/
|
*/
|
||||||
protected static function addDefaultNamespace(IRoute $route)
|
public static function addDefaultNamespace(IRoute $route)
|
||||||
{
|
{
|
||||||
if (static::$defaultNamespace !== null) {
|
if (static::$defaultNamespace !== null) {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user