diff --git a/src/Symfony/Component/Validator/Constraints/Url.php b/src/Symfony/Component/Validator/Constraints/Url.php index 3306c1b405561..3c36d72f76492 100644 --- a/src/Symfony/Component/Validator/Constraints/Url.php +++ b/src/Symfony/Component/Validator/Constraints/Url.php @@ -104,6 +104,7 @@ class Url extends Constraint * @deprecated since Symfony 4.1, to be removed in 5.0 */ public $checkDNS = self::CHECK_DNS_TYPE_NONE; + public $relativeProtocol = false; public function __construct($options = null) { diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 932aa14436fbc..8490d5c10e74f 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -61,7 +61,8 @@ public function validate($value, Constraint $constraint) return; } - $pattern = sprintf(static::PATTERN, implode('|', $constraint->protocols)); + $pattern = $constraint->relativeProtocol ? str_replace('(%s):', '(?:(%s):)?', static::PATTERN) : static::PATTERN; + $pattern = sprintf($pattern, implode('|', $constraint->protocols)); if (!preg_match($pattern, $value)) { $this->context->buildViolation($constraint->message) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index b7c1dc1d776a7..87b3f0d10ef70 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -65,6 +65,30 @@ public function testValidUrls($url) $this->assertNoViolation(); } + /** + * @dataProvider getValidRelativeUrls + * @dataProvider getValidUrls + */ + public function testValidRelativeUrl($url) + { + $constraint = new Url(array( + 'relativeProtocol' => true, + )); + + $this->validator->validate($url, $constraint); + + $this->assertNoViolation(); + } + + public function getValidRelativeUrls() + { + return array( + array('//google.com'), + array('//symfony.fake/blog/'), + array('//symfony.com/search?type=&q=url+validator'), + ); + } + public function getValidUrls() { return array( @@ -147,6 +171,46 @@ public function testInvalidUrls($url) ->assertRaised(); } + /** + * @dataProvider getInvalidRelativeUrls + * @dataProvider getInvalidUrls + */ + public function testInvalidRelativeUrl($url) + { + $constraint = new Url(array( + 'message' => 'myMessage', + 'relativeProtocol' => true, + )); + + $this->validator->validate($url, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$url.'"') + ->setCode(Url::INVALID_URL_ERROR) + ->assertRaised(); + } + + public function getInvalidRelativeUrls() + { + return array( + array('/google.com'), + array('//goog_le.com'), + array('//google.com::aa'), + array('//google.com:aa'), + array('//127.0.0.1:aa/'), + array('//[::1'), + array('//hello.☎/'), + array('//:password@symfony.com'), + array('//:password@@symfony.com'), + array('//username:passwordsymfony.com'), + array('//usern@me:password@symfony.com'), + array('//example.com/exploit.html?'), + array('//example.com/exploit.html?hel lo'), + array('//example.com/exploit.html?not_a%hex'), + array('//'), + ); + } + public function getInvalidUrls() { return array(
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: