Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format attribute: do not validate data instances that aren't the instance type to validate #773

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix wrong combined paths when traversing upward, fixes #557 ([#652](https://github.com/jsonrainbow/json-schema/pull/652))
- Correct PHPStan baseline ([#764](https://github.com/jsonrainbow/json-schema/pull/764))
- Correct spacing issue in `README.md` ([#763](https://github.com/jsonrainbow/json-schema/pull/763))
- Format attribute: do not validate data instances that aren't the instance type to validate ([#773](https://github.com/jsonrainbow/json-schema/pull/773))

### Changed
- Bump to minimum PHP 7.2 ([#746](https://github.com/jsonrainbow/json-schema/pull/746))
Expand Down
28 changes: 20 additions & 8 deletions src/JsonSchema/Constraints/FormatConstraint.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function check(&$element, $schema = null, ?JsonPointer $path = null, $i =

switch ($schema->format) {
case 'date':
if (!$date = $this->validateDateTime($element, 'Y-m-d')) {
if (is_string($element) && !$date = $this->validateDateTime($element, 'Y-m-d')) {
$this->addError(ConstraintError::FORMAT_DATE(), $path, [
'date' => $element,
'format' => $schema->format
Expand All @@ -45,7 +45,7 @@ public function check(&$element, $schema = null, ?JsonPointer $path = null, $i =
break;

case 'time':
if (!$this->validateDateTime($element, 'H:i:s')) {
if (is_string($element) && !$this->validateDateTime($element, 'H:i:s')) {
$this->addError(ConstraintError::FORMAT_TIME(), $path, [
'time' => json_encode($element),
'format' => $schema->format,
Expand All @@ -55,7 +55,7 @@ public function check(&$element, $schema = null, ?JsonPointer $path = null, $i =
break;

case 'date-time':
if (null === Rfc3339::createFromString($element)) {
if (is_string($element) && null === Rfc3339::createFromString($element)) {
$this->addError(ConstraintError::FORMAT_DATE_TIME(), $path, [
'dateTime' => json_encode($element),
'format' => $schema->format
Expand Down Expand Up @@ -101,14 +101,14 @@ public function check(&$element, $schema = null, ?JsonPointer $path = null, $i =
break;

case 'uri':
if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
if (is_string($element) && null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
$this->addError(ConstraintError::FORMAT_URL(), $path, ['format' => $schema->format]);
}
break;

case 'uriref':
case 'uri-reference':
if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
if (is_string($element) && null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
// 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.
Expand All @@ -133,20 +133,20 @@ public function check(&$element, $schema = null, ?JsonPointer $path = null, $i =
break;

case 'email':
if (null === filter_var($element, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE | FILTER_FLAG_EMAIL_UNICODE)) {
if (is_string($element) && null === filter_var($element, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE | FILTER_FLAG_EMAIL_UNICODE)) {
$this->addError(ConstraintError::FORMAT_EMAIL(), $path, ['format' => $schema->format]);
}
break;

case 'ip-address':
case 'ipv4':
if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
if (is_string($element) && null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
$this->addError(ConstraintError::FORMAT_IP(), $path, ['format' => $schema->format]);
}
break;

case 'ipv6':
if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
if (is_string($element) && null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
$this->addError(ConstraintError::FORMAT_IP(), $path, ['format' => $schema->format]);
}
break;
Expand Down Expand Up @@ -186,11 +186,19 @@ protected function validateDateTime($datetime, $format)

protected function validateRegex($regex)
{
if (!is_string($regex)) {
return true;
}

return false !== @preg_match(self::jsonPatternToPhpRegex($regex), '');
}

protected function validateColor($color)
{
if (!is_string($color)) {
return true;
}

if (in_array(strtolower($color), ['aqua', 'black', 'blue', 'fuchsia',
'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'orange', 'purple',
'red', 'silver', 'teal', 'white', 'yellow'])) {
Expand All @@ -215,6 +223,10 @@ protected function validatePhone($phone)

protected function validateHostname($host)
{
if (!is_string($host)) {
return true;
}

$hostnameRegex = '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/i';

return preg_match($hostnameRegex, $host);
Expand Down
29 changes: 29 additions & 0 deletions tests/Constraints/FormatTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,14 @@ public function getValidFormats(): array
return [
['2001-01-23', 'date'],
['2000-02-29', 'date'],
[42, 'date'],
[4.2, 'date'],

['12:22:01', 'time'],
['00:00:00', 'time'],
['23:59:59', 'time'],
[42, 'time'],
[4.2, 'time'],

['2000-05-01T12:12:12Z', 'date-time'],
['2000-05-01T12:12:12+0100', 'date-time'],
Expand All @@ -114,6 +118,8 @@ public function getValidFormats(): array
['2000-05-01T12:12:12.0Z', 'date-time'],
['2000-05-01T12:12:12.000Z', 'date-time'],
['2000-05-01T12:12:12.000000Z', 'date-time'],
[42, 'date-time'],
[4.2, 'date-time'],

['0', 'utc-millisec'],

Expand All @@ -136,6 +142,8 @@ public function getValidFormats(): array
['yellow', 'color'],
['#fff', 'color'],
['#00cc00', 'color'],
[42, 'color'],
[4.2, 'color'],

['background: blue', 'style'],
['color: #000;', 'style'],
Expand All @@ -149,18 +157,39 @@ public function getValidFormats(): array
['./relative:PathReference/', 'uri-reference'],
['relativePathReference/', 'uri-reference'],
['relative/Path:Reference/', 'uri-reference'],
[42, 'uri-reference'],
[4.2, 'uri-reference'],

['[email protected]', 'email'],
[42, 'email'],
[4.2, 'email'],

['10.10.10.10', 'ip-address'],
['127.0.0.1', 'ip-address'],
[42, 'ip-address'],
[4.2, 'ip-address'],

['127.0.0.1', 'ipv4'],
[42, 'ipv4'],
[4.2, 'ipv4'],

['::ff', 'ipv6'],
[42, 'ipv6'],
[4.2, 'ipv6'],

['www.example.com', 'host-name'],
['3v4l.org', 'host-name'],
['a-valid-host.com', 'host-name'],
['localhost', 'host-name'],
[42, 'host-name'],
[4.2, 'host-name'],

['www.example.com', 'hostname'],
['3v4l.org', 'hostname'],
['a-valid-host.com', 'hostname'],
['localhost', 'hostname'],
[42, 'hostname'],
[4.2, 'hostname'],

['anything', '*'],
['unknown', '*'],
Expand Down
Loading