diff --git a/src/Symfony/Component/Validator/Constraints/Base64Encoded.php b/src/Symfony/Component/Validator/Constraints/Base64Encoded.php new file mode 100644 index 0000000000000..9195dc5f1733f --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Base64Encoded.php @@ -0,0 +1,25 @@ + + * + * 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; + +/** + * Ensures that the value is a valid Base64-encoded. + * + * @author Refat Alsakka + */ +#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class Base64Encoded extends Constraint +{ + public string $message = 'The string "{{ value }}" is not a valid Base64-encoded value.'; +} diff --git a/src/Symfony/Component/Validator/Constraints/Base64EncodedValidator.php b/src/Symfony/Component/Validator/Constraints/Base64EncodedValidator.php new file mode 100644 index 0000000000000..d0d19813f9eca --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Base64EncodedValidator.php @@ -0,0 +1,40 @@ + + * + * 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; + +/** + * @author Refat Alsakka + */ +class Base64EncodedValidator extends ConstraintValidator +{ + public function validate(mixed $value, Constraint $constraint): void + { + if (!$constraint instanceof Base64Encoded) { + throw new UnexpectedTypeException($constraint, Base64Encoded::class); + } + + if (!$this->isValidBase64($value)) { + $this->context->buildViolation($constraint->message) + ->setParameter('{{ value }}', $value) + ->addViolation(); + } + } + + private function isValidBase64(string $value): bool + { + return base64_encode(base64_decode($value, true)) == $value; + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/Base64EncodedValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/Base64EncodedValidatorTest.php new file mode 100644 index 0000000000000..71bf93615be70 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/Base64EncodedValidatorTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Base64Encoded; +use Symfony\Component\Validator\Constraints\Base64EncodedValidator; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; + +/** + * @author Refat Alsakka + */ +class Base64EncodedValidatorTest extends ConstraintValidatorTestCase +{ + protected function createValidator(): Base64EncodedValidator + { + return new Base64EncodedValidator(); + } + + public function testValidBase64() + { + $this->validator->validate('U3ltZm9ueQ==', new Base64Encoded()); + $this->assertNoViolation(); + } + + public function testInvalidBase64() + { + $this->validator->validate('invalid@base64', new Base64Encoded()); + + $this->buildViolation('The value "{{ value }}" is not a valid Base64-encoded string.') + ->setParameter('{{ value }}', 'invalid@base64') + ->assertRaised(); + } +}