diff --git a/Constraints/Ip.php b/Constraints/Ip.php index 94c4ca484..c6f940c29 100644 --- a/Constraints/Ip.php +++ b/Constraints/Ip.php @@ -46,6 +46,16 @@ class Ip extends Constraint public const V6_ONLY_PUBLIC = '6_public'; public const ALL_ONLY_PUBLIC = 'all_public'; + // adds inverse FILTER_FLAG_NO_PRIV_RANGE + public const V4_ONLY_PRIV = '4_priv'; + public const V6_ONLY_PRIV = '6_priv'; + public const ALL_ONLY_PRIV = 'all_priv'; + + // adds inverse FILTER_FLAG_NO_RES_RANGE + public const V4_ONLY_RES = '4_res'; + public const V6_ONLY_RES = '6_res'; + public const ALL_ONLY_RES = 'all_res'; + public const INVALID_IP_ERROR = 'b1b427ae-9f6f-41b0-aa9b-84511fbb3c5b'; protected const VERSIONS = [ @@ -64,6 +74,14 @@ class Ip extends Constraint self::V4_ONLY_PUBLIC, self::V6_ONLY_PUBLIC, self::ALL_ONLY_PUBLIC, + + self::V4_ONLY_PRIV, + self::V6_ONLY_PRIV, + self::ALL_ONLY_PRIV, + + self::V4_ONLY_RES, + self::V6_ONLY_RES, + self::ALL_ONLY_RES, ]; protected const ERROR_NAMES = [ diff --git a/Constraints/IpValidator.php b/Constraints/IpValidator.php index 2f71a8804..7f4d6d13d 100644 --- a/Constraints/IpValidator.php +++ b/Constraints/IpValidator.php @@ -24,9 +24,6 @@ */ class IpValidator extends ConstraintValidator { - /** - * @return void - */ public function validate(mixed $value, Constraint $constraint) { if (!$constraint instanceof Ip) { @@ -48,8 +45,8 @@ public function validate(mixed $value, Constraint $constraint) } $flag = match ($constraint->version) { - Ip::V4 => \FILTER_FLAG_IPV4, - Ip::V6 => \FILTER_FLAG_IPV6, + Ip::V4, Ip::V4_ONLY_PRIV, Ip::V4_ONLY_RES => \FILTER_FLAG_IPV4, + Ip::V6, Ip::V6_ONLY_PRIV, Ip::V6_ONLY_RES => \FILTER_FLAG_IPV6, Ip::V4_NO_PRIV => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_PRIV_RANGE, Ip::V6_NO_PRIV => \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_PRIV_RANGE, Ip::ALL_NO_PRIV => \FILTER_FLAG_NO_PRIV_RANGE, @@ -67,6 +64,21 @@ public function validate(mixed $value, Constraint $constraint) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Ip::INVALID_IP_ERROR) ->addViolation(); + + return; + } + + $inverseFlag = match ($constraint->version) { + Ip::V4_ONLY_PRIV, Ip::V6_ONLY_PRIV, Ip::ALL_ONLY_PRIV => \FILTER_FLAG_NO_PRIV_RANGE, + Ip::V4_ONLY_RES, Ip::V6_ONLY_RES, Ip::ALL_ONLY_RES => \FILTER_FLAG_NO_RES_RANGE, + default => 0, + }; + + if ($inverseFlag && filter_var($value, \FILTER_VALIDATE_IP, $inverseFlag)) { + $this->context->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Ip::INVALID_IP_ERROR) + ->addViolation(); } } } diff --git a/Constraints/Mac.php b/Constraints/Mac.php new file mode 100644 index 000000000..dd107fcde --- /dev/null +++ b/Constraints/Mac.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidArgumentException; + +/** + * Validates that a value is a valid MAC address. + * + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Ninos Ego + */ +#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class Mac extends Constraint +{ + public const INVALID_MAC_ERROR = 'a183fbff-6968-43b4-82a2-cc5cf7150036'; + + protected const ERROR_NAMES = [ + self::INVALID_MAC_ERROR => 'INVALID_MAC_ERROR', + ]; + + /** + * @deprecated since Symfony 6.1, use const ERROR_NAMES instead + */ + protected static $errorNames = self::ERROR_NAMES; + + public $message = 'This is not a valid MAC address.'; + + public $normalizer; + + public function __construct( + array $options = null, + string $message = null, + callable $normalizer = null, + array $groups = null, + mixed $payload = null + ) { + parent::__construct($options, $groups, $payload); + + $this->message = $message ?? $this->message; + $this->normalizer = $normalizer ?? $this->normalizer; + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', get_debug_type($this->normalizer))); + } + } +} diff --git a/Constraints/MacValidator.php b/Constraints/MacValidator.php new file mode 100644 index 000000000..740f0a5b3 --- /dev/null +++ b/Constraints/MacValidator.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; + +/** + * Validates whether a value is a valid MAC address. + * + * @author Ninos Ego + */ +class MacValidator extends ConstraintValidator +{ + public function validate(mixed $value, Constraint $constraint) + { + if (!$constraint instanceof Mac) { + throw new UnexpectedTypeException($constraint, Mac::class); + } + + if (null === $value || '' === $value) { + return; + } + + if (!\is_scalar($value) && !$value instanceof \Stringable) { + throw new UnexpectedValueException($value, 'string'); + } + + $value = (string) $value; + + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + + if (!filter_var($value, \FILTER_VALIDATE_MAC)) { + $this->context->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Mac::INVALID_MAC_ERROR) + ->addViolation(); + } + } +}