diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 541a40a3e00f9..ce537fe30fa30 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 6.2 --- + * Add option `Email::VALIDATION_MODE_HTML5_ALLOW_NO_TLD` with "html5-allow-no-tld" e-mail validation mode, to match with the W3C official specification * Add method `getCause()` to `ConstraintViolationInterface` * Add the `When` constraint and validator * Deprecate the "loose" e-mail validation mode, use "html5" instead diff --git a/src/Symfony/Component/Validator/Constraints/Email.php b/src/Symfony/Component/Validator/Constraints/Email.php index 4340e7a7217da..55399f977d28b 100644 --- a/src/Symfony/Component/Validator/Constraints/Email.php +++ b/src/Symfony/Component/Validator/Constraints/Email.php @@ -25,6 +25,7 @@ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Email extends Constraint { + public const VALIDATION_MODE_HTML5_ALLOW_NO_TLD = 'html5-allow-no-tld'; public const VALIDATION_MODE_HTML5 = 'html5'; public const VALIDATION_MODE_STRICT = 'strict'; /** @@ -35,6 +36,7 @@ class Email extends Constraint public const INVALID_FORMAT_ERROR = 'bd79c0ab-ddba-46cc-a703-a7a4b08de310'; public const VALIDATION_MODES = [ + self::VALIDATION_MODE_HTML5_ALLOW_NO_TLD, self::VALIDATION_MODE_HTML5, self::VALIDATION_MODE_STRICT, self::VALIDATION_MODE_LOOSE, diff --git a/src/Symfony/Component/Validator/Constraints/EmailValidator.php b/src/Symfony/Component/Validator/Constraints/EmailValidator.php index 44dc30b171d3e..6ff845bb6f712 100644 --- a/src/Symfony/Component/Validator/Constraints/EmailValidator.php +++ b/src/Symfony/Component/Validator/Constraints/EmailValidator.php @@ -24,12 +24,14 @@ */ class EmailValidator extends ConstraintValidator { + private const PATTERN_HTML5_ALLOW_NO_TLD = '/^[a-zA-Z0-9.!#$%&\'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/'; private const PATTERN_HTML5 = '/^[a-zA-Z0-9.!#$%&\'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/'; private const PATTERN_LOOSE = '/^.+\@\S+\.\S+$/'; private const EMAIL_PATTERNS = [ Email::VALIDATION_MODE_LOOSE => self::PATTERN_LOOSE, Email::VALIDATION_MODE_HTML5 => self::PATTERN_HTML5, + Email::VALIDATION_MODE_HTML5_ALLOW_NO_TLD => self::PATTERN_HTML5_ALLOW_NO_TLD, ]; private string $defaultMode; diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php index d70c6bd8b904f..b181e61edec7c 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php @@ -26,6 +26,13 @@ public function testConstructorStrict() $this->assertEquals(Email::VALIDATION_MODE_STRICT, $subject->mode); } + public function testConstructorHtml5AllowNoTld() + { + $subject = new Email(['mode' => Email::VALIDATION_MODE_HTML5_ALLOW_NO_TLD]); + + $this->assertEquals(Email::VALIDATION_MODE_HTML5_ALLOW_NO_TLD, $subject->mode); + } + public function testUnknownModesTriggerException() { $this->expectException(InvalidArgumentException::class); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php index 65a449de8c204..d259a3f8a01c8 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php @@ -232,6 +232,35 @@ public function getInvalidHtml5Emails() ]; } + /** + * @dataProvider getInvalidAllowNoTldEmails + */ + public function testInvalidAllowNoTldEmails($email) + { + $constraint = new Email([ + 'message' => 'myMessage', + 'mode' => Email::VALIDATION_MODE_HTML5_ALLOW_NO_TLD, + ]); + + $this->validator->validate($email, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$email.'"') + ->setCode(Email::INVALID_FORMAT_ERROR) + ->assertRaised(); + } + + public function getInvalidAllowNoTldEmails() + { + return [ + ['example bar'], + ['example@'], + ['example@ bar'], + ['example@localhost bar'], + ['foo@example.com bar'], + ]; + } + public function testModeStrict() { $constraint = new Email(['mode' => Email::VALIDATION_MODE_STRICT]); @@ -253,6 +282,15 @@ public function testModeHtml5() ->assertRaised(); } + public function testModeHtml5AllowNoTld() + { + $constraint = new Email(['mode' => Email::VALIDATION_MODE_HTML5_ALLOW_NO_TLD]); + + $this->validator->validate('example@example', $constraint); + + $this->assertNoViolation(); + } + /** * @group legacy */
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: