patternphpMinor
PHP Validate JSON objects with a JSON schema
Viewed 0 times
validateobjectswithphpjsonschema
Problem
I have a basic JSON API written in PHP. I want to validate incoming JSON data.
I know there are PHP JSON validators out there, here is a quick one I just rolled up.
I know there are PHP JSON validators out there, here is a quick one I just rolled up.
$key_val) {
if(!property_exists($payload_value, $key)) echo "validation failed because the data does not match the schema";
reCursiveCheck($key_val, gettype($key_val), $payload_value->{$key}, gettype($payload_value->{$key}));
}
} else {
# VALUE IS A STRING, NUMBER, BOOL, NULL
$validation_param_strings = explode(",", $schema_value);
# STORE THE PARAMS TO CALL THE VALIDATION FUNCTION
$validation_params = array();
foreach($validation_param_strings as $validation_param) {
$params = explode("=", $validation_param);
$validation_params[$params[0]] = $params[1];
}
// print_r($validation_params);
validateProperty($payload_value, $payload_type, $validation_params);
}
}
function validateProperty($payload_value, $payload_type, $validation_rule){
if($payload_type !== $validation_rule["type"]) {
echo "types do not match";
}
# STRING VALIDATION
if($validation_rule["type"] === "string"){
if(strlen($payload_value) > $validation_rule["max_length"]) echo "string too long";
if(strlen($payload_value) ";
}
# NUMBER VALIDATION
if($validation_rule["type"] === "integer"){
if($payload_value > (int)$validation_rule["max"]) echo "number too large";
if($payload_value ";
}
# NULL VALIDATION
if($validation_rule["type"] === "null"){
echo "found a null";
}
}
foreach($json_schema as $key => $value) {
if(!property_exists($json_payload, $key)) echo "validation failed because the data does not match the schema";
reCursiveCheck($value, gettype($value), $json_payload->{$key}, gettype($json_payload->{$key}));
}
}
?>Solution
Here are additional review points on the proposed code focused on functionality, concision and performance:
While I mostly agree with the comment and accepted answer, I must write that I reached this question because I was looking for a simpler solution to validate a json against a schema than those based on composer.
Simpler, in my case, was desired because I must be able to adapt the solution to some specific needs within my project. Composer based solutions made me lose the patience to dive into huge amounts of complex code and I'd rather reinvent the bike if the cost is not too high and if what is proposed is a bunch of tanks (maybe very good ones, but not what I need). If there is a non-composer, simple and efficient solution available, I would be happy to use it.
So, here is a rewrite of a simple php json schema validator without composer in case someone also needs it:
` $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) {
cas
- You could initiate your recursive call directly without a
foreachloop. This means less code.
- The
gettypecalls for the json and the schema can be in the recursive function, thus removing the need for the types arguments.
- If a key in your json is not found in the schema, it is considered as valid. The opposite may be preferred.
- If a key in your schema is not found in the json, it is considered as invalid. The opposite may be preferred.
- For points 3. and 4., my preference goes for a general loop through the json rather than through the schema.
- A json may contain arrays.
- Your
validatePropertyfunction would have less repetitions and be a bit faster with aswitchto replace all theifconditions on types. You could also have a default handling for unsupported types.
- You may want to handle situations where properties are missing.
- Json values can be null.
While I mostly agree with the comment and accepted answer, I must write that I reached this question because I was looking for a simpler solution to validate a json against a schema than those based on composer.
Simpler, in my case, was desired because I must be able to adapt the solution to some specific needs within my project. Composer based solutions made me lose the patience to dive into huge amounts of complex code and I'd rather reinvent the bike if the cost is not too high and if what is proposed is a bunch of tanks (maybe very good ones, but not what I need). If there is a non-composer, simple and efficient solution available, I would be happy to use it.
So, here is a rewrite of a simple php json schema validator without composer in case someone also needs it:
` $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) {
cas
Context
StackExchange Code Review Q#149950, answer score: 2
Revisions (0)
No revisions yet.