From ba2163cbb8ca0aa1bcaeaf77a3f2959fe92a106f Mon Sep 17 00:00:00 2001 From: Martin Beranek Date: Fri, 3 Oct 2025 16:00:18 +0200 Subject: [PATCH 1/5] Validate all input types --- CHANGELOG.md | 2 ++ src/Params/GetInputParam.php | 6 +++- src/Params/InputParam.php | 28 ++++++++++------- src/Params/PostInputParam.php | 6 +++- src/Validation/InputType.php | 13 ++++++++ src/Validation/InputValidator.php | 50 +++++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 src/Validation/InputType.php create mode 100644 src/Validation/InputValidator.php diff --git a/CHANGELOG.md b/CHANGELOG.md index acede3f..a34d540 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [Unreleased][unreleased] +### Added +- Input type validation for InputParam ## 3.0.0 diff --git a/src/Params/GetInputParam.php b/src/Params/GetInputParam.php index b6b7a9c..750a1c3 100644 --- a/src/Params/GetInputParam.php +++ b/src/Params/GetInputParam.php @@ -4,6 +4,8 @@ namespace Tomaj\NetteApi\Params; +use Tomaj\NetteApi\Validation\InputValidator; + class GetInputParam extends InputParam { protected $type = self::TYPE_GET; @@ -14,6 +16,8 @@ public function getValue() return $_GET[$this->key]; } $value = $this->isMulti() ? filter_input(INPUT_GET, $this->key, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) : filter_input(INPUT_GET, $this->key); - return $value !== null && $value !== false ? $value : $this->default; + $value = $value !== null && $value !== false ? $value : $this->default; + $inputValidator = new InputValidator(); + return $inputValidator->transformType($value, $this->valueType); } } diff --git a/src/Params/InputParam.php b/src/Params/InputParam.php index 468520f..d398aa3 100644 --- a/src/Params/InputParam.php +++ b/src/Params/InputParam.php @@ -7,21 +7,23 @@ use Nette\Application\UI\Form; use Nette\Forms\Controls\BaseControl; use Nette\Utils\Html; +use Tomaj\NetteApi\Validation\InputType; +use Tomaj\NetteApi\Validation\InputValidator; use Tomaj\NetteApi\ValidationResult\ValidationResult; use Tomaj\NetteApi\ValidationResult\ValidationResultInterface; abstract class InputParam implements ParamInterface { - const TYPE_POST = 'POST'; - const TYPE_GET = 'GET'; - const TYPE_PUT = 'PUT'; - const TYPE_FILE = 'FILE'; - const TYPE_COOKIE = 'COOKIE'; - const TYPE_POST_RAW = 'POST_RAW'; - const TYPE_POST_JSON = 'POST_JSON'; + public const TYPE_POST = 'POST'; + public const TYPE_GET = 'GET'; + public const TYPE_PUT = 'PUT'; + public const TYPE_FILE = 'FILE'; + public const TYPE_COOKIE = 'COOKIE'; + public const TYPE_POST_RAW = 'POST_RAW'; + public const TYPE_POST_JSON = 'POST_JSON'; - const OPTIONAL = false; - const REQUIRED = true; + public const OPTIONAL = false; + public const REQUIRED = true; /** @var string */ protected $type; @@ -47,9 +49,12 @@ abstract class InputParam implements ParamInterface /** @var array */ protected $examples = []; - public function __construct(string $key) + protected ?InputType $valueType; + + public function __construct(string $key, ?InputType $valueType = null) { $this->key = $key; + $this->valueType = $valueType; } public function setRequired(): self @@ -238,6 +243,7 @@ public function validate(): ValidationResultInterface } } - return new ValidationResult(ValidationResult::STATUS_OK); + $inputValidator = new InputValidator(); + return $inputValidator->validate($value, $this->valueType); } } diff --git a/src/Params/PostInputParam.php b/src/Params/PostInputParam.php index e30e5fd..0e6a23d 100644 --- a/src/Params/PostInputParam.php +++ b/src/Params/PostInputParam.php @@ -4,6 +4,8 @@ namespace Tomaj\NetteApi\Params; +use Tomaj\NetteApi\Validation\InputValidator; + class PostInputParam extends InputParam { protected $type = self::TYPE_POST; @@ -14,6 +16,8 @@ public function getValue() return $_POST[$this->key]; } $value = $this->isMulti() ? filter_input(INPUT_POST, $this->key, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) : filter_input(INPUT_POST, $this->key); - return $value !== null && $value !== false ? $value : $this->default; + $value = $value !== null && $value !== false ? $value : $this->default; + $inputValidator = new InputValidator(); + return $inputValidator->transformType($value, $this->valueType); } } diff --git a/src/Validation/InputType.php b/src/Validation/InputType.php new file mode 100644 index 0000000..afbe735 --- /dev/null +++ b/src/Validation/InputType.php @@ -0,0 +1,13 @@ + is_bool($value) ? $isError = false : $isError = true, + InputType::Integer => is_int($value) ? $isError = false : $isError = true, + InputType::Double => is_float($value) || is_int($value) ? $isError = false : $isError = true, + InputType::Float => is_float($value) || is_int($value) ? $isError = false : $isError = true, + InputType::String => is_string($value) ? $isError = false : $isError = true, + InputType::Array => is_array($value) ? $isError = false : $isError = true, + default => false, + }; + + if ($isError) { + return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type. Expected ' . $expectedType->value . '.']); + } + return new ValidationResult(ValidationResult::STATUS_OK); + } + + public function transformType($value, ?InputType $expectedType = null) + { + if ($value === null || $expectedType === null) { + return $value; + } + + match ($expectedType) { + InputType::Boolean => ($value === '1' || $value === 1 || $value === true || strtolower((string) $value) === 'true') ? true : false, + InputType::Integer => is_numeric($value) ? settype($value, 'integer') : null, + InputType::Double => is_numeric($value) ? settype($value, 'double') : null, + InputType::Float => is_numeric($value) ? settype($value, 'float') : null, + InputType::String => is_string($value) ? settype($value, 'string') : null, + default => null, + }; + return $value; + } +} From 3e06f60d91d0ba59cabb120ff00d91d078370215 Mon Sep 17 00:00:00 2001 From: Martin Beranek Date: Fri, 3 Oct 2025 16:07:57 +0200 Subject: [PATCH 2/5] enum to class --- src/Params/InputParam.php | 5 ++--- src/Validation/InputType.php | 14 +++++++------- src/Validation/InputValidator.php | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Params/InputParam.php b/src/Params/InputParam.php index d398aa3..6882cdb 100644 --- a/src/Params/InputParam.php +++ b/src/Params/InputParam.php @@ -7,7 +7,6 @@ use Nette\Application\UI\Form; use Nette\Forms\Controls\BaseControl; use Nette\Utils\Html; -use Tomaj\NetteApi\Validation\InputType; use Tomaj\NetteApi\Validation\InputValidator; use Tomaj\NetteApi\ValidationResult\ValidationResult; use Tomaj\NetteApi\ValidationResult\ValidationResultInterface; @@ -49,9 +48,9 @@ abstract class InputParam implements ParamInterface /** @var array */ protected $examples = []; - protected ?InputType $valueType; + protected ?string $valueType; - public function __construct(string $key, ?InputType $valueType = null) + public function __construct(string $key, ?string $valueType = null) { $this->key = $key; $this->valueType = $valueType; diff --git a/src/Validation/InputType.php b/src/Validation/InputType.php index afbe735..3f5c740 100644 --- a/src/Validation/InputType.php +++ b/src/Validation/InputType.php @@ -2,12 +2,12 @@ namespace Tomaj\NetteApi\Validation; -enum InputType: string +class InputType { - case Boolean = 'boolean'; - case Integer = 'integer'; - case Double = 'double'; - case Float = 'float'; - case String = 'string'; - case Array = 'array'; + public const Boolean = 'boolean'; + public const Integer = 'integer'; + public const Double = 'double'; + public const Float = 'float'; + public const String = 'string'; + public const Array = 'array'; } diff --git a/src/Validation/InputValidator.php b/src/Validation/InputValidator.php index 190c792..6e587f0 100644 --- a/src/Validation/InputValidator.php +++ b/src/Validation/InputValidator.php @@ -9,7 +9,7 @@ class InputValidator { - public function validate($value, ?InputType $expectedType = null): ValidationResultInterface + public function validate($value, ?string $expectedType = null): ValidationResultInterface { if ($value === null || $expectedType === null) { return new ValidationResult(ValidationResult::STATUS_OK); @@ -31,7 +31,7 @@ public function validate($value, ?InputType $expectedType = null): ValidationRes return new ValidationResult(ValidationResult::STATUS_OK); } - public function transformType($value, ?InputType $expectedType = null) + public function transformType($value, ?string $expectedType = null) { if ($value === null || $expectedType === null) { return $value; From 93b8356c2060f93cd3e8da1d0ef78a9273b3657d Mon Sep 17 00:00:00 2001 From: Martin Beranek Date: Fri, 3 Oct 2025 16:10:56 +0200 Subject: [PATCH 3/5] match to switch --- src/Validation/InputType.php | 12 ++--- src/Validation/InputValidator.php | 89 +++++++++++++++++++++++-------- 2 files changed, 72 insertions(+), 29 deletions(-) diff --git a/src/Validation/InputType.php b/src/Validation/InputType.php index 3f5c740..08f90d2 100644 --- a/src/Validation/InputType.php +++ b/src/Validation/InputType.php @@ -4,10 +4,10 @@ class InputType { - public const Boolean = 'boolean'; - public const Integer = 'integer'; - public const Double = 'double'; - public const Float = 'float'; - public const String = 'string'; - public const Array = 'array'; + public const BOOLEAN = 'boolean'; + public const INTEGER = 'integer'; + public const DOUBLE = 'double'; + public const FLOAT = 'float'; + public const STRING = 'string'; + public const ARRAY = 'array'; } diff --git a/src/Validation/InputValidator.php b/src/Validation/InputValidator.php index 6e587f0..3f2581d 100644 --- a/src/Validation/InputValidator.php +++ b/src/Validation/InputValidator.php @@ -9,42 +9,85 @@ class InputValidator { - public function validate($value, ?string $expectedType = null): ValidationResultInterface + public function validate($value, ?InputType $expectedType = null): ValidationResultInterface { if ($value === null || $expectedType === null) { return new ValidationResult(ValidationResult::STATUS_OK); } - $isError = false; - match ($expectedType) { - InputType::Boolean => is_bool($value) ? $isError = false : $isError = true, - InputType::Integer => is_int($value) ? $isError = false : $isError = true, - InputType::Double => is_float($value) || is_int($value) ? $isError = false : $isError = true, - InputType::Float => is_float($value) || is_int($value) ? $isError = false : $isError = true, - InputType::String => is_string($value) ? $isError = false : $isError = true, - InputType::Array => is_array($value) ? $isError = false : $isError = true, - default => false, - }; - if ($isError) { - return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type. Expected ' . $expectedType->value . '.']); + switch ($expectedType) { + case InputType::BOOLEAN: + if (!is_bool($value)) { + return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type. Expected boolean.']); + } + break; + case InputType::INTEGER: + if (!is_int($value)) { + return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type. Expected integer.']); + } + break; + case InputType::DOUBLE: + if (!is_float($value) && !is_int($value)) { + return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type. Expected double.']); + } + break; + case InputType::FLOAT: + if (!is_float($value) && !is_int($value)) { + return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type. Expected float.']); + } + break; + case InputType::STRING: + if (!is_string($value)) { + return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type. Expected string.']); + } + break; + case InputType::ARRAY: + if (!is_array($value)) { + return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type. Expected array.']); + } + break; + default: + return new ValidationResult(ValidationResult::STATUS_ERROR, ['Value ' . $value . ' has invalid type.']); } return new ValidationResult(ValidationResult::STATUS_OK); } - public function transformType($value, ?string $expectedType = null) + public function transformType($value, ?InputType $expectedType = null) { if ($value === null || $expectedType === null) { return $value; } - - match ($expectedType) { - InputType::Boolean => ($value === '1' || $value === 1 || $value === true || strtolower((string) $value) === 'true') ? true : false, - InputType::Integer => is_numeric($value) ? settype($value, 'integer') : null, - InputType::Double => is_numeric($value) ? settype($value, 'double') : null, - InputType::Float => is_numeric($value) ? settype($value, 'float') : null, - InputType::String => is_string($value) ? settype($value, 'string') : null, - default => null, - }; + switch ($expectedType) { + case InputType::BOOLEAN: + if ($value === '1' || $value === 1 || $value === true || strtolower((string) $value) === 'true') { + return true; + } else { + return false; + } + // no break + case InputType::INTEGER: + if (is_numeric($value)) { + settype($value, 'integer'); + } + break; + case InputType::DOUBLE: + if (is_numeric($value)) { + settype($value, 'double'); + } + break; + case InputType::FLOAT: + if (is_numeric($value)) { + settype($value, 'float'); + } + break; + case InputType::STRING: + if (is_string($value)) { + settype($value, 'string'); + } + break; + default: + return $value; + } return $value; } } From a5a8952d1451e0d9f06ca43b670035c85ebdc86c Mon Sep 17 00:00:00 2001 From: Martin Beranek Date: Fri, 3 Oct 2025 16:12:41 +0200 Subject: [PATCH 4/5] syntax 7.1 --- src/Params/InputParam.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Params/InputParam.php b/src/Params/InputParam.php index 6882cdb..02c15b3 100644 --- a/src/Params/InputParam.php +++ b/src/Params/InputParam.php @@ -48,9 +48,14 @@ abstract class InputParam implements ParamInterface /** @var array */ protected $examples = []; - protected ?string $valueType; + /** @var string|null */ + protected $valueType; - public function __construct(string $key, ?string $valueType = null) + /** + * InputParam constructor. + * @param string|null $valueType + */ + public function __construct(string $key, $valueType = null) { $this->key = $key; $this->valueType = $valueType; From 8560cc9bfc073b5cc51c561cb5a47c28ea2a234a Mon Sep 17 00:00:00 2001 From: Martin Beranek Date: Fri, 3 Oct 2025 16:17:54 +0200 Subject: [PATCH 5/5] fix input validator --- src/Validation/InputValidator.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Validation/InputValidator.php b/src/Validation/InputValidator.php index 3f2581d..ffd1baf 100644 --- a/src/Validation/InputValidator.php +++ b/src/Validation/InputValidator.php @@ -9,7 +9,12 @@ class InputValidator { - public function validate($value, ?InputType $expectedType = null): ValidationResultInterface + /** + * Summary of validate + * @param mixed $value + * @param ?string $expectedType + */ + public function validate($value, $expectedType = null): ValidationResultInterface { if ($value === null || $expectedType === null) { return new ValidationResult(ValidationResult::STATUS_OK); @@ -52,7 +57,12 @@ public function validate($value, ?InputType $expectedType = null): ValidationRes return new ValidationResult(ValidationResult::STATUS_OK); } - public function transformType($value, ?InputType $expectedType = null) + /** + * Summary of transformType + * @param mixed $value + * @param ?string $expectedType + */ + public function transformType($value, $expectedType = null) { if ($value === null || $expectedType === null) { return $value;