Skip to main content
schema decode is already done
Source Link
<?php

function validateJsonSchema($json, $schema, $checkRequired=true)
{
    $decodeIfNeeded=function ($maybeJson) {
        if (is_string($maybeJson)) {
            try {
                return json_decode($maybeJson, false, 512, JSON_THROW_ON_ERROR);
            } catch (Exception $e) {
                return false;
            }
        } else {
            return $maybeJson;
        }
    };
    $json = $decodeIfNeeded($json);
    $schema = $decodeIfNeeded($schema);
    if (!$json||!$schema) {
        return "failed to decode json";
    }
    if (is_string($schema)) {
        try {
            $schema=json_decode($schema, false, 512, JSON_THROW_ON_ERROR);
        } catch (Exception $e) {
            return "schema cannot be decoded";
        }
    }
    if ($checkRequired) {
        $missingRequiredKeys=[];
        foreach ($schema as $schemaKey => $schemaValue) {
            if (property_exists($schemaValue, "required")
                &&$schemaValue->required) {
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach ($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if ($type=="object") {//Needed to handle array situations
            foreach ($schema as $schemaKey => $schemaValue) {
                if (!property_exists($schemaValue, "type")
                    ||!is_string($schemaValue->type)) {
                    $res=validateJsonSchema($jsonValue, $schemaValue, $checkRequired);
                    if ($res!="") {
                        return $res;
                    }
                }
            }
        } else {
            $schemaProperties=null;
            if (!is_array($schema)) {
                if ($checkRequired) {
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if ($missingKey!== false) {
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if (!is_array($schema)&&!property_exists($schema, $jsonKey)) {
                    return "key not in schema";
                }
                $schemaProperties=$schema->$jsonKey;
            } else {
                foreach ($schema as $schemaKey => $schemaValue) {
                    if (property_exists($schemaValue, "type")
                        &&is_string($schemaValue->type)) {//This is a single value within an array
                        if ($type==$schemaValue->type) {
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if (!(is_null($jsonValue)&&property_exists($schemaProperties, "nullable")&&$schemaProperties->nullable)) {
                if (is_null($schemaProperties)) {
                    return "type not allowed: ".$type;
                }
                if ($schemaProperties->type!=$type) {
                    if (!($type=="integer"&&$schemaProperties->type=="double")) {//integer instead of double is acceptable
                        return "type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey;
                    }
                }
                $getSchemaProperty=function ($schemaProperties, $name) {
                    if (property_exists($schemaProperties, $name)) {
                        return $schemaProperties->$name;
                    }
                    if ($name=="min") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MIN;
                        }
                        return PHP_INT_MIN;
                    }
                    if ($name=="max") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MAX;
                        }
                        return PHP_INT_MAX;
                    }
                    return null;
                };
                switch ($schemaProperties->type) {
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue, $getSchemaProperty($schemaProperties, "data"), $checkRequired);
                        if ($res!="") {
                            return $res;
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return "unknown type ".$schemaProperties->type;
                    break;
                }
                $min=$getSchemaProperty($schemaProperties, "min");
                $max=$getSchemaProperty($schemaProperties, "max");
                if ($count<$min) {
                    return "too short";
                }
                if ($count>$max) {
                    return "too long";
                }
            }
        }
    }
    if ($checkRequired&&count($missingRequiredKeys)>0) {
        return "missing required key(s)";
    }
    return "";
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json, $schema)."\n");
?>
<?php

function validateJsonSchema($json, $schema, $checkRequired=true)
{
    $decodeIfNeeded=function ($maybeJson) {
        if (is_string($maybeJson)) {
            try {
                return json_decode($maybeJson, false, 512, JSON_THROW_ON_ERROR);
            } catch (Exception $e) {
                return false;
            }
        } else {
            return $maybeJson;
        }
    };
    $json = $decodeIfNeeded($json);
    $schema = $decodeIfNeeded($schema);
    if (!$json||!$schema) {
        return "failed to decode json";
    }
    if (is_string($schema)) {
        try {
            $schema=json_decode($schema, false, 512, JSON_THROW_ON_ERROR);
        } catch (Exception $e) {
            return "schema cannot be decoded";
        }
    }
    if ($checkRequired) {
        $missingRequiredKeys=[];
        foreach ($schema as $schemaKey => $schemaValue) {
            if (property_exists($schemaValue, "required")
                &&$schemaValue->required) {
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach ($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if ($type=="object") {//Needed to handle array situations
            foreach ($schema as $schemaKey => $schemaValue) {
                if (!property_exists($schemaValue, "type")
                    ||!is_string($schemaValue->type)) {
                    $res=validateJsonSchema($jsonValue, $schemaValue, $checkRequired);
                    if ($res!="") {
                        return $res;
                    }
                }
            }
        } else {
            $schemaProperties=null;
            if (!is_array($schema)) {
                if ($checkRequired) {
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if ($missingKey!== false) {
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if (!is_array($schema)&&!property_exists($schema, $jsonKey)) {
                    return "key not in schema";
                }
                $schemaProperties=$schema->$jsonKey;
            } else {
                foreach ($schema as $schemaKey => $schemaValue) {
                    if (property_exists($schemaValue, "type")
                        &&is_string($schemaValue->type)) {//This is a single value within an array
                        if ($type==$schemaValue->type) {
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if (!(is_null($jsonValue)&&property_exists($schemaProperties, "nullable")&&$schemaProperties->nullable)) {
                if (is_null($schemaProperties)) {
                    return "type not allowed: ".$type;
                }
                if ($schemaProperties->type!=$type) {
                    if (!($type=="integer"&&$schemaProperties->type=="double")) {//integer instead of double is acceptable
                        return "type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey;
                    }
                }
                $getSchemaProperty=function ($schemaProperties, $name) {
                    if (property_exists($schemaProperties, $name)) {
                        return $schemaProperties->$name;
                    }
                    if ($name=="min") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MIN;
                        }
                        return PHP_INT_MIN;
                    }
                    if ($name=="max") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MAX;
                        }
                        return PHP_INT_MAX;
                    }
                    return null;
                };
                switch ($schemaProperties->type) {
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue, $getSchemaProperty($schemaProperties, "data"), $checkRequired);
                        if ($res!="") {
                            return $res;
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return "unknown type ".$schemaProperties->type;
                    break;
                }
                $min=$getSchemaProperty($schemaProperties, "min");
                $max=$getSchemaProperty($schemaProperties, "max");
                if ($count<$min) {
                    return "too short";
                }
                if ($count>$max) {
                    return "too long";
                }
            }
        }
    }
    if ($checkRequired&&count($missingRequiredKeys)>0) {
        return "missing required key(s)";
    }
    return "";
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json, $schema)."\n");
?>
<?php

function validateJsonSchema($json, $schema, $checkRequired=true)
{
    $decodeIfNeeded=function ($maybeJson) {
        if (is_string($maybeJson)) {
            try {
                return json_decode($maybeJson, false, 512, JSON_THROW_ON_ERROR);
            } catch (Exception $e) {
                return false;
            }
        } else {
            return $maybeJson;
        }
    };
    $json = $decodeIfNeeded($json);
    $schema = $decodeIfNeeded($schema);
    if (!$json||!$schema) {
        return "failed to decode json";
    }
    if ($checkRequired) {
        $missingRequiredKeys=[];
        foreach ($schema as $schemaKey => $schemaValue) {
            if (property_exists($schemaValue, "required")
                &&$schemaValue->required) {
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach ($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if ($type=="object") {//Needed to handle array situations
            foreach ($schema as $schemaKey => $schemaValue) {
                if (!property_exists($schemaValue, "type")
                    ||!is_string($schemaValue->type)) {
                    $res=validateJsonSchema($jsonValue, $schemaValue, $checkRequired);
                    if ($res!="") {
                        return $res;
                    }
                }
            }
        } else {
            $schemaProperties=null;
            if (!is_array($schema)) {
                if ($checkRequired) {
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if ($missingKey!== false) {
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if (!is_array($schema)&&!property_exists($schema, $jsonKey)) {
                    return "key not in schema";
                }
                $schemaProperties=$schema->$jsonKey;
            } else {
                foreach ($schema as $schemaKey => $schemaValue) {
                    if (property_exists($schemaValue, "type")
                        &&is_string($schemaValue->type)) {//This is a single value within an array
                        if ($type==$schemaValue->type) {
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if (!(is_null($jsonValue)&&property_exists($schemaProperties, "nullable")&&$schemaProperties->nullable)) {
                if (is_null($schemaProperties)) {
                    return "type not allowed: ".$type;
                }
                if ($schemaProperties->type!=$type) {
                    if (!($type=="integer"&&$schemaProperties->type=="double")) {//integer instead of double is acceptable
                        return "type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey;
                    }
                }
                $getSchemaProperty=function ($schemaProperties, $name) {
                    if (property_exists($schemaProperties, $name)) {
                        return $schemaProperties->$name;
                    }
                    if ($name=="min") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MIN;
                        }
                        return PHP_INT_MIN;
                    }
                    if ($name=="max") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MAX;
                        }
                        return PHP_INT_MAX;
                    }
                    return null;
                };
                switch ($schemaProperties->type) {
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue, $getSchemaProperty($schemaProperties, "data"), $checkRequired);
                        if ($res!="") {
                            return $res;
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return "unknown type ".$schemaProperties->type;
                    break;
                }
                $min=$getSchemaProperty($schemaProperties, "min");
                $max=$getSchemaProperty($schemaProperties, "max");
                if ($count<$min) {
                    return "too short";
                }
                if ($count>$max) {
                    return "too long";
                }
            }
        }
    }
    if ($checkRequired&&count($missingRequiredKeys)>0) {
        return "missing required key(s)";
    }
    return "";
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json, $schema)."\n");
?>
just removed parentheses on a return
Source Link
<?php

function validateJsonSchema($json, $schema, $checkRequired=true)
{
    $decodeIfNeeded=function ($maybeJson) {
        if (is_string($maybeJson)) {
            try {
                return json_decode($maybeJson, false, 512, JSON_THROW_ON_ERROR);
            } catch (Exception $e) {
                return false;
            }
        } else {
            return $maybeJson;
        }
    };
    $json = $decodeIfNeeded($json);
    $schema = $decodeIfNeeded($schema);
    if (!$json||!$schema) {
        return( "failed to decode json");json";
    }
    if (is_string($schema)) {
        try {
            $schema=json_decode($schema, false, 512, JSON_THROW_ON_ERROR);
        } catch (Exception $e) {
            return "schema cannot be decoded";
        }
    }
    if ($checkRequired) {
        $missingRequiredKeys=[];
        foreach ($schema as $schemaKey => $schemaValue) {
            if (property_exists($schemaValue, "required")
                &&$schemaValue->required) {
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach ($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if ($type=="object") {//Needed to handle array situations
            foreach ($schema as $schemaKey => $schemaValue) {
                if (!property_exists($schemaValue, "type")
                    ||!is_string($schemaValue->type)) {
                    $res=validateJsonSchema($jsonValue, $schemaValue, $checkRequired);
                    if ($res!="") {
                        return $res;
                    }
                }
            }
        } else {
            $schemaProperties=null;
            if (!is_array($schema)) {
                if ($checkRequired) {
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if ($missingKey!== false) {
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if (!is_array($schema)&&!property_exists($schema, $jsonKey)) {
                    return "key not in schema";
                }
                $schemaProperties=$schema->$jsonKey;
            } else {
                foreach ($schema as $schemaKey => $schemaValue) {
                    if (property_exists($schemaValue, "type")
                        &&is_string($schemaValue->type)) {//This is a single value within an array
                        if ($type==$schemaValue->type) {
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if (!(is_null($jsonValue)&&property_exists($schemaProperties, "nullable")&&$schemaProperties->nullable)) {
                if (is_null($schemaProperties)) {
                    return "type not allowed: ".$type;
                }
                if ($schemaProperties->type!=$type) {
                    if (!($type=="integer"&&$schemaProperties->type=="double")) {//integer instead of double is acceptable
                        return "type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey;
                    }
                }
                $getSchemaProperty=function ($schemaProperties, $name) {
                    if (property_exists($schemaProperties, $name)) {
                        return $schemaProperties->$name;
                    }
                    if ($name=="min") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MIN;
                        }
                        return PHP_INT_MIN;
                    }
                    if ($name=="max") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MAX;
                        }
                        return PHP_INT_MAX;
                    }
                    return null;
                };
                switch ($schemaProperties->type) {
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue, $getSchemaProperty($schemaProperties, "data"), $checkRequired);
                        if ($res!="") {
                            return $res;
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return "unknown type ".$schemaProperties->type;
                    break;
                }
                $min=$getSchemaProperty($schemaProperties, "min");
                $max=$getSchemaProperty($schemaProperties, "max");
                if ($count<$min) {
                    return "too short";
                }
                if ($count>$max) {
                    return "too long";
                }
            }
        }
    }
    if ($checkRequired&&count($missingRequiredKeys)>0) {
        return "missing required key(s)";
    }
    return "";
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json, $schema)."\n");
?>
<?php

function validateJsonSchema($json, $schema, $checkRequired=true)
{
    $decodeIfNeeded=function ($maybeJson) {
        if (is_string($maybeJson)) {
            try {
                return json_decode($maybeJson, false, 512, JSON_THROW_ON_ERROR);
            } catch (Exception $e) {
                return false;
            }
        } else {
            return $maybeJson;
        }
    };
    $json = $decodeIfNeeded($json);
    $schema = $decodeIfNeeded($schema);
    if (!$json||!$schema) {
        return("failed to decode json");
    }
    if (is_string($schema)) {
        try {
            $schema=json_decode($schema, false, 512, JSON_THROW_ON_ERROR);
        } catch (Exception $e) {
            return "schema cannot be decoded";
        }
    }
    if ($checkRequired) {
        $missingRequiredKeys=[];
        foreach ($schema as $schemaKey => $schemaValue) {
            if (property_exists($schemaValue, "required")
                &&$schemaValue->required) {
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach ($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if ($type=="object") {//Needed to handle array situations
            foreach ($schema as $schemaKey => $schemaValue) {
                if (!property_exists($schemaValue, "type")
                    ||!is_string($schemaValue->type)) {
                    $res=validateJsonSchema($jsonValue, $schemaValue, $checkRequired);
                    if ($res!="") {
                        return $res;
                    }
                }
            }
        } else {
            $schemaProperties=null;
            if (!is_array($schema)) {
                if ($checkRequired) {
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if ($missingKey!== false) {
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if (!is_array($schema)&&!property_exists($schema, $jsonKey)) {
                    return "key not in schema";
                }
                $schemaProperties=$schema->$jsonKey;
            } else {
                foreach ($schema as $schemaKey => $schemaValue) {
                    if (property_exists($schemaValue, "type")
                        &&is_string($schemaValue->type)) {//This is a single value within an array
                        if ($type==$schemaValue->type) {
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if (!(is_null($jsonValue)&&property_exists($schemaProperties, "nullable")&&$schemaProperties->nullable)) {
                if (is_null($schemaProperties)) {
                    return "type not allowed: ".$type;
                }
                if ($schemaProperties->type!=$type) {
                    if (!($type=="integer"&&$schemaProperties->type=="double")) {//integer instead of double is acceptable
                        return "type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey;
                    }
                }
                $getSchemaProperty=function ($schemaProperties, $name) {
                    if (property_exists($schemaProperties, $name)) {
                        return $schemaProperties->$name;
                    }
                    if ($name=="min") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MIN;
                        }
                        return PHP_INT_MIN;
                    }
                    if ($name=="max") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MAX;
                        }
                        return PHP_INT_MAX;
                    }
                    return null;
                };
                switch ($schemaProperties->type) {
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue, $getSchemaProperty($schemaProperties, "data"), $checkRequired);
                        if ($res!="") {
                            return $res;
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return "unknown type ".$schemaProperties->type;
                    break;
                }
                $min=$getSchemaProperty($schemaProperties, "min");
                $max=$getSchemaProperty($schemaProperties, "max");
                if ($count<$min) {
                    return "too short";
                }
                if ($count>$max) {
                    return "too long";
                }
            }
        }
    }
    if ($checkRequired&&count($missingRequiredKeys)>0) {
        return "missing required key(s)";
    }
    return "";
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json, $schema)."\n");
?>
<?php

function validateJsonSchema($json, $schema, $checkRequired=true)
{
    $decodeIfNeeded=function ($maybeJson) {
        if (is_string($maybeJson)) {
            try {
                return json_decode($maybeJson, false, 512, JSON_THROW_ON_ERROR);
            } catch (Exception $e) {
                return false;
            }
        } else {
            return $maybeJson;
        }
    };
    $json = $decodeIfNeeded($json);
    $schema = $decodeIfNeeded($schema);
    if (!$json||!$schema) {
        return "failed to decode json";
    }
    if (is_string($schema)) {
        try {
            $schema=json_decode($schema, false, 512, JSON_THROW_ON_ERROR);
        } catch (Exception $e) {
            return "schema cannot be decoded";
        }
    }
    if ($checkRequired) {
        $missingRequiredKeys=[];
        foreach ($schema as $schemaKey => $schemaValue) {
            if (property_exists($schemaValue, "required")
                &&$schemaValue->required) {
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach ($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if ($type=="object") {//Needed to handle array situations
            foreach ($schema as $schemaKey => $schemaValue) {
                if (!property_exists($schemaValue, "type")
                    ||!is_string($schemaValue->type)) {
                    $res=validateJsonSchema($jsonValue, $schemaValue, $checkRequired);
                    if ($res!="") {
                        return $res;
                    }
                }
            }
        } else {
            $schemaProperties=null;
            if (!is_array($schema)) {
                if ($checkRequired) {
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if ($missingKey!== false) {
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if (!is_array($schema)&&!property_exists($schema, $jsonKey)) {
                    return "key not in schema";
                }
                $schemaProperties=$schema->$jsonKey;
            } else {
                foreach ($schema as $schemaKey => $schemaValue) {
                    if (property_exists($schemaValue, "type")
                        &&is_string($schemaValue->type)) {//This is a single value within an array
                        if ($type==$schemaValue->type) {
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if (!(is_null($jsonValue)&&property_exists($schemaProperties, "nullable")&&$schemaProperties->nullable)) {
                if (is_null($schemaProperties)) {
                    return "type not allowed: ".$type;
                }
                if ($schemaProperties->type!=$type) {
                    if (!($type=="integer"&&$schemaProperties->type=="double")) {//integer instead of double is acceptable
                        return "type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey;
                    }
                }
                $getSchemaProperty=function ($schemaProperties, $name) {
                    if (property_exists($schemaProperties, $name)) {
                        return $schemaProperties->$name;
                    }
                    if ($name=="min") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MIN;
                        }
                        return PHP_INT_MIN;
                    }
                    if ($name=="max") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MAX;
                        }
                        return PHP_INT_MAX;
                    }
                    return null;
                };
                switch ($schemaProperties->type) {
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue, $getSchemaProperty($schemaProperties, "data"), $checkRequired);
                        if ($res!="") {
                            return $res;
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return "unknown type ".$schemaProperties->type;
                    break;
                }
                $min=$getSchemaProperty($schemaProperties, "min");
                $max=$getSchemaProperty($schemaProperties, "max");
                if ($count<$min) {
                    return "too short";
                }
                if ($count>$max) {
                    return "too long";
                }
            }
        }
    }
    if ($checkRequired&&count($missingRequiredKeys)>0) {
        return "missing required key(s)";
    }
    return "";
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json, $schema)."\n");
?>
Followed @mickmackusa recommendations.
Source Link
<?php

function validateJsonSchema($json, $schema, $checkRequired=true)
{
    $decodeIfNeeded=function ($maybeJson) {
        if (is_string($json$maybeJson)) {
            try {
            $json=json_decode    return json_decode($json$maybeJson, false, 512, JSON_THROW_ON_ERROR);
        }
       } catch (Exception $e) {
                return("json cannotfalse;
 be decoded");          }
        } else {
            return $maybeJson;
        }
    };
    $json = $decodeIfNeeded($json);
    $schema = $decodeIfNeeded($schema);
    if (!$json||!$schema) {
        return("failed to decode json");
    }
    if (is_string($schema)) {
        try {
            $schema=json_decode($schema, false, 512, JSON_THROW_ON_ERROR);
        }
        catch (Exception $e) {
            return( "schema cannot be decoded");decoded";
        }
    }
    if ($checkRequired) {
        $missingRequiredKeys=[];
        foreach ($schema as $schemaKey => $schemaValue) {
            if (property_exists($schemaValue, "required")
                &&$schemaValue->{"required"}>required) {
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach ($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if ($type=="object") {//Needed to handle array situations
            foreach ($schema as $schemaKey => $schemaValue) {
                if (!property_exists($schemaValue, "type")
                    ||!is_string($schemaValue->type)) {
                    $res=validateJsonSchema($jsonValue, $schemaValue, $checkRequired);
                    if ($res!="") {
                        return($res); $res;
                    }
                }
            }
        }
        else {
            $schemaProperties=null;
            if (!is_array($schema)) {
                if ($checkRequired) {
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if ($missingKey!== FALSEfalse) {
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if (!is_array($schema)&&!property_exists($schema, $jsonKey)) {
                    return( "key not in schema");schema";
                }
                $schemaProperties=$schema->$jsonKey;
            }
            else {
                foreach ($schema as $schemaKey => $schemaValue) {
                    if (property_exists($schemaValue, "type")
                        &&is_string($schemaValue->type)) {//This is a single value within an array
                        if ($type==$schemaValue->type) {
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if (!(is_null($jsonValue)&&property_exists($schemaProperties, "nullable")&&$schemaProperties->nullable)) {
                if (is_null($schemaProperties)) {
                    return( "type not allowed: ".$type);$type;
                }
                if ($schemaProperties->type!=$type) {
                    if (!($type=="integer"&&$schemaProperties->type=="double")) {//integer instead of double is acceptable
                        return( "type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey);$jsonKey;
                    }
                }
                $getSchemaProperty=function ($schemaProperties, $name) {
                    if (property_exists($schemaProperties, $name)) {
                        return( $schemaProperties->$name);>$name;
                    }
                    if ($name=="min") {
                        if ($schemaProperties->type=="double") {
                            return(PHP_FLOAT_MIN); PHP_FLOAT_MIN;
                        }
                        return(PHP_INT_MIN); PHP_INT_MIN;
                    }
                    if ($name=="max") {
                        if ($schemaProperties->type=="double") {
                            return(PHP_FLOAT_MAX); PHP_FLOAT_MAX;
                        }
                        return(PHP_INT_MAX); PHP_INT_MAX;
                    }
                    return(null); null;
                };
                switch ($schemaProperties->type) {
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                        $count=$jsonValue;
                    break;
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue, $getSchemaProperty($schemaProperties, "data"), $checkRequired);
                        if ($res!="") {
                            return($res); $res;
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return( "unknown type ".$schemaProperties->type);>type;
                    break;
                }
                $min=$getSchemaProperty($schemaProperties, "min");
                $max=$getSchemaProperty($schemaProperties, "max");
                if ($count<$min) {
                    return( "too short");short";
                }
                if ($count>$max) {
                    return( "too long");long";
                }
            }
        }
    }
    if ($checkRequired&&count($missingRequiredKeys)>0) {
        return( "missing required key(s)");";
    }
    return(""); "";
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json, $schema)."\n");
?>
<?php

function validateJsonSchema($json,$schema,$checkRequired=true){
    if(is_string($json)){
        try{
            $json=json_decode($json,false,512,JSON_THROW_ON_ERROR);
        }
        catch(Exception $e){
            return("json cannot be decoded");
        }
    }
    if(is_string($schema)){
        try{
            $schema=json_decode($schema,false,512,JSON_THROW_ON_ERROR);
        }
        catch(Exception $e){
            return("schema cannot be decoded");
        }
    }
    if($checkRequired){
        $missingRequiredKeys=[];
        foreach($schema as $schemaKey => $schemaValue) {
            if(property_exists($schemaValue,"required")
                &&$schemaValue->{"required"}){
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if($type=="object"){//Needed to handle array situations
            foreach($schema as $schemaKey => $schemaValue) {
                if(!property_exists($schemaValue,"type")
                    ||!is_string($schemaValue->type)){
                    $res=validateJsonSchema($jsonValue,$schemaValue,$checkRequired);
                    if($res!=""){
                        return($res);
                    }
                }
            }
        }
        else{
            $schemaProperties=null;
            if(!is_array($schema)){
                if($checkRequired){
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if($missingKey!== FALSE){
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if(!is_array($schema)&&!property_exists($schema,$jsonKey)){
                    return("key not in schema");
                }
                $schemaProperties=$schema->$jsonKey;
            }
            else{
                foreach($schema as $schemaKey => $schemaValue) {
                    if(property_exists($schemaValue,"type")
                        &&is_string($schemaValue->type)){//This is a single value within an array
                        if($type==$schemaValue->type){
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if(!(is_null($jsonValue)&&property_exists($schemaProperties,"nullable")&&$schemaProperties->nullable)){
                if(is_null($schemaProperties)){
                    return("type not allowed: ".$type);
                }
                if($schemaProperties->type!=$type){
                    if(!($type=="integer"&&$schemaProperties->type=="double")){//integer instead of double is acceptable
                        return("type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey);
                    }
                }
                $getSchemaProperty=function($schemaProperties,$name){
                    if(property_exists($schemaProperties,$name)){
                        return($schemaProperties->$name);
                    }
                    if($name=="min"){
                        if($schemaProperties->type=="double"){
                            return(PHP_FLOAT_MIN);
                        }
                        return(PHP_INT_MIN);
                    }
                    if($name=="max"){
                        if($schemaProperties->type=="double"){
                            return(PHP_FLOAT_MAX);
                        }
                        return(PHP_INT_MAX);
                    }
                    return(null);
                };
                switch($schemaProperties->type){
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                        $count=$jsonValue;
                    break;
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue,$getSchemaProperty($schemaProperties,"data"),$checkRequired);
                        if($res!=""){
                            return($res);
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return("unknown type ".$schemaProperties->type);
                    break;
                }
                $min=$getSchemaProperty($schemaProperties,"min");
                $max=$getSchemaProperty($schemaProperties,"max");
                if($count<$min){
                    return("too short");
                }
                if($count>$max){
                    return("too long");
                }
            }
        }
    }
    if($checkRequired&&count($missingRequiredKeys)>0){
        return("missing required key(s)");
    }
    return("");
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json,$schema)."\n");
?>
<?php

function validateJsonSchema($json, $schema, $checkRequired=true)
{
    $decodeIfNeeded=function ($maybeJson) {
        if (is_string($maybeJson)) {
            try {
                return json_decode($maybeJson, false, 512, JSON_THROW_ON_ERROR);
            } catch (Exception $e) {
                return false;
            }
        } else {
            return $maybeJson;
        }
    };
    $json = $decodeIfNeeded($json);
    $schema = $decodeIfNeeded($schema);
    if (!$json||!$schema) {
        return("failed to decode json");
    }
    if (is_string($schema)) {
        try {
            $schema=json_decode($schema, false, 512, JSON_THROW_ON_ERROR);
        } catch (Exception $e) {
            return "schema cannot be decoded";
        }
    }
    if ($checkRequired) {
        $missingRequiredKeys=[];
        foreach ($schema as $schemaKey => $schemaValue) {
            if (property_exists($schemaValue, "required")
                &&$schemaValue->required) {
                $missingRequiredKeys[]=$schemaKey;
            }
        }
    }
    foreach ($json as $jsonKey => $jsonValue) {
        $type=gettype($jsonValue);
        if ($type=="object") {//Needed to handle array situations
            foreach ($schema as $schemaKey => $schemaValue) {
                if (!property_exists($schemaValue, "type")
                    ||!is_string($schemaValue->type)) {
                    $res=validateJsonSchema($jsonValue, $schemaValue, $checkRequired);
                    if ($res!="") {
                        return $res;
                    }
                }
            }
        } else {
            $schemaProperties=null;
            if (!is_array($schema)) {
                if ($checkRequired) {
                    $missingKey = array_search($jsonKey, $missingRequiredKeys, true);
                    if ($missingKey!== false) {
                        unset($missingRequiredKeys[$missingKey]);
                    }
                }
                if (!is_array($schema)&&!property_exists($schema, $jsonKey)) {
                    return "key not in schema";
                }
                $schemaProperties=$schema->$jsonKey;
            } else {
                foreach ($schema as $schemaKey => $schemaValue) {
                    if (property_exists($schemaValue, "type")
                        &&is_string($schemaValue->type)) {//This is a single value within an array
                        if ($type==$schemaValue->type) {
                            $schemaProperties=$schemaValue;
                            break;
                        }
                    }
                }
            }
            if (!(is_null($jsonValue)&&property_exists($schemaProperties, "nullable")&&$schemaProperties->nullable)) {
                if (is_null($schemaProperties)) {
                    return "type not allowed: ".$type;
                }
                if ($schemaProperties->type!=$type) {
                    if (!($type=="integer"&&$schemaProperties->type=="double")) {//integer instead of double is acceptable
                        return "type mismatch, expected: ".$schemaProperties->type." instead of ".$type." for ".$jsonKey;
                    }
                }
                $getSchemaProperty=function ($schemaProperties, $name) {
                    if (property_exists($schemaProperties, $name)) {
                        return $schemaProperties->$name;
                    }
                    if ($name=="min") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MIN;
                        }
                        return PHP_INT_MIN;
                    }
                    if ($name=="max") {
                        if ($schemaProperties->type=="double") {
                            return PHP_FLOAT_MAX;
                        }
                        return PHP_INT_MAX;
                    }
                    return null;
                };
                switch ($schemaProperties->type) {
                    case "string":
                        $count=strlen($jsonValue);
                    break;
                    case "integer":
                    case "double":
                        $count=$jsonValue;
                    break;
                    case "boolean":
                        $count=0;
                    break;
                    case "array":
                        $res=validateJsonSchema($jsonValue, $getSchemaProperty($schemaProperties, "data"), $checkRequired);
                        if ($res!="") {
                            return $res;
                        }
                        $count=count($jsonValue);
                    break;
                    default:
                        return "unknown type ".$schemaProperties->type;
                    break;
                }
                $min=$getSchemaProperty($schemaProperties, "min");
                $max=$getSchemaProperty($schemaProperties, "max");
                if ($count<$min) {
                    return "too short";
                }
                if ($count>$max) {
                    return "too long";
                }
            }
        }
    }
    if ($checkRequired&&count($missingRequiredKeys)>0) {
        return "missing required key(s)";
    }
    return "";
}

$json='
{
    "a_string":"not short",
    "a_number":null,
    "a_double":3.14159265359,
    "a_boolean":true,
    "an_array":[
        "no name",
        3.14,
        true,
        {
            "a_string2":"not short",
            "a_number2":4
        }
    ]
}
';

$schema='
{
    "a_string":{
        "type":"string",
        "min":3,
        "max":10,
        "required":true
    },
    "a_number":{
        "type":"integer",
        "min":3,
        "max":10,
        "required":true,
        "nullable":true
    },
    "a_double":{
        "type":"double",
        "min":3,
        "max":10,
        "required":true,
        "nullable":false
    },
    "a_boolean":{
        "type":"boolean",
        "required":true
    },
    "an_array":{
        "type":"array",
        "min":2,
        "max":10,
        "required":false,
        "data":
            [
                {
                    "type":"string",
                    "min":3,
                    "max":10
                },
                {
                    "type":"double",
                    "min":3,
                    "max":10
                },
                {
                    "type":"boolean"
                },
                {
                    "a_string2":{
                        "type":"string",
                        "min":3,
                        "max":10,
                        "required":true
                    },
                    "a_number2":{
                        "type":"integer",
                        "min":3,
                        "max":10,
                        "required":true
                    }
                }
            ]
    }
}
';

echo(validateJsonSchema($json, $schema)."\n");
?>
Source Link
Loading