Optimisations

- Fixed issue with `InputFile` not setting file-name properly.
- Fixed issue with `InputFile` not setting the correct index when
posting certain arrays.
- Made Csrf-token cookie provider more versitile by creating new
`CookieTokenProvider` and `ITokenProvider` classes.
- Strict-checks optimisations.
- Updated documentation to reflect new changes.
This commit is contained in:
Simon Sessingø
2017-11-26 17:32:33 +01:00
parent b9aa348b38
commit 35dc26d741
13 changed files with 211 additions and 88 deletions
+12 -9
View File
@@ -35,7 +35,7 @@ class Input
public function parseInputs()
{
/* Parse get requests */
if (count($_GET) > 0) {
if (count($_GET) !== 0) {
$this->get = $this->handleGetPost($_GET);
}
@@ -46,12 +46,12 @@ class Input
parse_str(file_get_contents('php://input'), $postVars);
}
if (count($postVars) > 0) {
if (count($postVars) !== 0) {
$this->post = $this->handleGetPost($postVars);
}
/* Parse get requests */
if (count($_FILES) > 0) {
if (count($_FILES) !== 0) {
$this->file = $this->parseFiles();
}
}
@@ -69,7 +69,7 @@ class Input
continue;
}
$keys = [];
$keys = [$key];
$files = $this->rearrangeFiles($value['name'], $keys, $value);
@@ -87,6 +87,9 @@ class Input
protected function rearrangeFiles(array $values, &$index, $original)
{
$originalIndex = $index[0];
array_shift($index);
$output = [];
$getItem = function ($key, $property = 'name') use ($original, $index) {
@@ -107,7 +110,7 @@ class Input
if (is_array($getItem($key)) === false) {
$file = InputFile::createFromArray([
'index' => $key,
'index' => (empty($key) === true && empty($originalIndex) === false) ? $originalIndex : $key,
'filename' => $getItem($key),
'error' => $getItem($key, 'error'),
'tmp_name' => $getItem($key, 'tmp_name'),
@@ -128,7 +131,7 @@ class Input
$files = $this->rearrangeFiles($value, $index, $original);
if (isset($output[$key])) {
if (isset($output[$key]) === true) {
$output[$key][] = $files;
} else {
$output[$key] = $files;
@@ -217,15 +220,15 @@ class Input
$element = null;
if ($methods === null || in_array('get', $methods)) {
if ($methods === null || in_array('get', $methods, false) === true) {
$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);
}
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);
}
+6 -4
View File
@@ -16,7 +16,7 @@ class InputFile implements IInputItem
$this->index = $index;
// 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)
{
if (!isset($values['index'])) {
if (array_key_exists('index', $values) === false) {
throw new \InvalidArgumentException('Index key is required');
}
@@ -39,6 +39,7 @@ class InputFile implements IInputItem
'type' => null,
'size' => null,
'name' => null,
'filename' => null,
'error' => null,
], $values);
@@ -47,7 +48,7 @@ class InputFile implements IInputItem
->setError($values['error'])
->setType($values['type'])
->setTmpName($values['tmp_name'])
->setFilename($values['name']);
->setFilename($values['filename']);
}
@@ -267,8 +268,9 @@ class InputFile implements IInputItem
'tmp_name' => $this->tmpName,
'type' => $this->type,
'size' => $this->size,
'name' => $this->filename,
'name' => $this->name,
'error' => $this->error,
'filename' => $this->filename,
];
}
+1 -1
View File
@@ -13,7 +13,7 @@ class InputItem implements IInputItem
$this->value = $value;
// Make the name human friendly, by replace _ with space
$this->name = ucfirst(str_replace('_', ' ', $this->index));
$this->name = ucfirst(str_replace('_', ' ', strtolower($this->index)));
}
/**
+16 -27
View File
@@ -2,9 +2,10 @@
namespace Pecee\Http\Middleware;
use Pecee\CsrfToken;
use Pecee\Http\Middleware\Exceptions\TokenMismatchException;
use Pecee\Http\Request;
use Pecee\Http\Security\CookieTokenProvider;
use Pecee\Http\Security\ITokenProvider;
class BaseCsrfVerifier implements IMiddleware
{
@@ -12,15 +13,11 @@ class BaseCsrfVerifier implements IMiddleware
const HEADER_KEY = 'X-CSRF-TOKEN';
protected $except;
protected $csrfToken;
protected $token;
protected $tokenProvider;
public function __construct()
{
$this->csrfToken = new CsrfToken();
// Generate or get the CSRF-Token from Cookie.
$this->token = $this->csrfToken->getToken($this->generateToken());
$this->tokenProvider = new CookieTokenProvider();
}
/**
@@ -30,7 +27,7 @@ class BaseCsrfVerifier implements IMiddleware
*/
protected function skip(Request $request)
{
if ($this->except === null || is_array($this->except) === false) {
if ($this->except === null || count($this->except) === 0) {
return false;
}
@@ -67,37 +64,29 @@ class BaseCsrfVerifier implements IMiddleware
$token = $request->getHeader(static::HEADER_KEY);
}
if ($this->csrfToken->validate($token) === false) {
throw new TokenMismatchException('Invalid csrf-token.');
if ($this->tokenProvider->validate($token) === false) {
throw new TokenMismatchException('Invalid CSRF-token.');
}
}
// Refresh existing token
$this->csrfToken->refresh();
$this->tokenProvider->refresh();
}
public function generateToken()
public function getTokenProvider()
{
$token = CsrfToken::generateToken();
$this->csrfToken->setToken($token);
return $token;
return $this->tokenProvider;
}
public function hasToken()
/**
* Set token provider
* @param ITokenProvider $provider
*/
public function setTokenProvider(ITokenProvider $provider)
{
if ($this->token !== null) {
return true;
}
return $this->csrfToken->hasToken();
}
public function getToken()
{
return $this->token;
$this->tokenProvider = $provider;
}
}
@@ -0,0 +1,119 @@
<?php
namespace Pecee\Http\Security;
class CookieTokenProvider implements ITokenProvider
{
const CSRF_KEY = 'CSRF-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
*
* @throws \RuntimeException
* @return string
*/
public function generateToken()
{
if (function_exists('random_bytes') === true) {
return bin2hex(random_bytes(32));
}
$isSourceStrong = false;
$random = openssl_random_pseudo_bytes(32, $isSourceStrong);
if ($isSourceStrong === false || $random === false) {
throw new \RuntimeException('IV generation failed');
}
return $random;
}
/**
* Validate valid CSRF token
*
* @param string $token
* @return bool
*/
public function validate($token)
{
if ($token !== null && $this->getToken() !== null) {
return hash_equals($token, $this->getToken());
}
return false;
}
/**
* Set csrf token cookie
* Overwrite this method to save the token to another storage like session etc.
*
* @param string $token
*/
public function setToken($token)
{
$this->token = $token;
setcookie(static::CSRF_KEY, $token, time() + 60 * $this->cookieTimeoutMinutes, '/');
}
/**
* Get csrf token
* @param string|null $defaultValue
* @return string|null
*/
public function getToken($defaultValue = null)
{
$this->token = ($this->hasToken() === true) ? $_COOKIE[static::CSRF_KEY] : null;
return ($this->token !== null) ? $this->token : $defaultValue;
}
/**
* Refresh existing token
*/
public function refresh()
{
if ($this->token !== null) {
$this->setToken($this->token);
}
}
/**
* Returns whether the csrf token has been defined
* @return bool
*/
public function hasToken()
{
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);
}