From e66d8f1bef18c3f84c2ec696946c785f9606e758 Mon Sep 17 00:00:00 2001 From: "Israel J. Carberry" Date: Mon, 5 Jun 2017 15:57:58 -0500 Subject: [PATCH] [Validator] Adds support to check specific DNS record type for URL --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + .../Component/Validator/Constraints/Url.php | 16 ++++- .../Validator/Constraints/UrlValidator.php | 26 ++++++- .../Tests/Constraints/UrlValidatorTest.php | 71 ++++++++++++++++++- 4 files changed, 111 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index b35a4824104c..f886b1133a7b 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * not setting the `strict` option of the `Choice` constraint to `true` is deprecated and will throw an exception in Symfony 4.0 + * setting the `checkDNS` option of the `Url` constraint to `true` is deprecated in favor of constant values and will throw an exception in Symfony 4.0 3.3.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Url.php b/src/Symfony/Component/Validator/Constraints/Url.php index 8453a902081b..988dd19136da 100644 --- a/src/Symfony/Component/Validator/Constraints/Url.php +++ b/src/Symfony/Component/Validator/Constraints/Url.php @@ -21,6 +21,20 @@ */ class Url extends Constraint { + const CHECK_DNS_TYPE_ANY = 'ANY'; + const CHECK_DNS_TYPE_NONE = false; + const CHECK_DNS_TYPE_A = 'A'; + const CHECK_DNS_TYPE_A6 = 'A6'; + const CHECK_DNS_TYPE_AAAA = 'AAAA'; + const CHECK_DNS_TYPE_CNAME = 'CNAME'; + const CHECK_DNS_TYPE_MX = 'MX'; + const CHECK_DNS_TYPE_NAPTR = 'NAPTR'; + const CHECK_DNS_TYPE_NS = 'NS'; + const CHECK_DNS_TYPE_PTR = 'PTR'; + const CHECK_DNS_TYPE_SOA = 'SOA'; + const CHECK_DNS_TYPE_SRV = 'SRV'; + const CHECK_DNS_TYPE_TXT = 'TXT'; + const INVALID_URL_ERROR = '57c2f299-1154-4870-89bb-ef3b1f5ad229'; protected static $errorNames = array( @@ -30,5 +44,5 @@ class Url extends Constraint public $message = 'This value is not a valid URL.'; public $dnsMessage = 'The host could not be resolved.'; public $protocols = array('http', 'https'); - public $checkDNS = false; + public $checkDNS = self::CHECK_DNS_TYPE_NONE; } diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 118a8defc146..e011239d56f2 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -13,6 +13,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\InvalidOptionsException; use Symfony\Component\Validator\Exception\UnexpectedTypeException; /** @@ -72,9 +73,32 @@ public function validate($value, Constraint $constraint) } if ($constraint->checkDNS) { + // backwards compatibility + if ($constraint->checkDNS === true) { + $constraint->checkDNS = Url::CHECK_DNS_TYPE_ANY; + @trigger_error(sprintf('Use of the boolean TRUE for the "checkDNS" option in %s is deprecated. Use Url::CHECK_DNS_TYPE_ANY instead.', Url::class), E_USER_DEPRECATED); + } + + if (!in_array($constraint->checkDNS, array( + Url::CHECK_DNS_TYPE_ANY, + Url::CHECK_DNS_TYPE_A, + Url::CHECK_DNS_TYPE_A6, + Url::CHECK_DNS_TYPE_AAAA, + Url::CHECK_DNS_TYPE_CNAME, + Url::CHECK_DNS_TYPE_MX, + Url::CHECK_DNS_TYPE_NAPTR, + Url::CHECK_DNS_TYPE_NS, + Url::CHECK_DNS_TYPE_PTR, + Url::CHECK_DNS_TYPE_SOA, + Url::CHECK_DNS_TYPE_SRV, + Url::CHECK_DNS_TYPE_TXT, + ))) { + throw new InvalidOptionsException(sprintf('Invalid value for option "checkDNS" in constraint %s', get_class($constraint)), array('checkDNS')); + } + $host = parse_url($value, PHP_URL_HOST); - if (!is_string($host) || !checkdnsrr($host, 'ANY')) { + if (!is_string($host) || !checkdnsrr($host, $constraint->checkDNS)) { $this->context->buildViolation($constraint->dnsMessage) ->setParameter('{{ value }}', $this->formatValue($host)) ->setCode(Url::INVALID_URL_ERROR) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index 0459dd02201e..633dcf6d571b 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -203,7 +203,7 @@ public function testCheckDns($violation) DnsMock::withMockedHosts(array('example.com' => array(array('type' => $violation ? '' : 'A')))); $constraint = new Url(array( - 'checkDNS' => true, + 'checkDNS' => 'ANY', 'dnsMessage' => 'myMessage', )); @@ -223,6 +223,75 @@ public function getCheckDns() { return array(array(true), array(false)); } + + /** + * @dataProvider getCheckDnsTypes + * @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts + */ + public function testCheckDnsByType($type) + { + DnsMock::withMockedHosts(array('example.com' => array(array('type' => $type)))); + + $constraint = new Url(array( + 'checkDNS' => $type, + 'dnsMessage' => 'myMessage', + )); + + $this->validator->validate('http://example.com', $constraint); + + $this->assertNoViolation(); + } + + public function getCheckDnsTypes() + { + return array( + array('ANY'), + array('A'), + array('A6'), + array('AAAA'), + array('CNAME'), + array('MX'), + array('NAPTR'), + array('NS'), + array('PTR'), + array('SOA'), + array('SRV'), + array('TXT'), + ); + } + + /** + * @group legacy + */ + public function testCheckDnsWithBoolean() + { + DnsMock::withMockedHosts(array('example.com' => array(array('type' => 'A')))); + + $constraint = new Url(array( + 'checkDNS' => true, + 'dnsMessage' => 'myMessage', + )); + + $this->validator->validate('http://example.com', $constraint); + + $this->assertNoViolation(); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidOptionsException + * @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts + */ + public function testCheckDnsWithInvalidType() + { + DnsMock::withMockedHosts(array('example.com' => array(array('type' => 'A')))); + + $constraint = new Url(array( + 'checkDNS' => 'BOGUS', + 'dnsMessage' => 'myMessage', + )); + + $this->validator->validate('http://example.com', $constraint); + } } class EmailProvider