CodeIgniter Forums
JSON in-depth validation - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: CodeIgniter 4 (https://forum.codeigniter.com/forumdisplay.php?fid=28)
+--- Forum: CodeIgniter 4 Support (https://forum.codeigniter.com/forumdisplay.php?fid=30)
+--- Thread: JSON in-depth validation (/showthread.php?tid=76942)



JSON in-depth validation - Nimnod - 07-06-2020

Hi,

I am looking for an elegant way to validate some json-encoded values coming form a post. I consider valid_json helper function merely a first stage validation, to let me throw away syntactically incorrect input. What I would like to do is validate all the values in a resulting array after json_decode just as if they were posted without json. For this I am trying to implement a custom helper function to further validate the input, but i can't seem to pass an array as an argument to it.  The array would need to hold further validation rules concordant with CI4 validation rule syntax, dot matrix syntax included. Has anyone got an idea other than adding secondary validation in the relevent controller's method?

Secondly, even if I pass an json-encoded argument only to decode into an array, how do you request a validator run from inside of a helper function not having access to class pointer?

For now I managed to come up with this:

PHP Code:
public $rule = [
 
'values' => [
  'rules' => 'trim|required|valid_json|json_contain_fields[id,name,owner_id]'
  ]


json_contain_fields being my helper function. It is now limited only to checking if certain keys exist in the array after json_decode.


RE: JSON in-depth validation - Nimnod - 07-07-2020

I seem to have come up with a solution. Here's the helper function:

PHP Code:
    public function json_valid_fields($arg = null, string $fields = null)
    {
        $data = json_decode($arg, $assoc = true, $depth = 15);
        if (json_last_error() !== JSON_ERROR_NONE)
        {
            log_message('error', 'json_valid_fields: invalid json string');
            return false;
        }

        $validator = Services::validation();

        // separate field names with rules
        foreach (explode(',', $fields) as $field)
        {
            $config = explode(':', $field);
            $key = $config[0];

            // separate rules for a field
            $rules = explode('|', $config[1]);
            if (isset($data[$key]))
            {
                // run the checks, break at first failure
                foreach ($rules as $rule)
                {
                    $result = $validator->check($data[$key], $rule);

                    if (! $result)
                        return false;
                }
            }
            elseif (in_array('required', $rules))
            {
                log_message('notice', 'json_valid_fields: key ' .$key. ' is required');
                return false;
            }
        }   

        return true
;
    

And this is how I feed it with validation rules:

PHP Code:
public $rule = [
    
'values' =>    [
        
'rules'    =>    'trim|required|json_valid_fields['
                
.'id:trim|required|is_natural_no_zero,'
                
.'parent_id:trim|is_natural_no_zero,'
                
.'name:trim|required|max_length[256],'
                
.'owner_id:trim|required|is_natural_no_zero,'
                
.']',
        
'errors'    =>    [
            
'json_valid_fields' => 'Invalid JSON data'
        
]
    ],
]; 

Each field+ruleset line is separated with ',', and field name is separated from ruleset with single ':'.
All this allows to validate both syntax and field values in one go.