Skip to content
Snippets Groups Projects
validateparam.class.php 6.89 KiB
<?php
class validateparam
{

    /**
     * Summary of _aValidationDefs
     * @var array
     */
    protected array $_aValidationDefs = [];

    protected bool $_flag_debug = false;


    /**
     * Write debug line if _flag_debug is set to true
     * @param string $s  message to show
     * @return void
     */
    protected function _wd(string $s)
    {
        if ($this->_flag_debug) {
            echo "DEBUG: $s<br>\n";
        }
    }

    /**
     * Include the default validation rules defined in validateparam.settings.php
     */
    public function __construct(){
        // IMPORTANT:
        // This style is not so nice like <variable> = include <file>;
        // keep the include line unchanged - it is detected by installer 
        // CLI client project (amcli)
        include 'validateparam.settings.php';
    }

    /**
     * shared validaten checks for floor and integer
     * 
     * @param array $aOpt  Validation rules
     * @param mixed $value value to verify
     * @return string with found error
     */
    protected function _checkCount(array $aOpt, mixed $value)
    {
        $sError = "";

        if ($aOpt['min'] ?? false) {
            if ($value < $aOpt['min']) {
                $sError .= "Value is too small; minimum is $aOpt[min]. ";
            }
        }
        if ($aOpt['max'] ?? false) {
            if ($value > $aOpt['max']) {
                $sError .= "Value is too big; maximum is $aOpt[max]. ";
            }
        }
        if (isset($aOpt['oneof']) && is_array($aOpt['oneof'])) {
            if (array_search($value, $aOpt['oneof']) == false) {
                $sError .= "Value is invalid. Value doesn't match one of these values " . print_r($aOpt['oneof']);
            }
        }

        return $sError;
    }

    /**
     * Validate a single value. It returns a string with an errormessage.
     * No error means ok.
     * 
     * @param array $aOpt  Validation rules
     * @param mixed $value value to verify
     * @return string with found error
     */
    public function validateValue(array $aOpt, mixed $value): string
    {
        $sError = '';

        if (isset($aOpt['validate'])){

            if ($this->_aValidationDefs[$aOpt['validate']] ?? false) {
                $this->_wd("adding options ".print_r($this->_aValidationDefs[$aOpt['validate']],true));
                $aOpt = array_merge($aOpt, $this->_aValidationDefs[$aOpt['validate']]);
            } else {
                $sError .= "Unknown value in 'validate'='$aOpt[validate]'";
            }
        }
        // check type
        if (isset($aOpt['type'])) {
            $this->_wd("check type $aOpt[type]");
            switch ($aOpt['type']) {
                case 'array':
                    if (!is_array($value)) {
                        $sError .= "Value isn't an array";
                    }
                    break;
                case 'bool':
                    if (!is_bool($value)) {
                        // special case for bool after ini parsing
                        if(!$value==="" || !$value===1){
                            $sError .= "Value '$value' isn't a bool";
                        }
                    }
                    break;

                case 'float':
                    if (!is_float($value) && !is_int($value)) {
                        $sError .= "Value isn't a float";
                    } else {
                        $sError .= $this->_checkCount($aOpt, $value);
                    }
                    break;

                case 'int':
                case 'integer':
                    if (!is_int($value)) {
                        $sError .= "Value '$value' isn't an integer";
                    } else {
                        $sError .= $this->_checkCount($aOpt, $value);
                    }
                    break;

                case 'string':
                    if (!is_string($value)) {
                        $sError .= "Value '$value' isn't a string";
                    } else {
                        if ($aOpt['regex'] ?? false) {
                            if (!preg_match($aOpt['regex'], $value)) {
                                $sError .= "Value is invalid. Regex doesn't match: $aOpt[regex]";
                            }
                        }
                        if (isset($aOpt['oneof']) && is_array($aOpt['oneof'])) {
                            if (array_search($value, $aOpt['oneof']) == false) {
                                $sError .= "Value is invalid. Value doesn't match one of these values " . print_r($aOpt['oneof']);
                            }
                        }
                    }
                    break;

                default:
                    $sError .= "ERROR Cannot validate unknown type: '$aOpt[type]'<br>\n";
            }
        }
        // if string: verify regex

        return $sError;
    }

    /**
     * Validate an array of parameter definitions. It returns an array of all error messages
     * No error / an empty array means ok.
     * 
     * @param mixed $aDefs    array with definitions
     * @param mixed $aParams  array of given values
     * @param mixed $bStrict  flag: strict checking to detect wrong keys.
     * @return array with errors
     */
    public function validateArray(array $aDefs, array $aParams, bool $bStrict = true)
    {
        $aErrors = [];

        // echo "<pre>";
        // echo "aDefs = "; print_r($aDefs); 
        // echo "aParams = "; print_r($aParams);
        // echo "<hr>";
        if (!count($aDefs)) {
            return ['Defs' => 'No validation rules given.'];
        }

        $aTmp = $aParams;
        foreach ($aDefs as $sKey => $aOpt) {
            unset($aTmp[$sKey]);
            if ($aOpt['required'] ?? false) {

                $this->_wd("Check MUST $sKey");
                // verify MUST field
                if (!isset($aParams[$sKey])) {
                    $aErrors[$sKey] = "Missing required key '$sKey'";
                } else {
                    $this->_wd("MUST field exists: $sKey");
                    $sError = $this->validateValue($aOpt, $aParams[$sKey]);
                    if ($sError) {
                        $aErrors[$sKey] = $sError;
                    } else {
                        $this->_wd("$sKey was successfully validated.<hr>");
                    }

                }
            }
            if (isset($aParams[$sKey])) {
                $this->_wd("Check OPTIONAL $sKey");
                $sError = $this->validateValue($aOpt, $aParams[$sKey]);
                if ($sError) {
                    $aErrors[$sKey] = $sError;
                }
            }
        }
        if ($bStrict && isset($aTmp) && count($aTmp)) {
            foreach (array_keys($aTmp) as $sKey) {
                $aErrors[$sKey] = "Invalid key was found: '$sKey'; allowed keys are '" . implode("', '", array_keys($aDefs ?? [])) . "'";
            }
        }
        $this->_wd("found errors: " . print_r($aErrors, 1));
        return $aErrors;
    }
}