HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

PHP Validate JSON objects with a JSON schema

Submitted by: @import:stackexchange-codereview··
0
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.

 $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:

  • You could initiate your recursive call directly without a foreach loop. This means less code.



  • The gettype calls 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 validateProperty function would have less repetitions and be a bit faster with a switch to replace all the if conditions 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.