save
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Helpers\CanValidateDateTime;
|
||||
|
||||
use function date;
|
||||
use function date_parse_from_format;
|
||||
use function is_scalar;
|
||||
use function strtotime;
|
||||
use function vsprintf;
|
||||
|
||||
/**
|
||||
* Abstract class to validate ages.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
abstract class AbstractAge extends AbstractRule
|
||||
{
|
||||
use CanValidateDateTime;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $age;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $format;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $baseDate;
|
||||
|
||||
/**
|
||||
* Should compare the current base date with the given one.
|
||||
*
|
||||
* The dates are represented as integers in the format "Ymd".
|
||||
*/
|
||||
abstract protected function compare(int $baseDate, int $givenDate): bool;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*/
|
||||
public function __construct(int $age, ?string $format = null)
|
||||
{
|
||||
$this->age = $age;
|
||||
$this->format = $format;
|
||||
$this->baseDate = (int) date('Ymd') - $this->age * 10000;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->format === null) {
|
||||
return $this->isValidWithoutFormat((string) $input);
|
||||
}
|
||||
|
||||
return $this->isValidWithFormat($this->format, (string) $input);
|
||||
}
|
||||
|
||||
private function isValidWithoutFormat(string $dateTime): bool
|
||||
{
|
||||
$timestamp = strtotime($dateTime);
|
||||
if ($timestamp === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->compare($this->baseDate, (int) date('Ymd', $timestamp));
|
||||
}
|
||||
|
||||
private function isValidWithFormat(string $format, string $dateTime): bool
|
||||
{
|
||||
if (!$this->isDateTime($format, $dateTime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->compare(
|
||||
$this->baseDate,
|
||||
(int) vsprintf('%d%02d%02d', date_parse_from_format($format, $dateTime))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Helpers\CanCompareValues;
|
||||
|
||||
/**
|
||||
* Abstract class to help on creating rules that compare value.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
abstract class AbstractComparison extends AbstractRule
|
||||
{
|
||||
use CanCompareValues;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $compareTo;
|
||||
|
||||
/**
|
||||
* Compare both values and return whether the comparison is valid or not.
|
||||
*
|
||||
* @param mixed $left
|
||||
* @param mixed $right
|
||||
*/
|
||||
abstract protected function compare($left, $right): bool;
|
||||
|
||||
/**
|
||||
* Initializes the rule by setting the value to be compared to the input.
|
||||
*
|
||||
* @param mixed $maxValue
|
||||
*/
|
||||
public function __construct($maxValue)
|
||||
{
|
||||
$this->compareTo = $maxValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
$left = $this->toComparable($input);
|
||||
$right = $this->toComparable($this->compareTo);
|
||||
|
||||
if (!$this->isAbleToCompareValues($left, $right)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->compare($left, $right);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\NestedValidationException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
|
||||
/**
|
||||
* Abstract class for rules that are composed by other rules.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Wojciech Frącz <fraczwojciech@gmail.com>
|
||||
*/
|
||||
abstract class AbstractComposite extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var Validatable[]
|
||||
*/
|
||||
private $rules = [];
|
||||
|
||||
/**
|
||||
* Initializes the rule adding other rules to the stack.
|
||||
*/
|
||||
public function __construct(Validatable ...$rules)
|
||||
{
|
||||
$this->rules = $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setName(string $name): Validatable
|
||||
{
|
||||
$parentName = $this->getName();
|
||||
foreach ($this->rules as $rule) {
|
||||
$ruleName = $rule->getName();
|
||||
if ($ruleName && $parentName !== $ruleName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rule->setName($name);
|
||||
}
|
||||
|
||||
return parent::setName($name);
|
||||
}
|
||||
|
||||
public function setDefault(string $default, bool $defaultType=false): Validatable
|
||||
{
|
||||
$parentDefault = $this->getDefault();
|
||||
foreach ($this->rules as $rule) {
|
||||
$ruleDefault = $rule->getDefault();
|
||||
if ($ruleDefault && $parentDefault !== $ruleDefault) {
|
||||
continue;
|
||||
}
|
||||
$rule->setDefault($default, $defaultType);
|
||||
}
|
||||
return parent::setDefault($default, $defaultType);
|
||||
}
|
||||
/**
|
||||
* Append a rule into the stack of rules.
|
||||
*
|
||||
* @return AbstractComposite
|
||||
*/
|
||||
public function addRule(Validatable $rule): self
|
||||
{
|
||||
if ($this->shouldHaveNameOverwritten($rule) && $this->getName() !== null) {
|
||||
$rule->setName($this->getName());
|
||||
}
|
||||
|
||||
$this->rules[] = $rule;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the rules in the stack.
|
||||
*
|
||||
* @return Validatable[]
|
||||
*/
|
||||
public function getRules(): array
|
||||
{
|
||||
return $this->rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the exceptions throw when asserting all rules.
|
||||
*
|
||||
* @param mixed $input
|
||||
*
|
||||
* @return ValidationException[]
|
||||
*/
|
||||
protected function getAllThrownExceptions($input): array
|
||||
{
|
||||
return array_filter(
|
||||
array_map(
|
||||
function (Validatable $rule) use ($input): ?ValidationException {
|
||||
try {
|
||||
$rule->assert($input);
|
||||
} catch (ValidationException $exception) {
|
||||
$this->updateExceptionTemplate($exception);
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
$this->getRules()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function shouldHaveNameOverwritten(Validatable $rule): bool
|
||||
{
|
||||
return $this->hasName($this) && !$this->hasName($rule);
|
||||
}
|
||||
|
||||
private function hasName(Validatable $rule): bool
|
||||
{
|
||||
return $rule->getName() !== null;
|
||||
}
|
||||
|
||||
private function updateExceptionTemplate(ValidationException $exception): void
|
||||
{
|
||||
if ($this->template === null || $exception->hasCustomTemplate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$exception->updateTemplate($this->template);
|
||||
|
||||
if (!$exception instanceof NestedValidationException) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($exception->getChildren() as $childException) {
|
||||
$this->updateExceptionTemplate($childException);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
/**
|
||||
* Abstract class that creates an envelope around another rule.
|
||||
*
|
||||
* This class is usefull when you want to create rules that use other rules, but
|
||||
* having an custom message.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
abstract class AbstractEnvelope extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var Validatable
|
||||
*/
|
||||
private $validatable;
|
||||
|
||||
/**
|
||||
* @var mixed[]
|
||||
*/
|
||||
private $parameters;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param mixed[] $parameters
|
||||
*/
|
||||
public function __construct(Validatable $validatable, array $parameters = [])
|
||||
{
|
||||
$this->validatable = $validatable;
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return $this->validatable->validate($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function reportError($input, array $extraParameters = []): ValidationException
|
||||
{
|
||||
return parent::reportError($input, $extraParameters + $this->parameters);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function implode;
|
||||
use function is_scalar;
|
||||
use function str_replace;
|
||||
use function str_split;
|
||||
|
||||
/**
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
abstract class AbstractFilterRule extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $additionalChars;
|
||||
|
||||
abstract protected function validateFilteredInput(string $input): bool;
|
||||
|
||||
/**
|
||||
* Initializes the rule with a list of characters to be ignored by the validation.
|
||||
*/
|
||||
public function __construct(string ...$additionalChars)
|
||||
{
|
||||
$this->additionalChars = implode($additionalChars);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$stringInput = (string) $input;
|
||||
if ($stringInput === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$filteredInput = $this->filter($stringInput);
|
||||
|
||||
return $filteredInput === '' || $this->validateFilteredInput($filteredInput);
|
||||
}
|
||||
|
||||
private function filter(string $input): string
|
||||
{
|
||||
return str_replace(str_split($this->additionalChars), '', $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\NestedValidationException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function is_scalar;
|
||||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
abstract class AbstractRelated extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $mandatory = true;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $reference;
|
||||
|
||||
/**
|
||||
* @var Validatable|null
|
||||
*/
|
||||
private $rule;
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
abstract public function hasReference($input): bool;
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function getReferenceValue($input);
|
||||
|
||||
/**
|
||||
* @param mixed $reference
|
||||
*/
|
||||
public function __construct($reference, ?Validatable $rule = null, bool $mandatory = true)
|
||||
{
|
||||
$this->reference = $reference;
|
||||
$this->rule = $rule;
|
||||
$this->mandatory = $mandatory;
|
||||
|
||||
if ($rule && $rule->getName() !== null) {
|
||||
$this->setName($rule->getName());
|
||||
} elseif (is_scalar($reference)) {
|
||||
$this->setName((string) $reference);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getReference()
|
||||
{
|
||||
return $this->reference;
|
||||
}
|
||||
|
||||
public function isMandatory(): bool
|
||||
{
|
||||
return $this->mandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setName(string $name): Validatable
|
||||
{
|
||||
parent::setName($name);
|
||||
|
||||
if ($this->rule instanceof Validatable) {
|
||||
$this->rule->setName($name);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
$hasReference = $this->hasReference($input);
|
||||
if ($this->mandatory && !$hasReference) {
|
||||
throw $this->reportError($input, ['hasReference' => false]);
|
||||
}
|
||||
|
||||
if ($this->rule === null || !$hasReference) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->rule->assert($this->getReferenceValue($input));
|
||||
} catch (ValidationException $validationException) {
|
||||
/** @var NestedValidationException $nestedValidationException */
|
||||
$nestedValidationException = $this->reportError($this->reference, ['hasReference' => true]);
|
||||
$nestedValidationException->addChild($validationException);
|
||||
|
||||
throw $nestedValidationException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
$hasReference = $this->hasReference($input);
|
||||
if ($this->mandatory && !$hasReference) {
|
||||
throw $this->reportError($input, ['hasReference' => false]);
|
||||
}
|
||||
|
||||
if ($this->rule === null || !$hasReference) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->rule->check($this->getReferenceValue($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
$hasReference = $this->hasReference($input);
|
||||
if ($this->mandatory && !$hasReference) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->rule === null || !$hasReference) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->rule->validate($this->getReferenceValue($input));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Factory;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
* @author Vicente Mendoza <vicentemmor@yahoo.com.mx>
|
||||
*/
|
||||
abstract class AbstractRule implements Validatable
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $default;
|
||||
/**
|
||||
* @var bool|false
|
||||
*/
|
||||
protected $defaultType;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $template;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
if ($this->validate($input)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
$this->assert($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function reportError($input, array $extraParams = []): ValidationException
|
||||
{
|
||||
return Factory::getDefaultInstance()->exception($this, $input, $extraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setName(string $name): Validatable
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setTemplate(string $template): Validatable
|
||||
{
|
||||
$this->template = $template;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getDefault(): ?string
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getDefaultType(): ?bool
|
||||
{
|
||||
return $this->defaultType;
|
||||
}
|
||||
public function setDefault(string $default, bool $defaultType=false): Validatable
|
||||
{
|
||||
$this->default = $default;
|
||||
$this->defaultType = $defaultType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed$input
|
||||
*/
|
||||
public function __invoke($input): bool
|
||||
{
|
||||
return $this->validate($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Helpers\CanValidateUndefined;
|
||||
|
||||
use function in_array;
|
||||
use function is_scalar;
|
||||
use function mb_strtoupper;
|
||||
|
||||
/**
|
||||
* Abstract class for searches into arrays.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
abstract class AbstractSearcher extends AbstractRule
|
||||
{
|
||||
use CanValidateUndefined;
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
* @return mixed[]
|
||||
*/
|
||||
abstract protected function getDataSource($input = null): array;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
$dataSource = $this->getDataSource($input);
|
||||
|
||||
if ($this->isUndefined($input) && empty($dataSource)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array(mb_strtoupper((string) $input), $dataSource, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
/**
|
||||
* Abstract class to help on creating rules that wrap rules.
|
||||
*
|
||||
* @author Alasdair North <alasdair@runway.io>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
abstract class AbstractWrapper extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var Validatable
|
||||
*/
|
||||
private $validatable;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*/
|
||||
public function __construct(Validatable $validatable)
|
||||
{
|
||||
$this->validatable = $validatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
$this->validatable->assert($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
$this->validatable->check($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return $this->validatable->validate($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setName(string $name): Validatable
|
||||
{
|
||||
$this->validatable->setName($name);
|
||||
|
||||
return parent::setName($name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\AllOfException;
|
||||
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
class AllOf extends AbstractComposite
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
$exceptions = $this->getAllThrownExceptions($input);
|
||||
$numRules = count($this->getRules());
|
||||
$numExceptions = count($exceptions);
|
||||
$summary = [
|
||||
'total' => $numRules,
|
||||
'failed' => $numExceptions,
|
||||
'passed' => $numRules - $numExceptions,
|
||||
];
|
||||
if (!empty($exceptions)) {
|
||||
/** @var AllOfException $allOfException */
|
||||
$allOfException = $this->reportError($input, $summary);
|
||||
$allOfException->addChildren($exceptions);
|
||||
|
||||
throw $allOfException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
foreach ($this->getRules() as $rule) {
|
||||
$rule->check($input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
foreach ($this->getRules() as $rule) {
|
||||
if (!$rule->validate($input)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function ctype_alnum;
|
||||
|
||||
/**
|
||||
* Validates whether the input is alphanumeric or not.
|
||||
*
|
||||
* Alphanumeric is a combination of alphabetic (a-z and A-Z) and numeric (0-9)
|
||||
* characters.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
final class Alnum extends AbstractFilterRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateFilteredInput(string $input): bool
|
||||
{
|
||||
return ctype_alnum($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function ctype_alpha;
|
||||
|
||||
/**
|
||||
* Validates whether the input contains only alphabetic characters.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
final class Alpha extends AbstractFilterRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateFilteredInput(string $input): bool
|
||||
{
|
||||
return ctype_alpha($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates any input as invalid.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class AlwaysInvalid extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates any input as valid.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class AlwaysValid extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\AnyOfException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class AnyOf extends AbstractComposite
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
$validators = $this->getRules();
|
||||
$exceptions = $this->getAllThrownExceptions($input);
|
||||
$numRules = count($validators);
|
||||
$numExceptions = count($exceptions);
|
||||
if ($numExceptions === $numRules) {
|
||||
/** @var AnyOfException $anyOfException */
|
||||
$anyOfException = $this->reportError($input);
|
||||
$anyOfException->addChildren($exceptions);
|
||||
|
||||
throw $anyOfException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
foreach ($this->getRules() as $v) {
|
||||
if ($v->validate($input)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
foreach ($this->getRules() as $v) {
|
||||
try {
|
||||
$v->check($input);
|
||||
|
||||
return;
|
||||
} catch (ValidationException $e) {
|
||||
if (!isset($firstException)) {
|
||||
$firstException = $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($firstException)) {
|
||||
throw $firstException;
|
||||
}
|
||||
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Validates whether the type of an input is array.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author João Torquato <joao.otl@gmail.com>
|
||||
*/
|
||||
final class ArrayType extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_array($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use ArrayAccess;
|
||||
use SimpleXMLElement;
|
||||
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Validates if the input is an array or if the input can be used as an array.
|
||||
*
|
||||
* Instance of `ArrayAccess` or `SimpleXMLElement` are also considered as valid.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class ArrayVal extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_array($input) || $input instanceof ArrayAccess || $input instanceof SimpleXMLElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use ReflectionException;
|
||||
use ReflectionProperty;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function is_object;
|
||||
use function property_exists;
|
||||
|
||||
/**
|
||||
* Validates an object attribute, event private ones.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Attribute extends AbstractRelated
|
||||
{
|
||||
public function __construct(string $reference, ?Validatable $rule = null, bool $mandatory = true)
|
||||
{
|
||||
parent::__construct($reference, $rule, $mandatory);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getReferenceValue($input)
|
||||
{
|
||||
$propertyMirror = new ReflectionProperty($input, (string) $this->getReference());
|
||||
$propertyMirror->setAccessible(true);
|
||||
|
||||
return $propertyMirror->getValue($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasReference($input): bool
|
||||
{
|
||||
return is_object($input) && property_exists($input, (string) $this->getReference());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function is_null;
|
||||
use function mb_strlen;
|
||||
use function mb_substr;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Validate numbers in any base, even with non regular bases.
|
||||
*
|
||||
* @author Carlos André Ferrari <caferrari@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Base extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $base;
|
||||
|
||||
/**
|
||||
* Initializes the Base rule.
|
||||
*/
|
||||
public function __construct(int $base, ?string $chars = null)
|
||||
{
|
||||
if (!is_null($chars)) {
|
||||
$this->chars = $chars;
|
||||
}
|
||||
|
||||
$max = mb_strlen($this->chars);
|
||||
if ($base > $max) {
|
||||
throw new ComponentException(sprintf('a base between 1 and %s is required', $max));
|
||||
}
|
||||
$this->base = $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
$valid = mb_substr($this->chars, 0, $this->base);
|
||||
|
||||
return (bool) preg_match('@^[' . $valid . ']+$@', (string) $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_string;
|
||||
use function mb_strlen;
|
||||
use function preg_match;
|
||||
|
||||
/**
|
||||
* Validate if a string is Base64-encoded.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jens Segers <segers.jens@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Base64 extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!preg_match('#^[A-Za-z0-9+/\n\r]+={0,2}$#', $input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mb_strlen($input) % 4 === 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Helpers\CanCompareValues;
|
||||
|
||||
/**
|
||||
* Validates whether the input is between two other values.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Between extends AbstractEnvelope
|
||||
{
|
||||
use CanCompareValues;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param mixed $minValue
|
||||
* @param mixed $maxValue
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function __construct($minValue, $maxValue)
|
||||
{
|
||||
if ($this->toComparable($minValue) >= $this->toComparable($maxValue)) {
|
||||
throw new ComponentException('Minimum cannot be less than or equals to maximum');
|
||||
}
|
||||
|
||||
parent::__construct(
|
||||
new AllOf(
|
||||
new Min($minValue),
|
||||
new Max($maxValue)
|
||||
),
|
||||
[
|
||||
'minValue' => $minValue,
|
||||
'maxValue' => $maxValue,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_bool;
|
||||
|
||||
/**
|
||||
* Validates whether the type of the input is boolean.
|
||||
*
|
||||
* @author Devin Torres <devin@devintorres.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class BoolType extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_bool($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function filter_var;
|
||||
use function is_bool;
|
||||
|
||||
use const FILTER_NULL_ON_FAILURE;
|
||||
use const FILTER_VALIDATE_BOOLEAN;
|
||||
|
||||
/**
|
||||
* Validates if the input results in a boolean value.
|
||||
*
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class BoolVal extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_bool(filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function ctype_digit;
|
||||
use function intval;
|
||||
use function is_scalar;
|
||||
use function mb_strlen;
|
||||
use function strval;
|
||||
|
||||
/**
|
||||
* Validates a Dutch citizen service number (BSN).
|
||||
*
|
||||
* @see https://nl.wikipedia.org/wiki/Burgerservicenummer
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Ronald Drenth <ronalddrenth@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Bsn extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$input = (string) $input;
|
||||
|
||||
if (!ctype_digit($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mb_strlen(strval($input)) !== 9) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sum = -1 * intval($input[8]);
|
||||
for ($i = 9; $i > 1; --$i) {
|
||||
$sum += $i * intval($input[9 - $i]);
|
||||
}
|
||||
|
||||
return $sum !== 0 && $sum % 11 === 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Validatable;
|
||||
use Throwable;
|
||||
|
||||
use function call_user_func;
|
||||
use function restore_error_handler;
|
||||
use function set_error_handler;
|
||||
|
||||
/**
|
||||
* Validates the return of a callable for a given input.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Call extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $callable;
|
||||
|
||||
/**
|
||||
* @var Validatable
|
||||
*/
|
||||
private $rule;
|
||||
|
||||
/**
|
||||
* Initializes the rule with the callable to be executed after the input is passed.
|
||||
*/
|
||||
public function __construct(callable $callable, Validatable $rule)
|
||||
{
|
||||
$this->callable = $callable;
|
||||
$this->rule = $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
$this->setErrorHandler($input);
|
||||
|
||||
try {
|
||||
$this->rule->assert(call_user_func($this->callable, $input));
|
||||
} catch (ValidationException $exception) {
|
||||
throw $exception;
|
||||
} catch (Throwable $throwable) {
|
||||
throw $this->reportError($input);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
$this->setErrorHandler($input);
|
||||
|
||||
try {
|
||||
$this->rule->check(call_user_func($this->callable, $input));
|
||||
} catch (ValidationException $exception) {
|
||||
throw $exception;
|
||||
} catch (Throwable $throwable) {
|
||||
throw $this->reportError($input);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
try {
|
||||
$this->check($input);
|
||||
} catch (ValidationException $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function setErrorHandler($input): void
|
||||
{
|
||||
set_error_handler(function () use ($input): void {
|
||||
throw $this->reportError($input);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_callable;
|
||||
|
||||
/**
|
||||
* Validates whether the pseudo-type of the input is callable.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class CallableType extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_callable($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function array_merge;
|
||||
use function call_user_func_array;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Validates the input using the return of a given callable.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Callback extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $callback;
|
||||
|
||||
/**
|
||||
* @var mixed[]
|
||||
*/
|
||||
private $arguments;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param mixed ...$arguments
|
||||
*/
|
||||
public function __construct(callable $callback, ...$arguments)
|
||||
{
|
||||
$this->callback = $callback;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return (bool) call_user_func_array($this->callback, $this->getArguments($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function getArguments($input): array
|
||||
{
|
||||
$arguments = [$input];
|
||||
if (count($this->arguments) === 0) {
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
return array_merge($arguments, $this->arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function array_diff;
|
||||
use function in_array;
|
||||
use function mb_detect_encoding;
|
||||
use function mb_list_encodings;
|
||||
|
||||
/**
|
||||
* Validates if a string is in a specific charset.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Charset extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $charset;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function __construct(string ...$charset)
|
||||
{
|
||||
$available = mb_list_encodings();
|
||||
if (!empty(array_diff($charset, $available))) {
|
||||
throw new ComponentException('Invalid charset');
|
||||
}
|
||||
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return in_array(mb_detect_encoding($input, $this->charset, true), $this->charset, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_scalar;
|
||||
use function mb_strlen;
|
||||
use function preg_replace;
|
||||
|
||||
/**
|
||||
* Validates a Brazilian driver's license.
|
||||
*
|
||||
* @author Gabriel Pedro <gpedro@users.noreply.github.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Kinn Coelho Julião <kinncj@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Cnh extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Canonicalize input
|
||||
$input = (string) preg_replace('{\D}', '', (string) $input);
|
||||
|
||||
// Validate length and invalid numbers
|
||||
if (mb_strlen($input) != 11 || ((int) $input === 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate check digits using a modulus 11 algorithm
|
||||
for ($c = $s1 = $s2 = 0, $p = 9; $c < 9; $c++, $p--) {
|
||||
$s1 += (int) $input[$c] * $p;
|
||||
$s2 += (int) $input[$c] * (10 - $p);
|
||||
}
|
||||
|
||||
$dv1 = $s1 % 11;
|
||||
if ($input[9] != ($dv1 > 9) ? 0 : $dv1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dv2 = $s2 % 11 - ($dv1 > 9 ? 2 : 0);
|
||||
$check = $dv2 < 0 ? $dv2 + 11 : ($dv2 > 9 ? 0 : $dv2);
|
||||
|
||||
return $input[10] == $check;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function array_map;
|
||||
use function array_sum;
|
||||
use function count;
|
||||
use function is_scalar;
|
||||
use function preg_replace;
|
||||
use function str_split;
|
||||
|
||||
/**
|
||||
* Validates if the input is a Brazilian National Registry of Legal Entities (CNPJ) number.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jayson Reis <santosdosreis@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
* @author Renato Moura <renato@naturalweb.com.br>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Cnpj extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Code ported from jsfromhell.com
|
||||
$bases = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
||||
$digits = $this->getDigits((string) $input);
|
||||
|
||||
if (array_sum($digits) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($digits) !== 14) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$n = 0;
|
||||
for ($i = 0; $i < 12; ++$i) {
|
||||
$n += $digits[$i] * $bases[$i + 1];
|
||||
}
|
||||
|
||||
if ($digits[12] != (($n %= 11) < 2 ? 0 : 11 - $n)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$n = 0;
|
||||
for ($i = 0; $i <= 12; ++$i) {
|
||||
$n += $digits[$i] * $bases[$i];
|
||||
}
|
||||
|
||||
$check = ($n %= 11) < 2 ? 0 : 11 - $n;
|
||||
|
||||
return $digits[13] == $check;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
private function getDigits(string $input): array
|
||||
{
|
||||
return array_map(
|
||||
'intval',
|
||||
str_split(
|
||||
(string) preg_replace('/\D/', '', $input)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function preg_match;
|
||||
|
||||
/**
|
||||
* Validates if the input contains only consonants.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
final class Consonant extends AbstractFilterRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateFilteredInput(string $input): bool
|
||||
{
|
||||
return preg_match('/^(\s|[b-df-hj-np-tv-zB-DF-HJ-NP-TV-Z])*$/', $input) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_scalar;
|
||||
use function mb_stripos;
|
||||
use function mb_strpos;
|
||||
|
||||
/**
|
||||
* Validates if the input contains some value.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Marcelo Araujo <msaraujo@php.net>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Contains extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $containsValue;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $identical;
|
||||
|
||||
/**
|
||||
* Initializes the Contains rule.
|
||||
*
|
||||
* @param mixed $containsValue Value that will be sought
|
||||
* @param bool $identical Defines whether the value is identical, default is false
|
||||
*/
|
||||
public function __construct($containsValue, bool $identical = false)
|
||||
{
|
||||
$this->containsValue = $containsValue;
|
||||
$this->identical = $identical;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (is_array($input)) {
|
||||
return in_array($this->containsValue, $input, $this->identical);
|
||||
}
|
||||
|
||||
if (!is_scalar($input) || !is_scalar($this->containsValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->validateString((string) $input, (string) $this->containsValue);
|
||||
}
|
||||
|
||||
private function validateString(string $haystack, string $needle): bool
|
||||
{
|
||||
if ($needle === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->identical) {
|
||||
return mb_strpos($haystack, $needle) !== false;
|
||||
}
|
||||
|
||||
return mb_stripos($haystack, $needle) !== false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function array_map;
|
||||
|
||||
/**
|
||||
* Validates if the input contains at least one of defined values
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Kirill Dlussky <kirill@dlussky.ru>
|
||||
*/
|
||||
final class ContainsAny extends AbstractEnvelope
|
||||
{
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param mixed[] $needles At least one of the values provided must be found in input string or array
|
||||
* @param bool $identical Defines whether the value should be compared strictly, when validating array
|
||||
*/
|
||||
public function __construct(array $needles, bool $identical = false)
|
||||
{
|
||||
parent::__construct(
|
||||
new AnyOf(...$this->getRules($needles, $identical)),
|
||||
['needles' => $needles]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $needles
|
||||
*
|
||||
* @return Contains[]
|
||||
*/
|
||||
private function getRules(array $needles, bool $identical): array
|
||||
{
|
||||
return array_map(
|
||||
static function ($needle) use ($identical): Contains {
|
||||
return new Contains($needle, $identical);
|
||||
},
|
||||
$needles
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function ctype_cntrl;
|
||||
|
||||
/**
|
||||
* Validates if all of the characters in the provided string, are control characters.
|
||||
*
|
||||
* @author Andre Ramaciotti <andre@ramaciotti.com>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
final class Control extends AbstractFilterRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateFilteredInput(string $input): bool
|
||||
{
|
||||
return ctype_cntrl($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Countable as CountableInterface;
|
||||
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Validates if the input is countable.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author João Torquato <joao.otl@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Countable extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_array($input) || $input instanceof CountableInterface;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function array_column;
|
||||
use function array_keys;
|
||||
use function implode;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a country code in ISO 3166-1 standard.
|
||||
*
|
||||
* This rule supports the three sets of country codes (alpha-2, alpha-3, and numeric).
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Felipe Martins <me@fefas.net>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class CountryCode extends AbstractSearcher
|
||||
{
|
||||
/**
|
||||
* The ISO representation of a country code.
|
||||
*/
|
||||
public const ALPHA2 = 'alpha-2';
|
||||
|
||||
/**
|
||||
* The ISO3 representation of a country code.
|
||||
*/
|
||||
public const ALPHA3 = 'alpha-3';
|
||||
|
||||
/**
|
||||
* The ISO-number representation of a country code.
|
||||
*/
|
||||
public const NUMERIC = 'numeric';
|
||||
|
||||
/**
|
||||
* Position of the indexes of each set in the list of country codes.
|
||||
*/
|
||||
private const SET_INDEXES = [
|
||||
self::ALPHA2 => 0,
|
||||
self::ALPHA3 => 1,
|
||||
self::NUMERIC => 2,
|
||||
];
|
||||
|
||||
/**
|
||||
* @see https://salsa.debian.org/iso-codes-team/iso-codes
|
||||
*/
|
||||
private const COUNTRY_CODES = [
|
||||
// begin of auto-generated code
|
||||
['AD', 'AND', '020'], // Andorra
|
||||
['AE', 'ARE', '784'], // United Arab Emirates
|
||||
['AF', 'AFG', '004'], // Afghanistan
|
||||
['AG', 'ATG', '028'], // Antigua and Barbuda
|
||||
['AI', 'AFI', '262'], // French Afars and Issas
|
||||
['AI', 'AIA', '660'], // Anguilla
|
||||
['AL', 'ALB', '008'], // Albania
|
||||
['AM', 'ARM', '051'], // Armenia
|
||||
['AN', 'ANT', '530'], // Netherlands Antilles
|
||||
['AO', 'AGO', '024'], // Angola
|
||||
['AQ', 'ATA', '010'], // Antarctica
|
||||
['AR', 'ARG', '032'], // Argentina
|
||||
['AS', 'ASM', '016'], // American Samoa
|
||||
['AT', 'AUT', '040'], // Austria
|
||||
['AU', 'AUS', '036'], // Australia
|
||||
['AW', 'ABW', '533'], // Aruba
|
||||
['AX', 'ALA', '248'], // Åland Islands
|
||||
['AZ', 'AZE', '031'], // Azerbaijan
|
||||
['BA', 'BIH', '070'], // Bosnia and Herzegovina
|
||||
['BB', 'BRB', '052'], // Barbados
|
||||
['BD', 'BGD', '050'], // Bangladesh
|
||||
['BE', 'BEL', '056'], // Belgium
|
||||
['BF', 'BFA', '854'], // Burkina Faso
|
||||
['BG', 'BGR', '100'], // Bulgaria
|
||||
['BH', 'BHR', '048'], // Bahrain
|
||||
['BI', 'BDI', '108'], // Burundi
|
||||
['BJ', 'BEN', '204'], // Benin
|
||||
['BL', 'BLM', '652'], // Saint Barthélemy
|
||||
['BM', 'BMU', '060'], // Bermuda
|
||||
['BN', 'BRN', '096'], // Brunei Darussalam
|
||||
['BO', 'BOL', '068'], // Bolivia, Plurinational State of
|
||||
['BQ', 'ATB', null], // British Antarctic Territory
|
||||
['BQ', 'BES', '535'], // Bonaire, Sint Eustatius and Saba
|
||||
['BR', 'BRA', '076'], // Brazil
|
||||
['BS', 'BHS', '044'], // Bahamas
|
||||
['BT', 'BTN', '064'], // Bhutan
|
||||
['BU', 'BUR', '104'], // Burma, Socialist Republic of the Union of
|
||||
['BV', 'BVT', '074'], // Bouvet Island
|
||||
['BW', 'BWA', '072'], // Botswana
|
||||
['BY', 'BLR', '112'], // Belarus
|
||||
['BY', 'BYS', '112'], // Byelorussian SSR Soviet Socialist Republic
|
||||
['BZ', 'BLZ', '084'], // Belize
|
||||
['CA', 'CAN', '124'], // Canada
|
||||
['CC', 'CCK', '166'], // Cocos (Keeling) Islands
|
||||
['CD', 'COD', '180'], // Congo, The Democratic Republic of the
|
||||
['CF', 'CAF', '140'], // Central African Republic
|
||||
['CG', 'COG', '178'], // Congo
|
||||
['CH', 'CHE', '756'], // Switzerland
|
||||
['CI', 'CIV', '384'], // Côte d'Ivoire
|
||||
['CK', 'COK', '184'], // Cook Islands
|
||||
['CL', 'CHL', '152'], // Chile
|
||||
['CM', 'CMR', '120'], // Cameroon
|
||||
['CN', 'CHN', '156'], // China
|
||||
['CO', 'COL', '170'], // Colombia
|
||||
['CR', 'CRI', '188'], // Costa Rica
|
||||
['CS', 'CSK', '200'], // Czechoslovakia, Czechoslovak Socialist Republic
|
||||
['CS', 'SCG', '891'], // Serbia and Montenegro
|
||||
['CT', 'CTE', '128'], // Canton and Enderbury Islands
|
||||
['CU', 'CUB', '192'], // Cuba
|
||||
['CV', 'CPV', '132'], // Cabo Verde
|
||||
['CW', 'CUW', '531'], // Curaçao
|
||||
['CX', 'CXR', '162'], // Christmas Island
|
||||
['CY', 'CYP', '196'], // Cyprus
|
||||
['CZ', 'CZE', '203'], // Czechia
|
||||
['DD', 'DDR', '278'], // German Democratic Republic
|
||||
['DE', 'DEU', '276'], // Germany
|
||||
['DJ', 'DJI', '262'], // Djibouti
|
||||
['DK', 'DNK', '208'], // Denmark
|
||||
['DM', 'DMA', '212'], // Dominica
|
||||
['DO', 'DOM', '214'], // Dominican Republic
|
||||
['DY', 'DHY', '204'], // Dahomey
|
||||
['DZ', 'DZA', '012'], // Algeria
|
||||
['EC', 'ECU', '218'], // Ecuador
|
||||
['EE', 'EST', '233'], // Estonia
|
||||
['EG', 'EGY', '818'], // Egypt
|
||||
['EH', 'ESH', '732'], // Western Sahara
|
||||
['ER', 'ERI', '232'], // Eritrea
|
||||
['ES', 'ESP', '724'], // Spain
|
||||
['ET', 'ETH', '231'], // Ethiopia
|
||||
['FI', 'FIN', '246'], // Finland
|
||||
['FJ', 'FJI', '242'], // Fiji
|
||||
['FK', 'FLK', '238'], // Falkland Islands (Malvinas)
|
||||
['FM', 'FSM', '583'], // Micronesia, Federated States of
|
||||
['FO', 'FRO', '234'], // Faroe Islands
|
||||
['FQ', 'ATF', null], // French Southern and Antarctic Territories
|
||||
['FR', 'FRA', '250'], // France
|
||||
['FX', 'FXX', '249'], // France, Metropolitan
|
||||
['GA', 'GAB', '266'], // Gabon
|
||||
['GB', 'GBR', '826'], // United Kingdom
|
||||
['GD', 'GRD', '308'], // Grenada
|
||||
['GE', 'GEL', '296'], // Gilbert and Ellice Islands
|
||||
['GE', 'GEO', '268'], // Georgia
|
||||
['GF', 'GUF', '254'], // French Guiana
|
||||
['GG', 'GGY', '831'], // Guernsey
|
||||
['GH', 'GHA', '288'], // Ghana
|
||||
['GI', 'GIB', '292'], // Gibraltar
|
||||
['GL', 'GRL', '304'], // Greenland
|
||||
['GM', 'GMB', '270'], // Gambia
|
||||
['GN', 'GIN', '324'], // Guinea
|
||||
['GP', 'GLP', '312'], // Guadeloupe
|
||||
['GQ', 'GNQ', '226'], // Equatorial Guinea
|
||||
['GR', 'GRC', '300'], // Greece
|
||||
['GS', 'SGS', '239'], // South Georgia and the South Sandwich Islands
|
||||
['GT', 'GTM', '320'], // Guatemala
|
||||
['GU', 'GUM', '316'], // Guam
|
||||
['GW', 'GNB', '624'], // Guinea-Bissau
|
||||
['GY', 'GUY', '328'], // Guyana
|
||||
['HK', 'HKG', '344'], // Hong Kong
|
||||
['HM', 'HMD', '334'], // Heard Island and McDonald Islands
|
||||
['HN', 'HND', '340'], // Honduras
|
||||
['HR', 'HRV', '191'], // Croatia
|
||||
['HT', 'HTI', '332'], // Haiti
|
||||
['HU', 'HUN', '348'], // Hungary
|
||||
['HV', 'HVO', '854'], // Upper Volta, Republic of
|
||||
['ID', 'IDN', '360'], // Indonesia
|
||||
['IE', 'IRL', '372'], // Ireland
|
||||
['IL', 'ISR', '376'], // Israel
|
||||
['IM', 'IMN', '833'], // Isle of Man
|
||||
['IN', 'IND', '356'], // India
|
||||
['IO', 'IOT', '086'], // British Indian Ocean Territory
|
||||
['IQ', 'IRQ', '368'], // Iraq
|
||||
['IR', 'IRN', '364'], // Iran, Islamic Republic of
|
||||
['IS', 'ISL', '352'], // Iceland
|
||||
['IT', 'ITA', '380'], // Italy
|
||||
['JE', 'JEY', '832'], // Jersey
|
||||
['JM', 'JAM', '388'], // Jamaica
|
||||
['JO', 'JOR', '400'], // Jordan
|
||||
['JP', 'JPN', '392'], // Japan
|
||||
['JT', 'JTN', '396'], // Johnston Island
|
||||
['KE', 'KEN', '404'], // Kenya
|
||||
['KG', 'KGZ', '417'], // Kyrgyzstan
|
||||
['KH', 'KHM', '116'], // Cambodia
|
||||
['KI', 'KIR', '296'], // Kiribati
|
||||
['KM', 'COM', '174'], // Comoros
|
||||
['KN', 'KNA', '659'], // Saint Kitts and Nevis
|
||||
['KP', 'PRK', '408'], // Korea, Democratic People's Republic of
|
||||
['KR', 'KOR', '410'], // Korea, Republic of
|
||||
['KW', 'KWT', '414'], // Kuwait
|
||||
['KY', 'CYM', '136'], // Cayman Islands
|
||||
['KZ', 'KAZ', '398'], // Kazakhstan
|
||||
['LA', 'LAO', '418'], // Lao People's Democratic Republic
|
||||
['LB', 'LBN', '422'], // Lebanon
|
||||
['LC', 'LCA', '662'], // Saint Lucia
|
||||
['LI', 'LIE', '438'], // Liechtenstein
|
||||
['LK', 'LKA', '144'], // Sri Lanka
|
||||
['LR', 'LBR', '430'], // Liberia
|
||||
['LS', 'LSO', '426'], // Lesotho
|
||||
['LT', 'LTU', '440'], // Lithuania
|
||||
['LU', 'LUX', '442'], // Luxembourg
|
||||
['LV', 'LVA', '428'], // Latvia
|
||||
['LY', 'LBY', '434'], // Libya
|
||||
['MA', 'MAR', '504'], // Morocco
|
||||
['MC', 'MCO', '492'], // Monaco
|
||||
['MD', 'MDA', '498'], // Moldova, Republic of
|
||||
['ME', 'MNE', '499'], // Montenegro
|
||||
['MF', 'MAF', '663'], // Saint Martin (French part)
|
||||
['MG', 'MDG', '450'], // Madagascar
|
||||
['MH', 'MHL', '584'], // Marshall Islands
|
||||
['MI', 'MID', '488'], // Midway Islands
|
||||
['MK', 'MKD', '807'], // North Macedonia
|
||||
['ML', 'MLI', '466'], // Mali
|
||||
['MM', 'MMR', '104'], // Myanmar
|
||||
['MN', 'MNG', '496'], // Mongolia
|
||||
['MO', 'MAC', '446'], // Macao
|
||||
['MP', 'MNP', '580'], // Northern Mariana Islands
|
||||
['MQ', 'MTQ', '474'], // Martinique
|
||||
['MR', 'MRT', '478'], // Mauritania
|
||||
['MS', 'MSR', '500'], // Montserrat
|
||||
['MT', 'MLT', '470'], // Malta
|
||||
['MU', 'MUS', '480'], // Mauritius
|
||||
['MV', 'MDV', '462'], // Maldives
|
||||
['MW', 'MWI', '454'], // Malawi
|
||||
['MX', 'MEX', '484'], // Mexico
|
||||
['MY', 'MYS', '458'], // Malaysia
|
||||
['MZ', 'MOZ', '508'], // Mozambique
|
||||
['NA', 'NAM', '516'], // Namibia
|
||||
['NC', 'NCL', '540'], // New Caledonia
|
||||
['NE', 'NER', '562'], // Niger
|
||||
['NF', 'NFK', '574'], // Norfolk Island
|
||||
['NG', 'NGA', '566'], // Nigeria
|
||||
['NH', 'NHB', '548'], // New Hebrides
|
||||
['NI', 'NIC', '558'], // Nicaragua
|
||||
['NL', 'NLD', '528'], // Netherlands
|
||||
['NO', 'NOR', '578'], // Norway
|
||||
['NP', 'NPL', '524'], // Nepal
|
||||
['NQ', 'ATN', '216'], // Dronning Maud Land
|
||||
['NR', 'NRU', '520'], // Nauru
|
||||
['NT', 'NTZ', '536'], // Neutral Zone
|
||||
['NU', 'NIU', '570'], // Niue
|
||||
['NZ', 'NZL', '554'], // New Zealand
|
||||
['OM', 'OMN', '512'], // Oman
|
||||
['PA', 'PAN', '591'], // Panama
|
||||
['PC', 'PCI', '582'], // Pacific Islands (trust territory)
|
||||
['PE', 'PER', '604'], // Peru
|
||||
['PF', 'PYF', '258'], // French Polynesia
|
||||
['PG', 'PNG', '598'], // Papua New Guinea
|
||||
['PH', 'PHL', '608'], // Philippines
|
||||
['PK', 'PAK', '586'], // Pakistan
|
||||
['PL', 'POL', '616'], // Poland
|
||||
['PM', 'SPM', '666'], // Saint Pierre and Miquelon
|
||||
['PN', 'PCN', '612'], // Pitcairn
|
||||
['PR', 'PRI', '630'], // Puerto Rico
|
||||
['PS', 'PSE', '275'], // Palestine, State of
|
||||
['PT', 'PRT', '620'], // Portugal
|
||||
['PU', 'PUS', '849'], // US Miscellaneous Pacific Islands
|
||||
['PW', 'PLW', '585'], // Palau
|
||||
['PY', 'PRY', '600'], // Paraguay
|
||||
['PZ', 'PCZ', null], // Panama Canal Zone
|
||||
['QA', 'QAT', '634'], // Qatar
|
||||
['RE', 'REU', '638'], // Réunion
|
||||
['RH', 'RHO', '716'], // Southern Rhodesia
|
||||
['RO', 'ROU', '642'], // Romania
|
||||
['RS', 'SRB', '688'], // Serbia
|
||||
['RU', 'RUS', '643'], // Russian Federation
|
||||
['RW', 'RWA', '646'], // Rwanda
|
||||
['SA', 'SAU', '682'], // Saudi Arabia
|
||||
['SB', 'SLB', '090'], // Solomon Islands
|
||||
['SC', 'SYC', '690'], // Seychelles
|
||||
['SD', 'SDN', '729'], // Sudan
|
||||
['SE', 'SWE', '752'], // Sweden
|
||||
['SG', 'SGP', '702'], // Singapore
|
||||
['SH', 'SHN', '654'], // Saint Helena, Ascension and Tristan da Cunha
|
||||
['SI', 'SVN', '705'], // Slovenia
|
||||
['SJ', 'SJM', '744'], // Svalbard and Jan Mayen
|
||||
['SK', 'SKM', null], // Sikkim
|
||||
['SK', 'SVK', '703'], // Slovakia
|
||||
['SL', 'SLE', '694'], // Sierra Leone
|
||||
['SM', 'SMR', '674'], // San Marino
|
||||
['SN', 'SEN', '686'], // Senegal
|
||||
['SO', 'SOM', '706'], // Somalia
|
||||
['SR', 'SUR', '740'], // Suriname
|
||||
['SS', 'SSD', '728'], // South Sudan
|
||||
['ST', 'STP', '678'], // Sao Tome and Principe
|
||||
['SU', 'SUN', '810'], // USSR, Union of Soviet Socialist Republics
|
||||
['SV', 'SLV', '222'], // El Salvador
|
||||
['SX', 'SXM', '534'], // Sint Maarten (Dutch part)
|
||||
['SY', 'SYR', '760'], // Syrian Arab Republic
|
||||
['SZ', 'SWZ', '748'], // Eswatini
|
||||
['TC', 'TCA', '796'], // Turks and Caicos Islands
|
||||
['TD', 'TCD', '148'], // Chad
|
||||
['TF', 'ATF', '260'], // French Southern Territories
|
||||
['TG', 'TGO', '768'], // Togo
|
||||
['TH', 'THA', '764'], // Thailand
|
||||
['TJ', 'TJK', '762'], // Tajikistan
|
||||
['TK', 'TKL', '772'], // Tokelau
|
||||
['TL', 'TLS', '626'], // Timor-Leste
|
||||
['TM', 'TKM', '795'], // Turkmenistan
|
||||
['TN', 'TUN', '788'], // Tunisia
|
||||
['TO', 'TON', '776'], // Tonga
|
||||
['TP', 'TMP', '626'], // East Timor
|
||||
['TR', 'TUR', '792'], // Türkiye
|
||||
['TT', 'TTO', '780'], // Trinidad and Tobago
|
||||
['TV', 'TUV', '798'], // Tuvalu
|
||||
['TW', 'TWN', '158'], // Taiwan, Province of China
|
||||
['TZ', 'TZA', '834'], // Tanzania, United Republic of
|
||||
['UA', 'UKR', '804'], // Ukraine
|
||||
['UG', 'UGA', '800'], // Uganda
|
||||
['UM', 'UMI', '581'], // United States Minor Outlying Islands
|
||||
['US', 'USA', '840'], // United States
|
||||
['UY', 'URY', '858'], // Uruguay
|
||||
['UZ', 'UZB', '860'], // Uzbekistan
|
||||
['VA', 'VAT', '336'], // Holy See (Vatican City State)
|
||||
['VC', 'VCT', '670'], // Saint Vincent and the Grenadines
|
||||
['VD', 'VDR', null], // Viet-Nam, Democratic Republic of
|
||||
['VE', 'VEN', '862'], // Venezuela, Bolivarian Republic of
|
||||
['VG', 'VGB', '092'], // Virgin Islands, British
|
||||
['VI', 'VIR', '850'], // Virgin Islands, U.S.
|
||||
['VN', 'VNM', '704'], // Viet Nam
|
||||
['VU', 'VUT', '548'], // Vanuatu
|
||||
['WF', 'WLF', '876'], // Wallis and Futuna
|
||||
['WK', 'WAK', '872'], // Wake Island
|
||||
['WS', 'WSM', '882'], // Samoa
|
||||
['YD', 'YMD', '720'], // Yemen, Democratic, People's Democratic Republic of
|
||||
['YE', 'YEM', '887'], // Yemen
|
||||
['YT', 'MYT', '175'], // Mayotte
|
||||
['YU', 'YUG', '891'], // Yugoslavia, Socialist Federal Republic of
|
||||
['ZA', 'ZAF', '710'], // South Africa
|
||||
['ZM', 'ZMB', '894'], // Zambia
|
||||
['ZR', 'ZAR', '180'], // Zaire, Republic of
|
||||
['ZW', 'ZWE', '716'], // Zimbabwe
|
||||
// end of auto-generated code
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $set;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @throws ComponentException If $set is not a valid set
|
||||
*/
|
||||
public function __construct(string $set = self::ALPHA2)
|
||||
{
|
||||
if (!isset(self::SET_INDEXES[$set])) {
|
||||
throw new ComponentException(
|
||||
sprintf(
|
||||
'"%s" is not a valid set for ISO 3166-1 (Available: %s)',
|
||||
$set,
|
||||
implode(', ', array_keys(self::SET_INDEXES))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->set = $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDataSource($input = null): array
|
||||
{
|
||||
return array_column(self::COUNTRY_CODES, self::SET_INDEXES[$this->set]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function intval;
|
||||
use function mb_strlen;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a CPF (Brazilian Natural Persons Register) number.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jair Henrique <jair.henrique@gmail.com>
|
||||
* @author Jayson Reis <santosdosreis@gmail.com>
|
||||
* @author Jean Pimentel <jeanfap@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Cpf extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
// Code ported from jsfromhell.com
|
||||
$c = preg_replace('/\D/', '', $input);
|
||||
|
||||
if (mb_strlen($c) != 11 || preg_match('/^' . $c[0] . '{11}$/', $c) || $c === '01234567890') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$n = 0;
|
||||
for ($s = 10, $i = 0; $s >= 2; ++$i, --$s) {
|
||||
$n += intval($c[$i]) * $s;
|
||||
}
|
||||
|
||||
if ($c[9] != (($n %= 11) < 2 ? 0 : 11 - $n)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$n = 0;
|
||||
for ($s = 11, $i = 0; $s >= 2; ++$i, --$s) {
|
||||
$n += intval($c[$i]) * $s;
|
||||
}
|
||||
|
||||
$check = ($n %= 11) < 2 ? 0 : 11 - $n;
|
||||
|
||||
return $c[10] == $check;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function array_keys;
|
||||
use function implode;
|
||||
use function is_scalar;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a credit card number.
|
||||
*
|
||||
* @author Alexander Gorshkov <mazanax@yandex.ru>
|
||||
* @author Andy Snell <andysnell@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jean Pimentel <jeanfap@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
* @author Rakshit Arora <rakshit087@gmail.com>
|
||||
*/
|
||||
final class CreditCard extends AbstractRule
|
||||
{
|
||||
public const ANY = 'Any';
|
||||
|
||||
public const AMERICAN_EXPRESS = 'American Express';
|
||||
|
||||
public const DINERS_CLUB = 'Diners Club';
|
||||
|
||||
public const DISCOVER = 'Discover';
|
||||
|
||||
public const JCB = 'JCB';
|
||||
|
||||
public const MASTERCARD = 'MasterCard';
|
||||
|
||||
public const VISA = 'Visa';
|
||||
|
||||
public const RUPAY = 'RuPay';
|
||||
|
||||
private const BRAND_REGEX_LIST = [
|
||||
self::ANY => '/^[0-9]+$/',
|
||||
self::AMERICAN_EXPRESS => '/^3[47]\d{13}$/',
|
||||
self::DINERS_CLUB => '/^3(?:0[0-5]|[68]\d)\d{11}$/',
|
||||
self::DISCOVER => '/^6(?:011|5\d{2})\d{12}$/',
|
||||
self::JCB => '/^(?:2131|1800|35\d{3})\d{11}$/',
|
||||
self::MASTERCARD => '/(5[1-5]|2[2-7])\d{14}$/',
|
||||
self::VISA => '/^4\d{12}(?:\d{3})?$/',
|
||||
self::RUPAY => '/^6(?!011)(?:0[0-9]{14}|52[12][0-9]{12})$/',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $brand;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function __construct(string $brand = self::ANY)
|
||||
{
|
||||
if (!isset(self::BRAND_REGEX_LIST[$brand])) {
|
||||
throw new ComponentException(
|
||||
sprintf(
|
||||
'"%s" is not a valid credit card brand (Available: %s)',
|
||||
$brand,
|
||||
implode(', ', array_keys(self::BRAND_REGEX_LIST))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->brand = $brand;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$input = (string) preg_replace('/[ .-]/', '', (string) $input);
|
||||
if (!(new Luhn())->validate($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match(self::BRAND_REGEX_LIST[$this->brand], $input) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates currency codes in ISO 4217.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Justin Hook <justinhook88@yahoo.co.uk>
|
||||
* @author Tim Strijdhorst <tstrijdhorst@users.noreply.github.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class CurrencyCode extends AbstractSearcher
|
||||
{
|
||||
/**
|
||||
* @see http://www.currency-iso.org/en/home/tables/table-a1.html
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDataSource($input = null): array
|
||||
{
|
||||
return [
|
||||
'AED', // UAE Dirham
|
||||
'AFN', // Afghani
|
||||
'ALL', // Lek
|
||||
'AMD', // Armenian Dram
|
||||
'ANG', // Netherlands Antillean Guilder
|
||||
'AOA', // Kwanza
|
||||
'ARS', // Argentine Peso
|
||||
'AUD', // Australian Dollar
|
||||
'AWG', // Aruban Florin
|
||||
'AZN', // Azerbaijan Manat
|
||||
'BAM', // Convertible Mark
|
||||
'BBD', // Barbados Dollar
|
||||
'BDT', // Taka
|
||||
'BGN', // Bulgarian Lev
|
||||
'BHD', // Bahraini Dinar
|
||||
'BIF', // Burundi Franc
|
||||
'BMD', // Bermudian Dollar
|
||||
'BND', // Brunei Dollar
|
||||
'BOB', // Boliviano
|
||||
'BOV', // Mvdol
|
||||
'BRL', // Brazilian Real
|
||||
'BSD', // Bahamian Dollar
|
||||
'BTN', // Ngultrum
|
||||
'BWP', // Pula
|
||||
'BYN', // Belarusian Ruble
|
||||
'BZD', // Belize Dollar
|
||||
'CAD', // Canadian Dollar
|
||||
'CDF', // Congolese Franc
|
||||
'CHE', // WIR Euro
|
||||
'CHF', // Swiss Franc
|
||||
'CHW', // WIR Franc
|
||||
'CLF', // Unidad de Fomento
|
||||
'CLP', // Chilean Peso
|
||||
'CNY', // Yuan Renminbi
|
||||
'COP', // Colombian Peso
|
||||
'COU', // Unidad de Valor Real
|
||||
'CRC', // Costa Rican Colon
|
||||
'CUC', // Peso Convertible
|
||||
'CUP', // Cuban Peso
|
||||
'CVE', // Cabo Verde Escudo
|
||||
'CZK', // Czech Koruna
|
||||
'DJF', // Djibouti Franc
|
||||
'DKK', // Danish Krone
|
||||
'DOP', // Dominican Peso
|
||||
'DZD', // Algerian Dinar
|
||||
'EGP', // Egyptian Pound
|
||||
'ERN', // Nakfa
|
||||
'ETB', // Ethiopian Birr
|
||||
'EUR', // Euro
|
||||
'FJD', // Fiji Dollar
|
||||
'FKP', // Falkland Islands Pound
|
||||
'GBP', // Pound Sterling
|
||||
'GEL', // Lari
|
||||
'GHS', // Ghana Cedi
|
||||
'GIP', // Gibraltar Pound
|
||||
'GMD', // Dalasi
|
||||
'GNF', // Guinean Franc
|
||||
'GTQ', // Quetzal
|
||||
'GYD', // Guyana Dollar
|
||||
'HKD', // Hong Kong Dollar
|
||||
'HNL', // Lempira
|
||||
'HTG', // Gourde
|
||||
'HUF', // Forint
|
||||
'IDR', // Rupiah
|
||||
'ILS', // New Israeli Sheqel
|
||||
'INR', // Indian Rupee
|
||||
'IQD', // Iraqi Dinar
|
||||
'IRR', // Iranian Rial
|
||||
'ISK', // Iceland Krona
|
||||
'JMD', // Jamaican Dollar
|
||||
'JOD', // Jordanian Dinar
|
||||
'JPY', // Yen
|
||||
'KES', // Kenyan Shilling
|
||||
'KGS', // Som
|
||||
'KHR', // Riel
|
||||
'KMF', // Comorian Franc
|
||||
'KPW', // North Korean Won
|
||||
'KRW', // Won
|
||||
'KWD', // Kuwaiti Dinar
|
||||
'KYD', // Cayman Islands Dollar
|
||||
'KZT', // Tenge
|
||||
'LAK', // Lao Kip
|
||||
'LBP', // Lebanese Pound
|
||||
'LKR', // Sri Lanka Rupee
|
||||
'LRD', // Liberian Dollar
|
||||
'LSL', // Loti
|
||||
'LYD', // Libyan Dinar
|
||||
'MAD', // Moroccan Dirham
|
||||
'MDL', // Moldovan Leu
|
||||
'MGA', // Malagasy Ariary
|
||||
'MKD', // Denar
|
||||
'MMK', // Kyat
|
||||
'MNT', // Tugrik
|
||||
'MOP', // Pataca
|
||||
'MRU', // Ouguiya
|
||||
'MUR', // Mauritius Rupee
|
||||
'MVR', // Rufiyaa
|
||||
'MWK', // Malawi Kwacha
|
||||
'MXN', // Mexican Peso
|
||||
'MXV', // Mexican Unidad de Inversion (UDI)
|
||||
'MYR', // Malaysian Ringgit
|
||||
'MZN', // Mozambique Metical
|
||||
'NAD', // Namibia Dollar
|
||||
'NGN', // Naira
|
||||
'NIO', // Cordoba Oro
|
||||
'NOK', // Norwegian Krone
|
||||
'NPR', // Nepalese Rupee
|
||||
'NZD', // New Zealand Dollar
|
||||
'OMR', // Rial Omani
|
||||
'PAB', // Balboa
|
||||
'PEN', // Sol
|
||||
'PGK', // Kina
|
||||
'PHP', // Philippine Peso
|
||||
'PKR', // Pakistan Rupee
|
||||
'PLN', // Zloty
|
||||
'PYG', // Guarani
|
||||
'QAR', // Qatari Rial
|
||||
'RON', // Romanian Leu
|
||||
'RSD', // Serbian Dinar
|
||||
'RUB', // Russian Ruble
|
||||
'RWF', // Rwanda Franc
|
||||
'SAR', // Saudi Riyal
|
||||
'SBD', // Solomon Islands Dollar
|
||||
'SCR', // Seychelles Rupee
|
||||
'SDG', // Sudanese Pound
|
||||
'SEK', // Swedish Krona
|
||||
'SGD', // Singapore Dollar
|
||||
'SHP', // Saint Helena Pound
|
||||
'SLE', // Leone
|
||||
'SLL', // Leone
|
||||
'SOS', // Somali Shilling
|
||||
'SRD', // Surinam Dollar
|
||||
'SSP', // South Sudanese Pound
|
||||
'STN', // Dobra
|
||||
'SVC', // El Salvador Colon
|
||||
'SYP', // Syrian Pound
|
||||
'SZL', // Lilangeni
|
||||
'THB', // Baht
|
||||
'TJS', // Somoni
|
||||
'TMT', // Turkmenistan New Manat
|
||||
'TND', // Tunisian Dinar
|
||||
'TOP', // Pa’anga
|
||||
'TRY', // Turkish Lira
|
||||
'TTD', // Trinidad and Tobago Dollar
|
||||
'TWD', // New Taiwan Dollar
|
||||
'TZS', // Tanzanian Shilling
|
||||
'UAH', // Hryvnia
|
||||
'UGX', // Uganda Shilling
|
||||
'USD', // US Dollar
|
||||
'USN', // US Dollar (Next day)
|
||||
'UYI', // Uruguay Peso en Unidades Indexadas (UI)
|
||||
'UYU', // Peso Uruguayo
|
||||
'UYW', // Unidad Previsional
|
||||
'UZS', // Uzbekistan Sum
|
||||
'VED', // Bolívar Soberano
|
||||
'VES', // Bolívar Soberano
|
||||
'VND', // Dong
|
||||
'VUV', // Vatu
|
||||
'WST', // Tala
|
||||
'XAF', // CFA Franc BEAC
|
||||
'XAG', // Silver
|
||||
'XAU', // Gold
|
||||
'XBA', // Bond Markets Unit European Composite Unit (EURCO)
|
||||
'XBB', // Bond Markets Unit European Monetary Unit (E.M.U.-6)
|
||||
'XBC', // Bond Markets Unit European Unit of Account 9 (E.U.A.-9)
|
||||
'XBD', // Bond Markets Unit European Unit of Account 17 (E.U.A.-17)
|
||||
'XCD', // East Caribbean Dollar
|
||||
'XDR', // SDR (Special Drawing Right)
|
||||
'XOF', // CFA Franc BCEAO
|
||||
'XPD', // Palladium
|
||||
'XPF', // CFP Franc
|
||||
'XPT', // Platinum
|
||||
'XSU', // Sucre
|
||||
'XTS', // Codes specifically reserved for testing purposes
|
||||
'XUA', // ADB Unit of Account
|
||||
'XXX', // The codes assigned for transactions where no currency is involved
|
||||
'YER', // Yemeni Rial
|
||||
'ZAR', // Rand
|
||||
'ZMW', // Zambian Kwacha
|
||||
'ZWL', // Zimbabwe Dollar
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Helpers\CanValidateDateTime;
|
||||
|
||||
use function date;
|
||||
use function is_scalar;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function strtotime;
|
||||
|
||||
/**
|
||||
* Validates if input is a date.
|
||||
*
|
||||
* @author Bruno Luiz da Silva <contato@brunoluiz.net>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Date extends AbstractRule
|
||||
{
|
||||
use CanValidateDateTime;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $format;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sample;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function __construct(string $format = 'Y-m-d')
|
||||
{
|
||||
if (!preg_match('/^[djSFmMnYy\W]+$/', $format)) {
|
||||
throw new ComponentException(sprintf('"%s" is not a valid date format', $format));
|
||||
}
|
||||
|
||||
$this->format = $format;
|
||||
$this->sample = date($format, strtotime('2005-12-30'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isDateTime($this->format, (string) $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Respect\Validation\Helpers\CanValidateDateTime;
|
||||
|
||||
use function date;
|
||||
use function is_scalar;
|
||||
use function strtotime;
|
||||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class DateTime extends AbstractRule
|
||||
{
|
||||
use CanValidateDateTime;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $format;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sample;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*/
|
||||
public function __construct(?string $format = null)
|
||||
{
|
||||
$this->format = $format;
|
||||
$this->sample = date($format ?: 'c', strtotime('2005-12-30 01:02:03'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof DateTimeInterface) {
|
||||
return $this->format === null;
|
||||
}
|
||||
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->format === null) {
|
||||
return strtotime((string) $input) !== false;
|
||||
}
|
||||
|
||||
return $this->isDateTime($this->format, (string) $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_numeric;
|
||||
use function is_string;
|
||||
use function number_format;
|
||||
use function preg_replace;
|
||||
use function var_export;
|
||||
|
||||
/**
|
||||
* Validates the decimal
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Decimal extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $decimals;
|
||||
|
||||
public function __construct(int $decimals)
|
||||
{
|
||||
$this->decimals = $decimals;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_numeric($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->toFormattedString($input) === $this->toRawString($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function toRawString($input): string
|
||||
{
|
||||
if (is_string($input)) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
return var_export($input, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function toFormattedString($input): string
|
||||
{
|
||||
$formatted = number_format((float) $input, $this->decimals, '.', '');
|
||||
if (is_string($input)) {
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
return preg_replace('/^(\d+\.\d)0*$/', '$1', $formatted) ?: '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function ctype_digit;
|
||||
|
||||
/**
|
||||
* Validates whether the input contains only digits.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
final class Digit extends AbstractFilterRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateFilteredInput(string $input): bool
|
||||
{
|
||||
return ctype_digit($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Directory as NativeDirectory;
|
||||
use SplFileInfo;
|
||||
|
||||
use function is_dir;
|
||||
use function is_scalar;
|
||||
|
||||
/**
|
||||
* Validates if the given path is a directory.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Directory extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof SplFileInfo) {
|
||||
return $input->isDir();
|
||||
}
|
||||
|
||||
if ($input instanceof NativeDirectory) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_dir((string) $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\DomainException;
|
||||
use Respect\Validation\Exceptions\NestedValidationException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function array_merge;
|
||||
use function array_pop;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function iterator_to_array;
|
||||
use function mb_substr_count;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a valid domain name or not.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Mehmet Tolga Avcioglu <mehmet@activecom.net>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
* @author Róbert Nagy <vrnagy@gmail.com>
|
||||
*/
|
||||
final class Domain extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var Validatable
|
||||
*/
|
||||
private $genericRule;
|
||||
|
||||
/**
|
||||
* @var Validatable
|
||||
*/
|
||||
private $tldRule;
|
||||
|
||||
/**
|
||||
* @var Validatable
|
||||
*/
|
||||
private $partsRule;
|
||||
|
||||
public function __construct(bool $tldCheck = true)
|
||||
{
|
||||
$this->genericRule = $this->createGenericRule();
|
||||
$this->tldRule = $this->createTldRule($tldCheck);
|
||||
$this->partsRule = $this->createPartsRule();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
$exceptions = [];
|
||||
|
||||
$this->collectAssertException($exceptions, $this->genericRule, $input);
|
||||
$this->throwExceptions($exceptions, $input);
|
||||
|
||||
$parts = explode('.', (string) $input);
|
||||
if (count($parts) >= 2) {
|
||||
$this->collectAssertException($exceptions, $this->tldRule, array_pop($parts));
|
||||
}
|
||||
|
||||
foreach ($parts as $part) {
|
||||
$this->collectAssertException($exceptions, $this->partsRule, $part);
|
||||
}
|
||||
|
||||
$this->throwExceptions($exceptions, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
try {
|
||||
$this->assert($input);
|
||||
} catch (ValidationException $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
try {
|
||||
$this->assert($input);
|
||||
} catch (NestedValidationException $exception) {
|
||||
/** @var ValidationException $childException */
|
||||
foreach ($exception as $childException) {
|
||||
throw $childException;
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ValidationException[] $exceptions
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function collectAssertException(array &$exceptions, Validatable $validator, $input): void
|
||||
{
|
||||
try {
|
||||
$validator->assert($input);
|
||||
} catch (NestedValidationException $nestedValidationException) {
|
||||
$exceptions = array_merge(
|
||||
$exceptions,
|
||||
iterator_to_array($nestedValidationException)
|
||||
);
|
||||
} catch (ValidationException $validationException) {
|
||||
$exceptions[] = $validationException;
|
||||
}
|
||||
}
|
||||
|
||||
private function createGenericRule(): Validatable
|
||||
{
|
||||
return new AllOf(
|
||||
new StringType(),
|
||||
new NoWhitespace(),
|
||||
new Contains('.'),
|
||||
new Length(3)
|
||||
);
|
||||
}
|
||||
|
||||
private function createTldRule(bool $realTldCheck): Validatable
|
||||
{
|
||||
if ($realTldCheck) {
|
||||
return new Tld();
|
||||
}
|
||||
|
||||
return new AllOf(
|
||||
new Not(new StartsWith('-')),
|
||||
new NoWhitespace(),
|
||||
new Length(2)
|
||||
);
|
||||
}
|
||||
|
||||
private function createPartsRule(): Validatable
|
||||
{
|
||||
return new AllOf(
|
||||
new Alnum('-'),
|
||||
new Not(new StartsWith('-')),
|
||||
new AnyOf(
|
||||
new Not(new Contains('--')),
|
||||
new Callback(static function ($str) {
|
||||
return mb_substr_count($str, '--') == 1;
|
||||
})
|
||||
),
|
||||
new Not(new EndsWith('-'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ValidationException[] $exceptions
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function throwExceptions(array $exceptions, $input): void
|
||||
{
|
||||
if (count($exceptions)) {
|
||||
/** @var DomainException $domainException */
|
||||
$domainException = $this->reportError($input);
|
||||
$domainException->addChildren($exceptions);
|
||||
|
||||
throw $domainException;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\EachException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Helpers\CanValidateIterable;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
/**
|
||||
* Validates whether each value in the input is valid according to another rule.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Each extends AbstractRule
|
||||
{
|
||||
use CanValidateIterable;
|
||||
|
||||
/**
|
||||
* @var Validatable
|
||||
*/
|
||||
private $rule;
|
||||
|
||||
/**
|
||||
* Initializes the constructor.
|
||||
*/
|
||||
public function __construct(Validatable $rule)
|
||||
{
|
||||
$this->rule = $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
if (!$this->isIterable($input)) {
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
|
||||
$exceptions = [];
|
||||
foreach ($input as $value) {
|
||||
try {
|
||||
$this->rule->assert($value);
|
||||
} catch (ValidationException $exception) {
|
||||
$exceptions[] = $exception;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($exceptions)) {
|
||||
/** @var EachException $eachException */
|
||||
$eachException = $this->reportError($input);
|
||||
$eachException->addChildren($exceptions);
|
||||
|
||||
throw $eachException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
if (!$this->isIterable($input)) {
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
|
||||
foreach ($input as $value) {
|
||||
$this->rule->check($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
try {
|
||||
$this->check($input);
|
||||
} catch (ValidationException $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Egulias\EmailValidator\EmailValidator;
|
||||
use Egulias\EmailValidator\Validation\RFCValidation;
|
||||
|
||||
use function class_exists;
|
||||
use function filter_var;
|
||||
use function is_string;
|
||||
|
||||
use const FILTER_VALIDATE_EMAIL;
|
||||
|
||||
/**
|
||||
* Validates an email address.
|
||||
*
|
||||
* @author Andrey Kolyshkin <a.kolyshkin@semrush.com>
|
||||
* @author Eduardo Gulias Davis <me@egulias.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Paul Karikari <paulkarikari1@gmail.com>
|
||||
*/
|
||||
final class Email extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var EmailValidator|null
|
||||
*/
|
||||
private $validator;
|
||||
|
||||
/**
|
||||
* Initializes the rule assigning the EmailValidator instance.
|
||||
*
|
||||
* If the EmailValidator instance is not defined, tries to create one.
|
||||
*/
|
||||
public function __construct(?EmailValidator $validator = null)
|
||||
{
|
||||
$this->validator = $validator ?: $this->createEmailValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->validator !== null) {
|
||||
return $this->validator->isValid($input, new RFCValidation());
|
||||
}
|
||||
|
||||
return (bool) filter_var($input, FILTER_VALIDATE_EMAIL);
|
||||
}
|
||||
|
||||
private function createEmailValidator(): ?EmailValidator
|
||||
{
|
||||
if (class_exists(EmailValidator::class)) {
|
||||
return new EmailValidator();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function end;
|
||||
use function is_array;
|
||||
use function mb_strlen;
|
||||
use function mb_strripos;
|
||||
use function mb_strrpos;
|
||||
|
||||
/**
|
||||
* Validates only if the value is at the end of the input.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Hugo Hamon <hugo.hamon@sensiolabs.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class EndsWith extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $endValue;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $identical;
|
||||
|
||||
/**
|
||||
* @param mixed $endValue
|
||||
*/
|
||||
public function __construct($endValue, bool $identical = false)
|
||||
{
|
||||
$this->endValue = $endValue;
|
||||
$this->identical = $identical;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($this->identical) {
|
||||
return $this->validateIdentical($input);
|
||||
}
|
||||
|
||||
return $this->validateEquals($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function validateEquals($input): bool
|
||||
{
|
||||
if (is_array($input)) {
|
||||
return end($input) == $this->endValue;
|
||||
}
|
||||
|
||||
return mb_strripos($input, $this->endValue) === mb_strlen($input) - mb_strlen($this->endValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function validateIdentical($input): bool
|
||||
{
|
||||
if (is_array($input)) {
|
||||
return end($input) === $this->endValue;
|
||||
}
|
||||
|
||||
return mb_strrpos($input, $this->endValue) === mb_strlen($input) - mb_strlen($this->endValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates if the input is equal to some value.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Hugo Hamon <hugo.hamon@sensiolabs.com>
|
||||
*/
|
||||
final class Equals extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $compareTo;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param mixed $compareTo
|
||||
*/
|
||||
public function __construct($compareTo)
|
||||
{
|
||||
$this->compareTo = $compareTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return $input == $this->compareTo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_scalar;
|
||||
use function mb_strtoupper;
|
||||
|
||||
/**
|
||||
* Validates if the input is equivalent to some value.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Equivalent extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $compareTo;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param mixed $compareTo
|
||||
*/
|
||||
public function __construct($compareTo)
|
||||
{
|
||||
$this->compareTo = $compareTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (is_scalar($input)) {
|
||||
return $this->isStringEquivalent((string) $input);
|
||||
}
|
||||
|
||||
return $input == $this->compareTo;
|
||||
}
|
||||
|
||||
private function isStringEquivalent(string $input): bool
|
||||
{
|
||||
if (!is_scalar($this->compareTo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mb_strtoupper((string) $input) === mb_strtoupper((string) $this->compareTo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function filter_var;
|
||||
|
||||
use const FILTER_VALIDATE_INT;
|
||||
|
||||
/**
|
||||
* Validates whether the input is an even number or not.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jean Pimentel <jeanfap@gmail.com>
|
||||
* @author Paul Karikari <paulkarikari1@gmail.com>
|
||||
*/
|
||||
final class Even extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (filter_var($input, FILTER_VALIDATE_INT) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (int) $input % 2 === 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use SplFileInfo;
|
||||
|
||||
use function is_executable;
|
||||
use function is_scalar;
|
||||
|
||||
/**
|
||||
* Validates if a file is an executable.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Executable extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof SplFileInfo) {
|
||||
return $input->isExecutable();
|
||||
}
|
||||
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_executable((string) $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use SplFileInfo;
|
||||
|
||||
use function file_exists;
|
||||
use function is_string;
|
||||
|
||||
/**
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author William Espindola <oi@williamespindola.com.br>
|
||||
*/
|
||||
final class Exists extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof SplFileInfo) {
|
||||
$input = $input->getPathname();
|
||||
}
|
||||
|
||||
return is_string($input) && file_exists($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use SplFileInfo;
|
||||
|
||||
use function is_string;
|
||||
use function pathinfo;
|
||||
|
||||
use const PATHINFO_EXTENSION;
|
||||
|
||||
/**
|
||||
* Validate file extensions.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Extension extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $extension;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*/
|
||||
public function __construct(string $extension)
|
||||
{
|
||||
$this->extension = $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof SplFileInfo) {
|
||||
return $this->extension === $input->getExtension();
|
||||
}
|
||||
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->extension === pathinfo($input, PATHINFO_EXTENSION);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function abs;
|
||||
use function is_integer;
|
||||
use function is_numeric;
|
||||
|
||||
/**
|
||||
* Validates if the input is a factor of the defined dividend.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author David Meister <thedavidmeister@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Factor extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $dividend;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*/
|
||||
public function __construct(int $dividend)
|
||||
{
|
||||
$this->dividend = $dividend;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
// Every integer is a factor of zero, and zero is the only integer that
|
||||
// has zero for a factor.
|
||||
if ($this->dividend === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factors must be integers that are not zero.
|
||||
if (!is_numeric($input) || (int) $input != $input || $input == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$input = (int) abs((int) $input);
|
||||
$dividend = (int) abs($this->dividend);
|
||||
|
||||
// The dividend divided by the input must be an integer if input is a
|
||||
// factor of the dividend.
|
||||
return is_integer($dividend / $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function filter_var;
|
||||
|
||||
use const FILTER_NULL_ON_FAILURE;
|
||||
use const FILTER_VALIDATE_BOOLEAN;
|
||||
|
||||
/**
|
||||
* Validates if a value is considered as false.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class FalseVal extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_numeric;
|
||||
|
||||
/**
|
||||
* Validates whether the input follows the Fibonacci integer sequence.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Samuel Heinzmann <samuel.heinzmann@swisscom.com>
|
||||
*/
|
||||
final class Fibonacci extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_numeric($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sequence = [0, 1];
|
||||
$position = 1;
|
||||
while ($input > $sequence[$position]) {
|
||||
++$position;
|
||||
$sequence[$position] = $sequence[$position - 1] + $sequence[$position - 2];
|
||||
}
|
||||
|
||||
return $sequence[$position] === (int) $input;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use SplFileInfo;
|
||||
|
||||
use function is_file;
|
||||
use function is_string;
|
||||
|
||||
/**
|
||||
* Validates whether file input is as a regular filename.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class File extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof SplFileInfo) {
|
||||
return $input->isFile();
|
||||
}
|
||||
|
||||
return is_string($input) && is_file($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function array_key_exists;
|
||||
use function filter_var;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
|
||||
use const FILTER_VALIDATE_BOOLEAN;
|
||||
use const FILTER_VALIDATE_DOMAIN;
|
||||
use const FILTER_VALIDATE_EMAIL;
|
||||
use const FILTER_VALIDATE_FLOAT;
|
||||
use const FILTER_VALIDATE_INT;
|
||||
use const FILTER_VALIDATE_IP;
|
||||
use const FILTER_VALIDATE_REGEXP;
|
||||
use const FILTER_VALIDATE_URL;
|
||||
|
||||
/**
|
||||
* Validates the input with the PHP's filter_var() function.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class FilterVar extends AbstractEnvelope
|
||||
{
|
||||
private const ALLOWED_FILTERS = [
|
||||
FILTER_VALIDATE_BOOLEAN => 'is_bool',
|
||||
FILTER_VALIDATE_DOMAIN => 'is_string',
|
||||
FILTER_VALIDATE_EMAIL => 'is_string',
|
||||
FILTER_VALIDATE_FLOAT => 'is_float',
|
||||
FILTER_VALIDATE_INT => 'is_int',
|
||||
FILTER_VALIDATE_IP => 'is_string',
|
||||
FILTER_VALIDATE_REGEXP => 'is_string',
|
||||
FILTER_VALIDATE_URL => 'is_string',
|
||||
];
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param mixed $options
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function __construct(int $filter, $options = [])
|
||||
{
|
||||
if (!array_key_exists($filter, self::ALLOWED_FILTERS)) {
|
||||
throw new ComponentException('Cannot accept the given filter');
|
||||
}
|
||||
|
||||
$arguments = [$filter];
|
||||
if (is_array($options) || is_int($options)) {
|
||||
$arguments[] = $options;
|
||||
}
|
||||
|
||||
parent::__construct(new Callback(static function ($input) use ($filter, $arguments) {
|
||||
return (self::ALLOWED_FILTERS[$filter])(
|
||||
filter_var($input, ...$arguments)
|
||||
);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_finite;
|
||||
use function is_numeric;
|
||||
|
||||
/**
|
||||
* Validates if the input is a finite number.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Finite extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_numeric($input) && is_finite((float) $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_float;
|
||||
|
||||
/**
|
||||
* Validates whether the type of the input is float.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Reginaldo Junior <76regi@gmail.com>
|
||||
*/
|
||||
final class FloatType extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_float($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function filter_var;
|
||||
use function is_float;
|
||||
|
||||
use const FILTER_VALIDATE_FLOAT;
|
||||
|
||||
/**
|
||||
* Validate whether the input value is float.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jayson Reis <santosdosreis@gmail.com>
|
||||
*/
|
||||
final class FloatVal extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_float(filter_var($input, FILTER_VALIDATE_FLOAT));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function ctype_graph;
|
||||
|
||||
/**
|
||||
* Validates if all characters in the input are printable and actually creates visible output (no white space).
|
||||
*
|
||||
* @author Andre Ramaciotti <andre@ramaciotti.com>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
final class Graph extends AbstractFilterRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateFilteredInput(string $input): bool
|
||||
{
|
||||
return ctype_graph($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates whether the input is less than a value.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class GreaterThan extends AbstractComparison
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function compare($left, $right): bool
|
||||
{
|
||||
return $left > $right;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates weather the input is a hex RGB color or not.
|
||||
*
|
||||
* @author Davide Pastore <pasdavide@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class HexRgbColor extends AbstractEnvelope
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(new Regex('/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function bcmod;
|
||||
use function is_string;
|
||||
use function ord;
|
||||
use function preg_match;
|
||||
use function preg_replace_callback;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function strval;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a valid IBAN (International Bank Account Number) or not.
|
||||
*
|
||||
* @author Mazen Touati <mazen_touati@hotmail.com>
|
||||
*/
|
||||
final class Iban extends AbstractRule
|
||||
{
|
||||
private const COUNTRIES_LENGTHS = [
|
||||
'AL' => 28,
|
||||
'AD' => 24,
|
||||
'AT' => 20,
|
||||
'AZ' => 28,
|
||||
'BH' => 22,
|
||||
'BE' => 16,
|
||||
'BA' => 20,
|
||||
'BR' => 29,
|
||||
'BG' => 22,
|
||||
'CR' => 21,
|
||||
'HR' => 21,
|
||||
'CY' => 28,
|
||||
'CZ' => 24,
|
||||
'DK' => 18,
|
||||
'DO' => 28,
|
||||
'EE' => 20,
|
||||
'FO' => 18,
|
||||
'FI' => 18,
|
||||
'FR' => 27,
|
||||
'GE' => 22,
|
||||
'DE' => 22,
|
||||
'GI' => 23,
|
||||
'GR' => 27,
|
||||
'GL' => 18,
|
||||
'GT' => 28,
|
||||
'HU' => 28,
|
||||
'IS' => 26,
|
||||
'IE' => 22,
|
||||
'IL' => 23,
|
||||
'IT' => 27,
|
||||
'JO' => 30,
|
||||
'KZ' => 20,
|
||||
'KW' => 30,
|
||||
'LV' => 21,
|
||||
'LB' => 28,
|
||||
'LI' => 21,
|
||||
'LT' => 20,
|
||||
'LU' => 20,
|
||||
'MK' => 19,
|
||||
'MT' => 31,
|
||||
'MR' => 27,
|
||||
'MU' => 30,
|
||||
'MD' => 24,
|
||||
'MC' => 27,
|
||||
'ME' => 22,
|
||||
'NL' => 18,
|
||||
'NO' => 15,
|
||||
'PK' => 24,
|
||||
'PL' => 28,
|
||||
'PS' => 29,
|
||||
'PT' => 25,
|
||||
'QA' => 29,
|
||||
'XK' => 20,
|
||||
'RO' => 24,
|
||||
'LC' => 32,
|
||||
'SM' => 27,
|
||||
'ST' => 25,
|
||||
'SA' => 24,
|
||||
'RS' => 22,
|
||||
'SC' => 31,
|
||||
'SK' => 24,
|
||||
'SI' => 19,
|
||||
'ES' => 24,
|
||||
'SE' => 24,
|
||||
'CH' => 21,
|
||||
'TL' => 23,
|
||||
'TN' => 24,
|
||||
'TR' => 26,
|
||||
'UA' => 29,
|
||||
'AE' => 23,
|
||||
'GB' => 22,
|
||||
'VG' => 24,
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$iban = str_replace(' ', '', $input);
|
||||
if (!preg_match('/[A-Z0-9]{15,34}/', $iban)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$countryCode = substr($iban, 0, 2);
|
||||
if (!$this->hasValidCountryLength($iban, $countryCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$checkDigits = substr($iban, 2, 2);
|
||||
$bban = substr($iban, 4);
|
||||
$rearranged = $bban . $countryCode . $checkDigits;
|
||||
|
||||
return bcmod($this->convertToIntegerAsString($rearranged), '97') === '1';
|
||||
}
|
||||
|
||||
private function hasValidCountryLength(string $iban, string $countryCode): bool
|
||||
{
|
||||
if (!isset(self::COUNTRIES_LENGTHS[$countryCode])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strlen($iban) === self::COUNTRIES_LENGTHS[$countryCode];
|
||||
}
|
||||
|
||||
private function convertToIntegerAsString(string $reArrangedIban): string
|
||||
{
|
||||
return (string) preg_replace_callback(
|
||||
'/[A-Z]/',
|
||||
static function (array $match): string {
|
||||
return strval(ord($match[0]) - 55);
|
||||
},
|
||||
$reArrangedIban
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates if the input is identical to some value.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Identical extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $compareTo;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param mixed $compareTo
|
||||
*/
|
||||
public function __construct($compareTo)
|
||||
{
|
||||
$this->compareTo = $compareTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return $input === $this->compareTo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use finfo;
|
||||
use SplFileInfo;
|
||||
|
||||
use function is_file;
|
||||
use function is_string;
|
||||
use function mb_strpos;
|
||||
|
||||
use const FILEINFO_MIME_TYPE;
|
||||
|
||||
/**
|
||||
* Validates if the file is a valid image by checking its MIME type.
|
||||
*
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Guilherme Siani <guilherme@siani.com.br>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Image extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var finfo
|
||||
*/
|
||||
private $fileInfo;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*/
|
||||
public function __construct(?finfo $fileInfo = null)
|
||||
{
|
||||
$this->fileInfo = $fileInfo ?: new finfo(FILEINFO_MIME_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof SplFileInfo) {
|
||||
return $this->validate($input->getPathname());
|
||||
}
|
||||
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_file($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mb_strpos((string) $this->fileInfo->file($input), 'image/') === 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_scalar;
|
||||
use function mb_strlen;
|
||||
use function preg_replace;
|
||||
|
||||
/**
|
||||
* Validates is the input is a valid IMEI.
|
||||
*
|
||||
* @author Alexander Gorshkov <mazanax@yandex.ru>
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Diego Oliveira <contato@diegoholiveira.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Imei extends AbstractRule
|
||||
{
|
||||
private const IMEI_SIZE = 15;
|
||||
|
||||
/**
|
||||
* @see https://en.wikipedia.org/wiki/International_Mobile_Station_Equipment_Identity
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$numbers = (string) preg_replace('/\D/', '', (string) $input);
|
||||
if (mb_strlen($numbers) != self::IMEI_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (new Luhn())->validate($numbers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function mb_stripos;
|
||||
use function mb_strpos;
|
||||
|
||||
/**
|
||||
* Validates if the input can be found in a defined array or string.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class In extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|mixed
|
||||
*/
|
||||
private $haystack;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $compareIdentical;
|
||||
|
||||
/**
|
||||
* Initializes the rule with the haystack and optionally compareIdentical flag.
|
||||
*
|
||||
* @param mixed[]|mixed $haystack
|
||||
*/
|
||||
public function __construct($haystack, bool $compareIdentical = false)
|
||||
{
|
||||
$this->haystack = $haystack;
|
||||
$this->compareIdentical = $compareIdentical;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($this->compareIdentical) {
|
||||
return $this->validateIdentical($input);
|
||||
}
|
||||
|
||||
return $this->validateEquals($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function validateEquals($input): bool
|
||||
{
|
||||
if (is_array($this->haystack)) {
|
||||
return in_array($input, $this->haystack);
|
||||
}
|
||||
|
||||
if ($input === null || $input === '') {
|
||||
return $input == $this->haystack;
|
||||
}
|
||||
|
||||
return mb_stripos($this->haystack, (string) $input) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function validateIdentical($input): bool
|
||||
{
|
||||
if (is_array($this->haystack)) {
|
||||
return in_array($input, $this->haystack, true);
|
||||
}
|
||||
|
||||
if ($input === null || $input === '') {
|
||||
return $input === $this->haystack;
|
||||
}
|
||||
|
||||
return mb_strpos($this->haystack, (string) $input) !== false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_infinite;
|
||||
use function is_numeric;
|
||||
|
||||
/**
|
||||
* Validates if the input is an infinite number
|
||||
*
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Infinite extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_numeric($input) && is_infinite((float) $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates if the input is an instance of the given class or interface.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Instance extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $instanceName;
|
||||
|
||||
/**
|
||||
* Initializes the rule with the expected instance name.
|
||||
*/
|
||||
public function __construct(string $instanceName)
|
||||
{
|
||||
$this->instanceName = $instanceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return $input instanceof $this->instanceName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_int;
|
||||
|
||||
/**
|
||||
* Validates whether the type of the input is integer.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class IntType extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return is_int($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
|
||||
/**
|
||||
* Validates if the input is an integer.
|
||||
*
|
||||
* @author Adam Benson <adam.benson@bigcommerce.com>
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Andrei Drulchenko <andrdru@gmail.com>
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class IntVal extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (is_int($input)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match('/^-?\d+$/', $input) === 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function bccomp;
|
||||
use function explode;
|
||||
use function filter_var;
|
||||
use function ip2long;
|
||||
use function is_string;
|
||||
use function long2ip;
|
||||
use function mb_strpos;
|
||||
use function mb_substr_count;
|
||||
use function sprintf;
|
||||
use function str_repeat;
|
||||
use function str_replace;
|
||||
use function strtr;
|
||||
|
||||
use const FILTER_VALIDATE_IP;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a valid IP address.
|
||||
*
|
||||
* This validator uses the native filter_var() PHP function.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
|
||||
*/
|
||||
final class Ip extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $range;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $startAddress;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $endAddress;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $mask;
|
||||
|
||||
/**
|
||||
* Initializes the rule defining the range and some options for filter_var().
|
||||
*
|
||||
* @throws ComponentException In case the range is invalid
|
||||
*/
|
||||
public function __construct(string $range = '*', ?int $options = null)
|
||||
{
|
||||
$this->parseRange($range);
|
||||
$this->range = $this->createRange();
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->verifyAddress($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->mask) {
|
||||
return $this->belongsToSubnet($input);
|
||||
}
|
||||
|
||||
if ($this->startAddress && $this->endAddress) {
|
||||
return $this->verifyNetwork($input);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function createRange(): ?string
|
||||
{
|
||||
if ($this->startAddress && $this->endAddress) {
|
||||
return $this->startAddress . '-' . $this->endAddress;
|
||||
}
|
||||
|
||||
if ($this->startAddress && $this->mask) {
|
||||
return $this->startAddress . '/' . long2ip((int) $this->mask);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function parseRange(string $input): void
|
||||
{
|
||||
if ($input == '*' || $input == '*.*.*.*' || $input == '0.0.0.0-255.255.255.255') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mb_strpos($input, '-') !== false) {
|
||||
[$this->startAddress, $this->endAddress] = explode('-', $input);
|
||||
|
||||
if ($this->startAddress !== null && !$this->verifyAddress($this->startAddress)) {
|
||||
throw new ComponentException('Invalid network range');
|
||||
}
|
||||
|
||||
if ($this->endAddress !== null && !$this->verifyAddress($this->endAddress)) {
|
||||
throw new ComponentException('Invalid network range');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (mb_strpos($input, '*') !== false) {
|
||||
$this->parseRangeUsingWildcards($input);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (mb_strpos($input, '/') !== false) {
|
||||
$this->parseRangeUsingCidr($input);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ComponentException('Invalid network range');
|
||||
}
|
||||
|
||||
private function fillAddress(string $address, string $fill = '*'): string
|
||||
{
|
||||
return $address . str_repeat('.' . $fill, 3 - mb_substr_count($address, '.'));
|
||||
}
|
||||
|
||||
private function parseRangeUsingWildcards(string $input): void
|
||||
{
|
||||
$address = $this->fillAddress($input);
|
||||
|
||||
$this->startAddress = strtr($address, '*', '0');
|
||||
$this->endAddress = str_replace('*', '255', $address);
|
||||
}
|
||||
|
||||
private function parseRangeUsingCidr(string $input): void
|
||||
{
|
||||
$parts = explode('/', $input);
|
||||
|
||||
$this->startAddress = $this->fillAddress($parts[0], '0');
|
||||
$isAddressMask = mb_strpos($parts[1], '.') !== false;
|
||||
|
||||
if ($isAddressMask && $this->verifyAddress($parts[1])) {
|
||||
$this->mask = sprintf('%032b', ip2long($parts[1]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($isAddressMask || $parts[1] < 8 || $parts[1] > 30) {
|
||||
throw new ComponentException('Invalid network mask');
|
||||
}
|
||||
|
||||
$this->mask = sprintf('%032b', ip2long((string) long2ip(~(2 ** (32 - (int) $parts[1]) - 1))));
|
||||
}
|
||||
|
||||
private function verifyAddress(string $address): bool
|
||||
{
|
||||
return filter_var($address, FILTER_VALIDATE_IP, ['flags' => $this->options]) !== false;
|
||||
}
|
||||
|
||||
private function verifyNetwork(string $input): bool
|
||||
{
|
||||
$input = sprintf('%u', ip2long($input));
|
||||
|
||||
return $this->startAddress !== null
|
||||
&& $this->endAddress !== null
|
||||
&& bccomp($input, sprintf('%u', ip2long($this->startAddress))) >= 0
|
||||
&& bccomp($input, sprintf('%u', ip2long($this->endAddress))) <= 0;
|
||||
}
|
||||
|
||||
private function belongsToSubnet(string $input): bool
|
||||
{
|
||||
if ($this->mask === null || $this->startAddress === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$min = sprintf('%032b', ip2long($this->startAddress));
|
||||
$input = sprintf('%032b', ip2long($input));
|
||||
|
||||
return ($input & $this->mask) === ($min & $this->mask);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function implode;
|
||||
use function is_scalar;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a valid ISBN (International Standard Book Number) or not.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Moritz Fromm <moritzgitfromm@gmail.com>
|
||||
*/
|
||||
final class Isbn extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @see https://howtodoinjava.com/regex/java-regex-validate-international-standard-book-number-isbns
|
||||
*/
|
||||
private const PIECES = [
|
||||
'^(?:ISBN(?:-1[03])?:? )?(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})',
|
||||
'[- 0-9X]{13}$|97[89][0-9]{10}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)',
|
||||
'(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match(sprintf('/%s/', implode(self::PIECES)), (string) $input) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Helpers\CanValidateIterable;
|
||||
|
||||
/**
|
||||
* Validates whether the pseudo-type of the input is iterable or not.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class IterableType extends AbstractRule
|
||||
{
|
||||
use CanValidateIterable;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return $this->isIterable($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function function_exists;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function json_last_error;
|
||||
|
||||
use const JSON_ERROR_NONE;
|
||||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Json extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_string($input) || $input === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (function_exists('json_validate')) {
|
||||
return json_validate($input);
|
||||
}
|
||||
|
||||
json_decode($input);
|
||||
|
||||
return json_last_error() === JSON_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function array_key_exists;
|
||||
use function is_array;
|
||||
use function is_scalar;
|
||||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Key extends AbstractRelated
|
||||
{
|
||||
/**
|
||||
* @param mixed $reference
|
||||
*/
|
||||
public function __construct($reference, ?Validatable $rule = null, bool $mandatory = true)
|
||||
{
|
||||
if (!is_scalar($reference) || $reference === '') {
|
||||
throw new ComponentException('Invalid array key name');
|
||||
}
|
||||
|
||||
parent::__construct($reference, $rule, $mandatory);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReferenceValue($input)
|
||||
{
|
||||
return $input[$this->getReference()];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasReference($input): bool
|
||||
{
|
||||
return is_array($input) && array_key_exists($this->getReference(), $input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use ArrayAccess;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_shift;
|
||||
use function explode;
|
||||
use function is_array;
|
||||
use function is_null;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function property_exists;
|
||||
use function rtrim;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Ivan Zinovyev <vanyazin@gmail.com>
|
||||
*/
|
||||
final class KeyNested extends AbstractRelated
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasReference($input): bool
|
||||
{
|
||||
try {
|
||||
$this->getReferenceValue($input);
|
||||
} catch (ComponentException $cex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReferenceValue($input)
|
||||
{
|
||||
if (is_scalar($input)) {
|
||||
$message = sprintf('Cannot select the %s in the given data', $this->getReference());
|
||||
throw new ComponentException($message);
|
||||
}
|
||||
|
||||
$keys = $this->getReferencePieces();
|
||||
$value = $input;
|
||||
while (!is_null($key = array_shift($keys))) {
|
||||
$value = $this->getValue($value, $key);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getReferencePieces(): array
|
||||
{
|
||||
return explode('.', rtrim((string) $this->getReference(), '.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $array
|
||||
* @param mixed $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getValueFromArray(array $array, $key)
|
||||
{
|
||||
if (!array_key_exists($key, $array)) {
|
||||
$message = sprintf('Cannot select the key %s from the given array', $this->getReference());
|
||||
throw new ComponentException($message);
|
||||
}
|
||||
|
||||
return $array[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayAccess<mixed, mixed> $array
|
||||
* @param mixed $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getValueFromArrayAccess(ArrayAccess $array, $key)
|
||||
{
|
||||
if (!$array->offsetExists($key)) {
|
||||
$message = sprintf('Cannot select the key %s from the given array', $this->getReference());
|
||||
throw new ComponentException($message);
|
||||
}
|
||||
|
||||
return $array->offsetGet($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint
|
||||
*
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getValueFromObject(object $object, string $property)
|
||||
{
|
||||
if (empty($property) || !property_exists($object, $property)) {
|
||||
$message = sprintf('Cannot select the property %s from the given object', $this->getReference());
|
||||
throw new ComponentException($message);
|
||||
}
|
||||
|
||||
return $object->{$property};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param mixed $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getValue($value, $key)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return $this->getValueFromArray($value, $key);
|
||||
}
|
||||
|
||||
if ($value instanceof ArrayAccess) {
|
||||
return $this->getValueFromArrayAccess($value, $key);
|
||||
}
|
||||
|
||||
if (is_object($value)) {
|
||||
return $this->getValueFromObject($value, $key);
|
||||
}
|
||||
|
||||
$message = sprintf('Cannot select the property %s from the given data', $this->getReference());
|
||||
throw new ComponentException($message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\NonNegatable;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function current;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Validates a keys in a defined structure.
|
||||
*
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class KeySet extends AbstractWrapper implements NonNegatable
|
||||
{
|
||||
/**
|
||||
* @var mixed[]
|
||||
*/
|
||||
private $keys;
|
||||
|
||||
/**
|
||||
* @var mixed[]
|
||||
*/
|
||||
private $extraKeys = [];
|
||||
|
||||
/**
|
||||
* @var Key[]
|
||||
*/
|
||||
private $keyRules;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.UselessAnnotation
|
||||
* @param Validatable ...$validatables
|
||||
*/
|
||||
public function __construct(Validatable ...$validatables)
|
||||
{
|
||||
$this->keyRules = array_map([$this, 'getKeyRule'], $validatables);
|
||||
$this->keys = array_map([$this, 'getKeyReference'], $this->keyRules);
|
||||
|
||||
parent::__construct(new AllOf(...$this->keyRules));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
if (!$this->hasValidStructure($input)) {
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
|
||||
parent::assert($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
if (!$this->hasValidStructure($input)) {
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
|
||||
parent::check($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!$this->hasValidStructure($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::validate($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ComponentException
|
||||
*/
|
||||
private function getKeyRule(Validatable $validatable): Key
|
||||
{
|
||||
if ($validatable instanceof Key) {
|
||||
return $validatable;
|
||||
}
|
||||
|
||||
if (!$validatable instanceof AllOf || count($validatable->getRules()) !== 1) {
|
||||
throw new ComponentException('KeySet rule accepts only Key rules');
|
||||
}
|
||||
|
||||
return $this->getKeyRule(current($validatable->getRules()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function getKeyReference(Key $rule)
|
||||
{
|
||||
return $rule->getReference();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function hasValidStructure($input): bool
|
||||
{
|
||||
if (!is_array($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->keyRules as $keyRule) {
|
||||
if (!array_key_exists($keyRule->getReference(), $input) && $keyRule->isMandatory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unset($input[$keyRule->getReference()]);
|
||||
}
|
||||
|
||||
foreach ($input as $extraKey => &$ignoreValue) {
|
||||
$this->extraKeys[] = $extraKey;
|
||||
}
|
||||
|
||||
return count($input) == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Factory;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function array_keys;
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class KeyValue extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var int|string
|
||||
*/
|
||||
private $comparedKey;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $ruleName;
|
||||
|
||||
/**
|
||||
* @var int|string
|
||||
*/
|
||||
private $baseKey;
|
||||
|
||||
/**
|
||||
* @param int|string $comparedKey
|
||||
* @param int|string $baseKey
|
||||
*/
|
||||
public function __construct($comparedKey, string $ruleName, $baseKey)
|
||||
{
|
||||
$this->comparedKey = $comparedKey;
|
||||
$this->ruleName = $ruleName;
|
||||
$this->baseKey = $baseKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function assert($input): void
|
||||
{
|
||||
$rule = $this->getRule($input);
|
||||
|
||||
try {
|
||||
$rule->assert($input[$this->comparedKey]);
|
||||
} catch (ValidationException $exception) {
|
||||
throw $this->overwriteExceptionParams($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
$rule = $this->getRule($input);
|
||||
|
||||
try {
|
||||
$rule->check($input[$this->comparedKey]);
|
||||
} catch (ValidationException $exception) {
|
||||
throw $this->overwriteExceptionParams($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
try {
|
||||
$rule = $this->getRule($input);
|
||||
} catch (ValidationException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $rule->validate($input[$this->comparedKey]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function reportError($input, array $extraParams = []): ValidationException
|
||||
{
|
||||
try {
|
||||
return $this->overwriteExceptionParams($this->getRule($input)->reportError($input));
|
||||
} catch (ValidationException $exception) {
|
||||
return $this->overwriteExceptionParams($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function getRule($input): Validatable
|
||||
{
|
||||
if (!isset($input[$this->comparedKey])) {
|
||||
throw parent::reportError($this->comparedKey);
|
||||
}
|
||||
|
||||
if (!isset($input[$this->baseKey])) {
|
||||
throw parent::reportError($this->baseKey);
|
||||
}
|
||||
|
||||
try {
|
||||
$rule = Factory::getDefaultInstance()->rule($this->ruleName, [$input[$this->baseKey]]);
|
||||
$rule->setName((string) $this->comparedKey);
|
||||
} catch (ComponentException $exception) {
|
||||
throw parent::reportError($input, ['component' => true]);
|
||||
}
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
private function overwriteExceptionParams(ValidationException $exception): ValidationException
|
||||
{
|
||||
$params = [];
|
||||
foreach (array_keys($exception->getParams()) as $key) {
|
||||
if (in_array($key, ['template', 'translator'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$params[$key] = $this->baseKey;
|
||||
}
|
||||
$params['name'] = $this->comparedKey;
|
||||
|
||||
$exception->updateParams($params);
|
||||
|
||||
return $exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,549 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function array_column;
|
||||
use function array_filter;
|
||||
use function array_search;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Validates whether the input is language code based on ISO 639.
|
||||
*
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class LanguageCode extends AbstractEnvelope
|
||||
{
|
||||
public const ALPHA2 = 'alpha-2';
|
||||
public const ALPHA3 = 'alpha-3';
|
||||
|
||||
public const AVAILABLE_SETS = [self::ALPHA2, self::ALPHA3];
|
||||
|
||||
/**
|
||||
* @see http://www.loc.gov/standards/iso639-2/ISO-639-2_utf-8.txt
|
||||
*/
|
||||
public const LANGUAGE_CODES = [
|
||||
// phpcs:disable Squiz.PHP.CommentedOutCode.Found
|
||||
['aa', 'aar'], // Afar
|
||||
['ab', 'abk'], // Abkhazian
|
||||
['', 'ace'], // Achinese
|
||||
['', 'ach'], // Acoli
|
||||
['', 'ada'], // Adangme
|
||||
['', 'ady'], // Adyghe; Adygei
|
||||
['', 'afa'], // Afro-Asiatic languages
|
||||
['', 'afh'], // Afrihili
|
||||
['af', 'afr'], // Afrikaans
|
||||
['', 'ain'], // Ainu
|
||||
['ak', 'aka'], // Akan
|
||||
['', 'akk'], // Akkadian
|
||||
['sq', 'alb'], // Albanian
|
||||
['', 'ale'], // Aleut
|
||||
['', 'alg'], // Algonquian languages
|
||||
['', 'alt'], // Southern Altai
|
||||
['am', 'amh'], // Amharic
|
||||
['', 'ang'], // English, Old (ca.450-1100)
|
||||
['', 'anp'], // Angika
|
||||
['', 'apa'], // Apache languages
|
||||
['ar', 'ara'], // Arabic
|
||||
['', 'arc'], // Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)
|
||||
['an', 'arg'], // Aragonese
|
||||
['hy', 'arm'], // Armenian
|
||||
['', 'arn'], // Mapudungun; Mapuche
|
||||
['', 'arp'], // Arapaho
|
||||
['', 'art'], // Artificial languages
|
||||
['', 'arw'], // Arawak
|
||||
['as', 'asm'], // Assamese
|
||||
['', 'ast'], // Asturian; Bable; Leonese; Asturleonese
|
||||
['', 'ath'], // Athapascan languages
|
||||
['', 'aus'], // Australian languages
|
||||
['av', 'ava'], // Avaric
|
||||
['ae', 'ave'], // Avestan
|
||||
['', 'awa'], // Awadhi
|
||||
['ay', 'aym'], // Aymara
|
||||
['az', 'aze'], // Azerbaijani
|
||||
['', 'bad'], // Banda languages
|
||||
['', 'bai'], // Bamileke languages
|
||||
['ba', 'bak'], // Bashkir
|
||||
['', 'bal'], // Baluchi
|
||||
['bm', 'bam'], // Bambara
|
||||
['', 'ban'], // Balinese
|
||||
['eu', 'baq'], // Basque
|
||||
['', 'bas'], // Basa
|
||||
['', 'bat'], // Baltic languages
|
||||
['', 'bej'], // Beja; Bedawiyet
|
||||
['be', 'bel'], // Belarusian
|
||||
['', 'bem'], // Bemba
|
||||
['bn', 'ben'], // Bengali
|
||||
['', 'ber'], // Berber languages
|
||||
['', 'bho'], // Bhojpuri
|
||||
['bh', 'bih'], // Bihari languages
|
||||
['', 'bik'], // Bikol
|
||||
['', 'bin'], // Bini; Edo
|
||||
['bi', 'bis'], // Bislama
|
||||
['', 'bla'], // Siksika
|
||||
['', 'bnt'], // Bantu languages
|
||||
['bs', 'bos'], // Bosnian
|
||||
['', 'bra'], // Braj
|
||||
['br', 'bre'], // Breton
|
||||
['', 'btk'], // Batak languages
|
||||
['', 'bua'], // Buriat
|
||||
['', 'bug'], // Buginese
|
||||
['bg', 'bul'], // Bulgarian
|
||||
['my', 'bur'], // Burmese
|
||||
['', 'byn'], // Blin; Bilin
|
||||
['', 'cad'], // Caddo
|
||||
['', 'cai'], // Central American Indian languages
|
||||
['', 'car'], // Galibi Carib
|
||||
['ca', 'cat'], // Catalan; Valencian
|
||||
['', 'cau'], // Caucasian languages
|
||||
['', 'ceb'], // Cebuano
|
||||
['', 'cel'], // Celtic languages
|
||||
['ch', 'cha'], // Chamorro
|
||||
['', 'chb'], // Chibcha
|
||||
['ce', 'che'], // Chechen
|
||||
['', 'chg'], // Chagatai
|
||||
['zh', 'chi'], // Chinese
|
||||
['', 'chk'], // Chuukese
|
||||
['', 'chm'], // Mari
|
||||
['', 'chn'], // Chinook jargon
|
||||
['', 'cho'], // Choctaw
|
||||
['', 'chp'], // Chipewyan; Dene Suline
|
||||
['', 'chr'], // Cherokee
|
||||
['cu', 'chu'], // Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic
|
||||
['cv', 'chv'], // Chuvash
|
||||
['', 'chy'], // Cheyenne
|
||||
['', 'cmc'], // Chamic languages
|
||||
['', 'cnr'], // Montenegrin
|
||||
['', 'cop'], // Coptic
|
||||
['kw', 'cor'], // Cornish
|
||||
['co', 'cos'], // Corsican
|
||||
['', 'cpe'], // Creoles and pidgins, English based
|
||||
['', 'cpf'], // Creoles and pidgins, French-based
|
||||
['', 'cpp'], // Creoles and pidgins, Portuguese-based
|
||||
['cr', 'cre'], // Cree
|
||||
['', 'crh'], // Crimean Tatar; Crimean Turkish
|
||||
['', 'crp'], // Creoles and pidgins
|
||||
['', 'csb'], // Kashubian
|
||||
['', 'cus'], // Cushitic languages
|
||||
['cs', 'cze'], // Czech
|
||||
['', 'dak'], // Dakota
|
||||
['da', 'dan'], // Danish
|
||||
['', 'dar'], // Dargwa
|
||||
['', 'day'], // Land Dayak languages
|
||||
['', 'del'], // Delaware
|
||||
['', 'den'], // Slave (Athapascan)
|
||||
['', 'dgr'], // Dogrib
|
||||
['', 'din'], // Dinka
|
||||
['dv', 'div'], // Divehi; Dhivehi; Maldivian
|
||||
['', 'doi'], // Dogri
|
||||
['', 'dra'], // Dravidian languages
|
||||
['', 'dsb'], // Lower Sorbian
|
||||
['', 'dua'], // Duala
|
||||
['', 'dum'], // Dutch, Middle (ca.1050-1350)
|
||||
['nl', 'dut'], // Dutch; Flemish
|
||||
['', 'dyu'], // Dyula
|
||||
['dz', 'dzo'], // Dzongkha
|
||||
['', 'efi'], // Efik
|
||||
['', 'egy'], // Egyptian (Ancient)
|
||||
['', 'eka'], // Ekajuk
|
||||
['', 'elx'], // Elamite
|
||||
['en', 'eng'], // English
|
||||
['', 'enm'], // English, Middle (1100-1500)
|
||||
['eo', 'epo'], // Esperanto
|
||||
['et', 'est'], // Estonian
|
||||
['ee', 'ewe'], // Ewe
|
||||
['', 'ewo'], // Ewondo
|
||||
['', 'fan'], // Fang
|
||||
['fo', 'fao'], // Faroese
|
||||
['', 'fat'], // Fanti
|
||||
['fj', 'fij'], // Fijian
|
||||
['', 'fil'], // Filipino; Pilipino
|
||||
['fi', 'fin'], // Finnish
|
||||
['', 'fiu'], // Finno-Ugrian languages
|
||||
['', 'fon'], // Fon
|
||||
['fr', 'fre'], // French
|
||||
['', 'frm'], // French, Middle (ca.1400-1600)
|
||||
['', 'fro'], // French, Old (842-ca.1400)
|
||||
['', 'frr'], // Northern Frisian
|
||||
['', 'frs'], // Eastern Frisian
|
||||
['fy', 'fry'], // Western Frisian
|
||||
['ff', 'ful'], // Fulah
|
||||
['', 'fur'], // Friulian
|
||||
['', 'gaa'], // Ga
|
||||
['', 'gay'], // Gayo
|
||||
['', 'gba'], // Gbaya
|
||||
['', 'gem'], // Germanic languages
|
||||
['ka', 'geo'], // Georgian
|
||||
['de', 'ger'], // German
|
||||
['', 'gez'], // Geez
|
||||
['', 'gil'], // Gilbertese
|
||||
['gd', 'gla'], // Gaelic; Scottish Gaelic
|
||||
['ga', 'gle'], // Irish
|
||||
['gl', 'glg'], // Galician
|
||||
['gv', 'glv'], // Manx
|
||||
['', 'gmh'], // German, Middle High (ca.1050-1500)
|
||||
['', 'goh'], // German, Old High (ca.750-1050)
|
||||
['', 'gon'], // Gondi
|
||||
['', 'gor'], // Gorontalo
|
||||
['', 'got'], // Gothic
|
||||
['', 'grb'], // Grebo
|
||||
['', 'grc'], // Greek, Ancient (to 1453)
|
||||
['el', 'gre'], // Greek, Modern (1453-)
|
||||
['gn', 'grn'], // Guarani
|
||||
['', 'gsw'], // Swiss German; Alemannic; Alsatian
|
||||
['gu', 'guj'], // Gujarati
|
||||
['', 'gwi'], // Gwich'in
|
||||
['', 'hai'], // Haida
|
||||
['ht', 'hat'], // Haitian; Haitian Creole
|
||||
['ha', 'hau'], // Hausa
|
||||
['', 'haw'], // Hawaiian
|
||||
['he', 'heb'], // Hebrew
|
||||
['hz', 'her'], // Herero
|
||||
['', 'hil'], // Hiligaynon
|
||||
['', 'him'], // Himachali languages; Western Pahari languages
|
||||
['hi', 'hin'], // Hindi
|
||||
['', 'hit'], // Hittite
|
||||
['', 'hmn'], // Hmong; Mong
|
||||
['ho', 'hmo'], // Hiri Motu
|
||||
['hr', 'hrv'], // Croatian
|
||||
['', 'hsb'], // Upper Sorbian
|
||||
['hu', 'hun'], // Hungarian
|
||||
['', 'hup'], // Hupa
|
||||
['', 'iba'], // Iban
|
||||
['ig', 'ibo'], // Igbo
|
||||
['is', 'ice'], // Icelandic
|
||||
['io', 'ido'], // Ido
|
||||
['ii', 'iii'], // Sichuan Yi; Nuosu
|
||||
['', 'ijo'], // Ijo languages
|
||||
['iu', 'iku'], // Inuktitut
|
||||
['ie', 'ile'], // Interlingue; Occidental
|
||||
['', 'ilo'], // Iloko
|
||||
['ia', 'ina'], // Interlingua (International Auxiliary Language Association)
|
||||
['', 'inc'], // Indic languages
|
||||
['id', 'ind'], // Indonesian
|
||||
['', 'ine'], // Indo-European languages
|
||||
['', 'inh'], // Ingush
|
||||
['ik', 'ipk'], // Inupiaq
|
||||
['', 'ira'], // Iranian languages
|
||||
['', 'iro'], // Iroquoian languages
|
||||
['it', 'ita'], // Italian
|
||||
['jv', 'jav'], // Javanese
|
||||
['', 'jbo'], // Lojban
|
||||
['ja', 'jpn'], // Japanese
|
||||
['', 'jpr'], // Judeo-Persian
|
||||
['', 'jrb'], // Judeo-Arabic
|
||||
['', 'kaa'], // Kara-Kalpak
|
||||
['', 'kab'], // Kabyle
|
||||
['', 'kac'], // Kachin; Jingpho
|
||||
['kl', 'kal'], // Kalaallisut; Greenlandic
|
||||
['', 'kam'], // Kamba
|
||||
['kn', 'kan'], // Kannada
|
||||
['', 'kar'], // Karen languages
|
||||
['ks', 'kas'], // Kashmiri
|
||||
['kr', 'kau'], // Kanuri
|
||||
['', 'kaw'], // Kawi
|
||||
['kk', 'kaz'], // Kazakh
|
||||
['', 'kbd'], // Kabardian
|
||||
['', 'kha'], // Khasi
|
||||
['', 'khi'], // Khoisan languages
|
||||
['km', 'khm'], // Central Khmer
|
||||
['', 'kho'], // Khotanese; Sakan
|
||||
['ki', 'kik'], // Kikuyu; Gikuyu
|
||||
['rw', 'kin'], // Kinyarwanda
|
||||
['ky', 'kir'], // Kirghiz; Kyrgyz
|
||||
['', 'kmb'], // Kimbundu
|
||||
['', 'kok'], // Konkani
|
||||
['kv', 'kom'], // Komi
|
||||
['kg', 'kon'], // Kongo
|
||||
['ko', 'kor'], // Korean
|
||||
['', 'kos'], // Kosraean
|
||||
['', 'kpe'], // Kpelle
|
||||
['', 'krc'], // Karachay-Balkar
|
||||
['', 'krl'], // Karelian
|
||||
['', 'kro'], // Kru languages
|
||||
['', 'kru'], // Kurukh
|
||||
['kj', 'kua'], // Kuanyama; Kwanyama
|
||||
['', 'kum'], // Kumyk
|
||||
['ku', 'kur'], // Kurdish
|
||||
['', 'kut'], // Kutenai
|
||||
['', 'lad'], // Ladino
|
||||
['', 'lah'], // Lahnda
|
||||
['', 'lam'], // Lamba
|
||||
['lo', 'lao'], // Lao
|
||||
['la', 'lat'], // Latin
|
||||
['lv', 'lav'], // Latvian
|
||||
['', 'lez'], // Lezghian
|
||||
['li', 'lim'], // Limburgan; Limburger; Limburgish
|
||||
['ln', 'lin'], // Lingala
|
||||
['lt', 'lit'], // Lithuanian
|
||||
['', 'lol'], // Mongo
|
||||
['', 'loz'], // Lozi
|
||||
['lb', 'ltz'], // Luxembourgish; Letzeburgesch
|
||||
['', 'lua'], // Luba-Lulua
|
||||
['lu', 'lub'], // Luba-Katanga
|
||||
['lg', 'lug'], // Ganda
|
||||
['', 'lui'], // Luiseno
|
||||
['', 'lun'], // Lunda
|
||||
['', 'luo'], // Luo (Kenya and Tanzania)
|
||||
['', 'lus'], // Lushai
|
||||
['mk', 'mac'], // Macedonian
|
||||
['', 'mad'], // Madurese
|
||||
['', 'mag'], // Magahi
|
||||
['mh', 'mah'], // Marshallese
|
||||
['', 'mai'], // Maithili
|
||||
['', 'mak'], // Makasar
|
||||
['ml', 'mal'], // Malayalam
|
||||
['', 'man'], // Mandingo
|
||||
['mi', 'mao'], // Maori
|
||||
['', 'map'], // Austronesian languages
|
||||
['mr', 'mar'], // Marathi
|
||||
['', 'mas'], // Masai
|
||||
['ms', 'may'], // Malay
|
||||
['', 'mdf'], // Moksha
|
||||
['', 'mdr'], // Mandar
|
||||
['', 'men'], // Mende
|
||||
['', 'mga'], // Irish, Middle (900-1200)
|
||||
['', 'mic'], // Mi'kmaq; Micmac
|
||||
['', 'min'], // Minangkabau
|
||||
['', 'mis'], // Uncoded languages
|
||||
['', 'mkh'], // Mon-Khmer languages
|
||||
['mg', 'mlg'], // Malagasy
|
||||
['mt', 'mlt'], // Maltese
|
||||
['', 'mnc'], // Manchu
|
||||
['', 'mni'], // Manipuri
|
||||
['', 'mno'], // Manobo languages
|
||||
['', 'moh'], // Mohawk
|
||||
['mn', 'mon'], // Mongolian
|
||||
['', 'mos'], // Mossi
|
||||
['', 'mul'], // Multiple languages
|
||||
['', 'mun'], // Munda languages
|
||||
['', 'mus'], // Creek
|
||||
['', 'mwl'], // Mirandese
|
||||
['', 'mwr'], // Marwari
|
||||
['', 'myn'], // Mayan languages
|
||||
['', 'myv'], // Erzya
|
||||
['', 'nah'], // Nahuatl languages
|
||||
['', 'nai'], // North American Indian languages
|
||||
['', 'nap'], // Neapolitan
|
||||
['na', 'nau'], // Nauru
|
||||
['nv', 'nav'], // Navajo; Navaho
|
||||
['nr', 'nbl'], // Ndebele, South; South Ndebele
|
||||
['nd', 'nde'], // Ndebele, North; North Ndebele
|
||||
['ng', 'ndo'], // Ndonga
|
||||
['', 'nds'], // Low German; Low Saxon; German, Low; Saxon, Low
|
||||
['ne', 'nep'], // Nepali
|
||||
['', 'new'], // Nepal Bhasa; Newari
|
||||
['', 'nia'], // Nias
|
||||
['', 'nic'], // Niger-Kordofanian languages
|
||||
['', 'niu'], // Niuean
|
||||
['nn', 'nno'], // Norwegian Nynorsk; Nynorsk, Norwegian
|
||||
['nb', 'nob'], // Bokmål, Norwegian; Norwegian Bokmål
|
||||
['', 'nog'], // Nogai
|
||||
['', 'non'], // Norse, Old
|
||||
['no', 'nor'], // Norwegian
|
||||
['', 'nqo'], // N'Ko
|
||||
['', 'nso'], // Pedi; Sepedi; Northern Sotho
|
||||
['', 'nub'], // Nubian languages
|
||||
['', 'nwc'], // Classical Newari; Old Newari; Classical Nepal Bhasa
|
||||
['ny', 'nya'], // Chichewa; Chewa; Nyanja
|
||||
['', 'nym'], // Nyamwezi
|
||||
['', 'nyn'], // Nyankole
|
||||
['', 'nyo'], // Nyoro
|
||||
['', 'nzi'], // Nzima
|
||||
['oc', 'oci'], // Occitan (post 1500)
|
||||
['oj', 'oji'], // Ojibwa
|
||||
['or', 'ori'], // Oriya
|
||||
['om', 'orm'], // Oromo
|
||||
['', 'osa'], // Osage
|
||||
['os', 'oss'], // Ossetian; Ossetic
|
||||
['', 'ota'], // Turkish, Ottoman (1500-1928)
|
||||
['', 'oto'], // Otomian languages
|
||||
['', 'paa'], // Papuan languages
|
||||
['', 'pag'], // Pangasinan
|
||||
['', 'pal'], // Pahlavi
|
||||
['', 'pam'], // Pampanga; Kapampangan
|
||||
['pa', 'pan'], // Panjabi; Punjabi
|
||||
['', 'pap'], // Papiamento
|
||||
['', 'pau'], // Palauan
|
||||
['', 'peo'], // Persian, Old (ca.600-400 B.C.)
|
||||
['fa', 'per'], // Persian
|
||||
['', 'phi'], // Philippine languages
|
||||
['', 'phn'], // Phoenician
|
||||
['pi', 'pli'], // Pali
|
||||
['pl', 'pol'], // Polish
|
||||
['', 'pon'], // Pohnpeian
|
||||
['pt', 'por'], // Portuguese
|
||||
['', 'pra'], // Prakrit languages
|
||||
['', 'pro'], // Provençal, Old (to 1500); Occitan, Old (to 1500)
|
||||
['ps', 'pus'], // Pushto; Pashto
|
||||
['', 'qaaqtz'], // Reserved for local use
|
||||
['qu', 'que'], // Quechua
|
||||
['', 'raj'], // Rajasthani
|
||||
['', 'rap'], // Rapanui
|
||||
['', 'rar'], // Rarotongan; Cook Islands Maori
|
||||
['', 'roa'], // Romance languages
|
||||
['rm', 'roh'], // Romansh
|
||||
['', 'rom'], // Romany
|
||||
['ro', 'rum'], // Romanian; Moldavian; Moldovan
|
||||
['rn', 'run'], // Rundi
|
||||
['', 'rup'], // Aromanian; Arumanian; Macedo-Romanian
|
||||
['ru', 'rus'], // Russian
|
||||
['', 'sad'], // Sandawe
|
||||
['sg', 'sag'], // Sango
|
||||
['', 'sah'], // Yakut
|
||||
['', 'sai'], // South American Indian languages
|
||||
['', 'sal'], // Salishan languages
|
||||
['', 'sam'], // Samaritan Aramaic
|
||||
['sa', 'san'], // Sanskrit
|
||||
['', 'sas'], // Sasak
|
||||
['', 'sat'], // Santali
|
||||
['', 'scn'], // Sicilian
|
||||
['', 'sco'], // Scots
|
||||
['', 'sel'], // Selkup
|
||||
['', 'sem'], // Semitic languages
|
||||
['', 'sga'], // Irish, Old (to 900)
|
||||
['', 'sgn'], // Sign Languages
|
||||
['', 'shn'], // Shan
|
||||
['', 'sid'], // Sidamo
|
||||
['si', 'sin'], // Sinhala; Sinhalese
|
||||
['', 'sio'], // Siouan languages
|
||||
['', 'sit'], // Sino-Tibetan languages
|
||||
['', 'sla'], // Slavic languages
|
||||
['sk', 'slo'], // Slovak
|
||||
['sl', 'slv'], // Slovenian
|
||||
['', 'sma'], // Southern Sami
|
||||
['se', 'sme'], // Northern Sami
|
||||
['', 'smi'], // Sami languages
|
||||
['', 'smj'], // Lule Sami
|
||||
['', 'smn'], // Inari Sami
|
||||
['sm', 'smo'], // Samoan
|
||||
['', 'sms'], // Skolt Sami
|
||||
['sn', 'sna'], // Shona
|
||||
['sd', 'snd'], // Sindhi
|
||||
['', 'snk'], // Soninke
|
||||
['', 'sog'], // Sogdian
|
||||
['so', 'som'], // Somali
|
||||
['', 'son'], // Songhai languages
|
||||
['st', 'sot'], // Sotho, Southern
|
||||
['es', 'spa'], // Spanish; Castilian
|
||||
['sc', 'srd'], // Sardinian
|
||||
['', 'srn'], // Sranan Tongo
|
||||
['sr', 'srp'], // Serbian
|
||||
['', 'srr'], // Serer
|
||||
['', 'ssa'], // Nilo-Saharan languages
|
||||
['ss', 'ssw'], // Swati
|
||||
['', 'suk'], // Sukuma
|
||||
['su', 'sun'], // Sundanese
|
||||
['', 'sus'], // Susu
|
||||
['', 'sux'], // Sumerian
|
||||
['sw', 'swa'], // Swahili
|
||||
['sv', 'swe'], // Swedish
|
||||
['', 'syc'], // Classical Syriac
|
||||
['', 'syr'], // Syriac
|
||||
['ty', 'tah'], // Tahitian
|
||||
['', 'tai'], // Tai languages
|
||||
['ta', 'tam'], // Tamil
|
||||
['tt', 'tat'], // Tatar
|
||||
['te', 'tel'], // Telugu
|
||||
['', 'tem'], // Timne
|
||||
['', 'ter'], // Tereno
|
||||
['', 'tet'], // Tetum
|
||||
['tg', 'tgk'], // Tajik
|
||||
['tl', 'tgl'], // Tagalog
|
||||
['th', 'tha'], // Thai
|
||||
['bo', 'tib'], // Tibetan
|
||||
['', 'tig'], // Tigre
|
||||
['ti', 'tir'], // Tigrinya
|
||||
['', 'tiv'], // Tiv
|
||||
['', 'tkl'], // Tokelau
|
||||
['', 'tlh'], // Klingon; tlhIngan-Hol
|
||||
['', 'tli'], // Tlingit
|
||||
['', 'tmh'], // Tamashek
|
||||
['', 'tog'], // Tonga (Nyasa)
|
||||
['to', 'ton'], // Tonga (Tonga Islands)
|
||||
['', 'tpi'], // Tok Pisin
|
||||
['', 'tsi'], // Tsimshian
|
||||
['tn', 'tsn'], // Tswana
|
||||
['ts', 'tso'], // Tsonga
|
||||
['tk', 'tuk'], // Turkmen
|
||||
['', 'tum'], // Tumbuka
|
||||
['', 'tup'], // Tupi languages
|
||||
['tr', 'tur'], // Turkish
|
||||
['', 'tut'], // Altaic languages
|
||||
['', 'tvl'], // Tuvalu
|
||||
['tw', 'twi'], // Twi
|
||||
['', 'tyv'], // Tuvinian
|
||||
['', 'udm'], // Udmurt
|
||||
['', 'uga'], // Ugaritic
|
||||
['ug', 'uig'], // Uighur; Uyghur
|
||||
['uk', 'ukr'], // Ukrainian
|
||||
['', 'umb'], // Umbundu
|
||||
['', 'und'], // Undetermined
|
||||
['ur', 'urd'], // Urdu
|
||||
['uz', 'uzb'], // Uzbek
|
||||
['', 'vai'], // Vai
|
||||
['ve', 'ven'], // Venda
|
||||
['vi', 'vie'], // Vietnamese
|
||||
['vo', 'vol'], // Volapük
|
||||
['', 'vot'], // Votic
|
||||
['', 'wak'], // Wakashan languages
|
||||
['', 'wal'], // Wolaitta; Wolaytta
|
||||
['', 'war'], // Waray
|
||||
['', 'was'], // Washo
|
||||
['cy', 'wel'], // Welsh
|
||||
['', 'wen'], // Sorbian languages
|
||||
['wa', 'wln'], // Walloon
|
||||
['wo', 'wol'], // Wolof
|
||||
['', 'xal'], // Kalmyk; Oirat
|
||||
['xh', 'xho'], // Xhosa
|
||||
['', 'yao'], // Yao
|
||||
['', 'yap'], // Yapese
|
||||
['yi', 'yid'], // Yiddish
|
||||
['yo', 'yor'], // Yoruba
|
||||
['', 'ypk'], // Yupik languages
|
||||
['', 'zap'], // Zapotec
|
||||
['', 'zbl'], // Blissymbols; Blissymbolics; Bliss
|
||||
['', 'zen'], // Zenaga
|
||||
['', 'zgh'], // Standard Moroccan Tamazight
|
||||
['za', 'zha'], // Zhuang; Chuang
|
||||
['', 'znd'], // Zande languages
|
||||
['zu', 'zul'], // Zulu
|
||||
['', 'zun'], // Zuni
|
||||
['', 'zxx'], // No linguistic content; Not applicable
|
||||
// phpcs:enable Squiz.PHP.CommentedOutCode.Found
|
||||
];
|
||||
|
||||
/**
|
||||
* Initializes the rule defining the ISO 639 set.
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function __construct(string $set = self::ALPHA2)
|
||||
{
|
||||
$index = array_search($set, self::AVAILABLE_SETS, true);
|
||||
if ($index === false) {
|
||||
throw new ComponentException(sprintf('"%s" is not a valid language set for ISO 639', $set));
|
||||
}
|
||||
|
||||
parent::__construct(new In($this->getHaystack($index), true), ['set' => $set]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getHaystack(int $index): array
|
||||
{
|
||||
return array_filter(array_column(self::LANGUAGE_CODES, $index));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
|
||||
use function is_scalar;
|
||||
|
||||
/**
|
||||
* Validates if a date is leap.
|
||||
*
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jayson Reis <santosdosreis@gmail.com>
|
||||
*/
|
||||
final class LeapDate extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $format;
|
||||
|
||||
/**
|
||||
* Initializes the rule with the expected format.
|
||||
*/
|
||||
public function __construct(string $format)
|
||||
{
|
||||
$this->format = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof DateTimeInterface) {
|
||||
return $input->format('m-d') === '02-29';
|
||||
}
|
||||
|
||||
if (is_scalar($input)) {
|
||||
return $this->validate(DateTimeImmutable::createFromFormat($this->format, (string) $input));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use DateTimeInterface;
|
||||
|
||||
use function date;
|
||||
use function is_numeric;
|
||||
use function is_scalar;
|
||||
use function sprintf;
|
||||
use function strtotime;
|
||||
|
||||
/**
|
||||
* Validates if a year is leap.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jayson Reis <santosdosreis@gmail.com>
|
||||
*/
|
||||
final class LeapYear extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (is_numeric($input)) {
|
||||
$date = strtotime(sprintf('%d-02-29', (int) $input));
|
||||
|
||||
return (bool) date('L', (int) $date);
|
||||
}
|
||||
|
||||
if (is_scalar($input)) {
|
||||
return $this->validate((int) date('Y', (int) strtotime((string) $input)));
|
||||
}
|
||||
|
||||
if ($input instanceof DateTimeInterface) {
|
||||
return $this->validate($input->format('Y'));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Countable as CountableInterface;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
use function count;
|
||||
use function get_object_vars;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function mb_strlen;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Validates the length of the given input.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Blake Hair <blake.hair@gmail.com>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Hugo Hamon <hugo.hamon@sensiolabs.com>
|
||||
* @author João Torquato <joao.otl@gmail.com>
|
||||
* @author Marcelo Araujo <msaraujo@php.net>
|
||||
*/
|
||||
final class Length extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $minValue;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $maxValue;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $inclusive;
|
||||
|
||||
/**
|
||||
* Creates the rule with a minimum and maximum value.
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function __construct(?int $min = null, ?int $max = null, bool $inclusive = true)
|
||||
{
|
||||
$this->minValue = $min;
|
||||
$this->maxValue = $max;
|
||||
$this->inclusive = $inclusive;
|
||||
|
||||
if ($max !== null && $min > $max) {
|
||||
throw new ComponentException(sprintf('%d cannot be less than %d for validation', $min, $max));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
$length = $this->extractLength($input);
|
||||
if ($length === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->validateMin($length) && $this->validateMax($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
*/
|
||||
private function extractLength($input): ?int
|
||||
{
|
||||
if (is_string($input)) {
|
||||
return (int) mb_strlen($input);
|
||||
}
|
||||
|
||||
if (is_array($input) || $input instanceof CountableInterface) {
|
||||
return count($input);
|
||||
}
|
||||
|
||||
if (is_object($input)) {
|
||||
return $this->extractLength(get_object_vars($input));
|
||||
}
|
||||
|
||||
if (is_int($input)) {
|
||||
return $this->extractLength((string) $input);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function validateMin(int $length): bool
|
||||
{
|
||||
if ($this->minValue === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->inclusive) {
|
||||
return $length >= $this->minValue;
|
||||
}
|
||||
|
||||
return $length > $this->minValue;
|
||||
}
|
||||
|
||||
private function validateMax(int $length): bool
|
||||
{
|
||||
if ($this->maxValue === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->inclusive) {
|
||||
return $length <= $this->maxValue;
|
||||
}
|
||||
|
||||
return $length < $this->maxValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates whether the input is less than a value.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class LessThan extends AbstractComparison
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function compare($left, $right): bool
|
||||
{
|
||||
return $left < $right;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_string;
|
||||
use function mb_strtolower;
|
||||
|
||||
/**
|
||||
* Validates whether the characters in the input are lowercase.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jean Pimentel <jeanfap@gmail.com>
|
||||
*/
|
||||
final class Lowercase extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $input === mb_strtolower($input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function str_split;
|
||||
|
||||
/**
|
||||
* Validate whether a given input is a Luhn number.
|
||||
*
|
||||
* @see https://en.wikipedia.org/wiki/Luhn_algorithm
|
||||
*
|
||||
* @author Alexander Gorshkov <mazanax@yandex.ru>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Luhn extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!(new Digit())->validate($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isValid((string) $input);
|
||||
}
|
||||
|
||||
private function isValid(string $input): bool
|
||||
{
|
||||
$sum = 0;
|
||||
$digits = array_map('intval', str_split($input));
|
||||
$numDigits = count($digits);
|
||||
$parity = $numDigits % 2;
|
||||
for ($i = 0; $i < $numDigits; ++$i) {
|
||||
$digit = $digits[$i];
|
||||
if ($parity == $i % 2) {
|
||||
$digit <<= 1;
|
||||
if (9 < $digit) {
|
||||
$digit = $digit - 9;
|
||||
}
|
||||
}
|
||||
$sum += $digit;
|
||||
}
|
||||
|
||||
return $sum % 10 == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a valid MAC address.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Fábio da Silva Ribeiro <fabiorphp@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class MacAddress extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match('/^(([0-9a-fA-F]{2}-){5}|([0-9a-fA-F]{2}:){5})[0-9a-fA-F]{2}$/', $input) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates whether the input is less than or equal to a value.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Max extends AbstractComparison
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function compare($left, $right): bool
|
||||
{
|
||||
return $left <= $right;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates a maximum age for a given date.
|
||||
*
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class MaxAge extends AbstractAge
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function compare(int $baseDate, int $givenDate): bool
|
||||
{
|
||||
return $baseDate <= $givenDate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use finfo;
|
||||
use SplFileInfo;
|
||||
|
||||
use function is_file;
|
||||
use function is_string;
|
||||
|
||||
use const FILEINFO_MIME_TYPE;
|
||||
|
||||
/**
|
||||
* Validates if the input is a file and if its MIME type matches the expected one.
|
||||
*
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Mimetype extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mimetype;
|
||||
|
||||
/**
|
||||
* @var finfo
|
||||
*/
|
||||
private $fileInfo;
|
||||
|
||||
/**
|
||||
* Initializes the rule by defining the expected mimetype from the input.
|
||||
*/
|
||||
public function __construct(string $mimetype, ?finfo $fileInfo = null)
|
||||
{
|
||||
$this->mimetype = $mimetype;
|
||||
$this->fileInfo = $fileInfo ?: new finfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($input instanceof SplFileInfo) {
|
||||
return $this->validate($input->getPathname());
|
||||
}
|
||||
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_file($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->mimetype === $this->fileInfo->file($input, FILEINFO_MIME_TYPE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates whether the input is greater than or equal to a value.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class Min extends AbstractComparison
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function compare($left, $right): bool
|
||||
{
|
||||
return $left >= $right;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* Validates a minimum age for a given date.
|
||||
*
|
||||
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jean Pimentel <jeanfap@gmail.com>
|
||||
* @author Kennedy Tedesco <kennedyt.tw@gmail.com>
|
||||
*/
|
||||
final class MinAge extends AbstractAge
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function compare(int $baseDate, int $givenDate): bool
|
||||
{
|
||||
return $baseDate >= $givenDate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use libphonenumber\NumberParseException;
|
||||
|
||||
use function is_scalar;
|
||||
|
||||
final class Mobile extends AbstractRule
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_scalar($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 此处使用简单的正则表达式检查中国大陆的手机号码格式
|
||||
return preg_match('/^1[3456789]\d{9}$/', (string) $input) === 1;
|
||||
} catch (NumberParseException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* @author Danilo Benevides <danilobenevides01@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Jean Pimentel <jeanfap@gmail.com>
|
||||
*/
|
||||
final class Multiple extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $multipleOf;
|
||||
|
||||
public function __construct(int $multipleOf)
|
||||
{
|
||||
$this->multipleOf = $multipleOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if ($this->multipleOf == 0) {
|
||||
return $input == 0;
|
||||
}
|
||||
|
||||
return $input % $this->multipleOf == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function is_numeric;
|
||||
|
||||
/**
|
||||
* Validates whether the input is a negative number.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Ismael Elias <ismael.esq@hotmail.com>
|
||||
*/
|
||||
final class Negative extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_numeric($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $input < 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function array_map;
|
||||
use function floor;
|
||||
use function mb_strlen;
|
||||
use function str_split;
|
||||
|
||||
/**
|
||||
* Validates the access key of the Brazilian electronic invoice (NFe).
|
||||
*
|
||||
*
|
||||
* (pt-br) Valida chave de acesso de NFe, mais especificamente, relacionada ao DANFE.
|
||||
*
|
||||
* @see (pt-br) Manual de Integração do Contribuinte v4.0.1 em http://www.nfe.fazenda.gov.br
|
||||
*
|
||||
* @author Andrey Knupp Vital <andreykvital@gmail.com>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class NfeAccessKey extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (mb_strlen($input) !== 44) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$digits = array_map('intval', str_split($input));
|
||||
$w = [];
|
||||
for ($i = 0, $z = 5, $m = 43; $i <= $m; ++$i) {
|
||||
$z = $i < $m ? $z - 1 == 1 ? 9 : $z - 1 : 0;
|
||||
$w[] = $z;
|
||||
}
|
||||
|
||||
for ($i = 0, $s = 0, $k = 44; $i < $k; ++$i) {
|
||||
$s += $digits[$i] * $w[$i];
|
||||
}
|
||||
|
||||
$s -= 11 * floor($s / 11);
|
||||
$v = $s == 0 || $s == 1 ? 0 : 11 - $s;
|
||||
|
||||
return $v == $digits[43];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use function array_pop;
|
||||
use function array_sum;
|
||||
use function is_numeric;
|
||||
use function is_string;
|
||||
use function mb_substr;
|
||||
use function preg_match;
|
||||
use function str_split;
|
||||
|
||||
/**
|
||||
* Validates Spain's fiscal identification number (NIF).
|
||||
*
|
||||
*
|
||||
* @see https://es.wikipedia.org/wiki/N%C3%BAmero_de_identificaci%C3%B3n_fiscal
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Julián Gutiérrez <juliangut@gmail.com>
|
||||
* @author Senén <senen@instasent.com>
|
||||
*/
|
||||
final class Nif extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/^(\d{8})([A-Z])$/', $input, $matches)) {
|
||||
return $this->validateDni((int) $matches[1], $matches[2]);
|
||||
}
|
||||
|
||||
if (preg_match('/^([KLMXYZ])(\d{7})([A-Z])$/', $input, $matches)) {
|
||||
return $this->validateNie($matches[1], $matches[2], $matches[3]);
|
||||
}
|
||||
|
||||
if (preg_match('/^([A-HJNP-SUVW])(\d{7})([0-9A-Z])$/', $input, $matches)) {
|
||||
return $this->validateCif($matches[2], $matches[3]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function validateDni(int $number, string $control): bool
|
||||
{
|
||||
return mb_substr('TRWAGMYFPDXBNJZSQVHLCKE', $number % 23, 1) === $control;
|
||||
}
|
||||
|
||||
private function validateNie(string $prefix, string $number, string $control): bool
|
||||
{
|
||||
if ($prefix === 'Y') {
|
||||
return $this->validateDni((int) ('1' . $number), $control);
|
||||
}
|
||||
|
||||
if ($prefix === 'Z') {
|
||||
return $this->validateDni((int) ('2' . $number), $control);
|
||||
}
|
||||
|
||||
return $this->validateDni((int) $number, $control);
|
||||
}
|
||||
|
||||
private function validateCif(string $number, string $control): bool
|
||||
{
|
||||
$code = 0;
|
||||
$position = 1;
|
||||
/** @var int $digit */
|
||||
foreach (str_split($number) as $digit) {
|
||||
$increaser = $digit;
|
||||
if ($position % 2 !== 0) {
|
||||
$increaser = array_sum(str_split((string) ($digit * 2)));
|
||||
}
|
||||
|
||||
$code += $increaser;
|
||||
++$position;
|
||||
}
|
||||
|
||||
$digits = str_split((string) $code);
|
||||
$lastDigit = (int) array_pop($digits);
|
||||
$key = $lastDigit === 0 ? 0 : 10 - $lastDigit;
|
||||
|
||||
if (is_numeric($control)) {
|
||||
return (int) $key === (int) $control;
|
||||
}
|
||||
|
||||
return mb_substr('JABCDEFGHI', $key % 10, 1) === $control;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user