From 5e92df010b5022ee2e4c00cf2f48bba7de05c686 Mon Sep 17 00:00:00 2001 From: Erayd Date: Thu, 23 Feb 2017 11:27:59 +1300 Subject: [PATCH] Fix non-conforming URL validation Json schema spec says URLs are validated as per RFC-3986, but PHP's FILTER_VALIDATE_URL can't cope with relative path references, which are explicitly allowed. See https://tools.ietf.org/html/rfc3986#section-4.2 for further information. --- .../Constraints/FormatConstraint.php | 21 ++++++++++++++++++- tests/Constraints/FormatTest.php | 4 ++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/JsonSchema/Constraints/FormatConstraint.php b/src/JsonSchema/Constraints/FormatConstraint.php index 5ea9f95b..839debcc 100644 --- a/src/JsonSchema/Constraints/FormatConstraint.php +++ b/src/JsonSchema/Constraints/FormatConstraint.php @@ -81,7 +81,26 @@ public function check(&$element, $schema = null, JsonPointer $path = null, $i = case 'uri': if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) { - $this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format)); + // FILTER_VALIDATE_URL does not conform to RFC-3986, and cannot handle relative URLs, but + // the json-schema spec uses RFC-3986, so need a bit of hackery to properly validate them. + // See https://tools.ietf.org/html/rfc3986#section-4.2 for additional information. + if (substr($element, 0, 2) === '//') { // network-path reference + $validURL = filter_var('scheme:' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE); + } elseif (substr($element, 0, 1) === '/') { // absolute-path reference + $validURL = filter_var('scheme://host' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE); + } elseif (strlen($element)) { // relative-path reference + $pathParts = explode('/', $element, 2); + if ($pathParts[0][0] !== '.' && strpos($pathParts[0], ':') !== false) { + $validURL = null; + } else { + $validURL = filter_var('scheme://host/' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE); + } + } else { + $validURL = null; + } + if ($validURL === null) { + $this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format)); + } } break; diff --git a/tests/Constraints/FormatTest.php b/tests/Constraints/FormatTest.php index a240b6df..f590b3f3 100644 --- a/tests/Constraints/FormatTest.php +++ b/tests/Constraints/FormatTest.php @@ -124,6 +124,9 @@ public function getValidFormats() array('555 320 1212', 'phone'), array('http://bluebox.org', 'uri'), + array('//bluebox.org', 'uri'), + array('/absolutePathReference/', 'uri'), + array('relativePathReference/', 'uri'), array('info@something.edu', 'email'), @@ -173,6 +176,7 @@ public function getInvalidFormats() array('1 123 4424', 'phone'), array('htt:/bluebox.org', 'uri'), + array('', 'uri'), array('info@somewhere', 'email'),