"Fossies" - the Fresh Open Source Software Archive

Member "grav/system/src/Grav/Common/Data/Validation.php" (1 Sep 2020, 24002 Bytes) of package /linux/www/grav-v1.6.27.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Validation.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 /**
    4  * @package    Grav\Common\Data
    5  *
    6  * @copyright  Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
    7  * @license    MIT License; see LICENSE file for details.
    8  */
    9 
   10 namespace Grav\Common\Data;
   11 
   12 use Grav\Common\Grav;
   13 use Grav\Common\Utils;
   14 use Grav\Common\Yaml;
   15 
   16 class Validation
   17 {
   18     /**
   19      * Validate value against a blueprint field definition.
   20      *
   21      * @param mixed $value
   22      * @param array $field
   23      * @return array
   24      */
   25     public static function validate($value, array $field)
   26     {
   27         if (!isset($field['type'])) {
   28             $field['type'] = 'text';
   29         }
   30 
   31         $validate = (array)($field['validate'] ?? null);
   32         $type = $validate['type'] ?? $field['type'];
   33         $required = $validate['required'] ?? false;
   34 
   35         // If value isn't required, we will stop validation if empty value is given.
   36         if ($required !== true && ($value === null || $value === '' || (($field['type'] === 'checkbox' || $field['type'] === 'switch') && $value == false))
   37         ) {
   38             return [];
   39         }
   40 
   41         // Get language class.
   42         $language = Grav::instance()['language'];
   43 
   44         $name = ucfirst($field['label'] ?? $field['name']);
   45         $message = (string) isset($field['validate']['message'])
   46             ? $language->translate($field['validate']['message'])
   47             : $language->translate('GRAV.FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
   48 
   49 
   50         // Validate type with fallback type text.
   51         $method = 'type' . str_replace('-', '_', $type);
   52 
   53         // If this is a YAML field validate/filter as such
   54         if (isset($field['yaml']) && $field['yaml'] === true) {
   55             $method = 'typeYaml';
   56         }
   57 
   58         $messages = [];
   59 
   60         $success = method_exists(__CLASS__, $method) ? self::$method($value, $validate, $field) : true;
   61         if (!$success) {
   62             $messages[$field['name']][] = $message;
   63         }
   64 
   65         // Check individual rules.
   66         foreach ($validate as $rule => $params) {
   67             $method = 'validate' . ucfirst(str_replace('-', '_', $rule));
   68 
   69             if (method_exists(__CLASS__, $method)) {
   70                 $success = self::$method($value, $params);
   71 
   72                 if (!$success) {
   73                     $messages[$field['name']][] = $message;
   74                 }
   75             }
   76         }
   77 
   78         return $messages;
   79     }
   80 
   81     /**
   82      * Filter value against a blueprint field definition.
   83      *
   84      * @param  mixed  $value
   85      * @param  array  $field
   86      * @return mixed  Filtered value.
   87      */
   88     public static function filter($value, array $field)
   89     {
   90         $validate = (array)($field['filter'] ?? $field['validate'] ?? null);
   91 
   92         // If value isn't required, we will return null if empty value is given.
   93         if (($value === null || $value === '') && empty($validate['required'])) {
   94             return null;
   95         }
   96 
   97         if (!isset($field['type'])) {
   98             $field['type'] = 'text';
   99         }
  100         $type = $field['filter']['type'] ?? $field['validate']['type'] ?? $field['type'];
  101 
  102         $method = 'filter' . ucfirst(str_replace('-', '_', $type));
  103 
  104         // If this is a YAML field validate/filter as such
  105         if (isset($field['yaml']) && $field['yaml'] === true) {
  106             $method = 'filterYaml';
  107         }
  108 
  109         if (!method_exists(__CLASS__, $method)) {
  110             $method = isset($field['array']) && $field['array'] === true ? 'filterArray' : 'filterText';
  111         }
  112 
  113         return self::$method($value, $validate, $field);
  114     }
  115 
  116     /**
  117      * HTML5 input: text
  118      *
  119      * @param  mixed  $value   Value to be validated.
  120      * @param  array  $params  Validation parameters.
  121      * @param  array  $field   Blueprint for the field.
  122      * @return bool   True if validation succeeded.
  123      */
  124     public static function typeText($value, array $params, array $field)
  125     {
  126         if (!\is_string($value) && !is_numeric($value)) {
  127             return false;
  128         }
  129 
  130         $value = (string)$value;
  131 
  132         if (!empty($params['trim'])) {
  133             $value = trim($value);
  134         }
  135 
  136         if (isset($params['min']) && \strlen($value) < $params['min']) {
  137             return false;
  138         }
  139 
  140         if (isset($params['max']) && \strlen($value) > $params['max']) {
  141             return false;
  142         }
  143 
  144         $min = $params['min'] ?? 0;
  145         if (isset($params['step']) && (\strlen($value) - $min) % $params['step'] === 0) {
  146             return false;
  147         }
  148 
  149         if ((!isset($params['multiline']) || !$params['multiline']) && preg_match('/\R/um', $value)) {
  150             return false;
  151         }
  152 
  153         return true;
  154     }
  155 
  156     protected static function filterText($value, array $params, array $field)
  157     {
  158         if (!\is_string($value) && !is_numeric($value)) {
  159             return '';
  160         }
  161 
  162         if (!empty($params['trim'])) {
  163             $value = trim($value);
  164         }
  165 
  166         return (string) $value;
  167     }
  168 
  169     /**
  170      * @param mixed $value
  171      * @param array $params
  172      * @param array $field
  173      * @return string|null
  174      */
  175     protected static function filterCheckbox($value, array $params, array $field)
  176     {
  177         $value = (string)$value;
  178         $field_value = (string)($field['value'] ?? '1');
  179 
  180         return $value === $field_value ? $value : null;
  181     }
  182 
  183     protected static function filterCommaList($value, array $params, array $field)
  184     {
  185         return \is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
  186     }
  187 
  188     public static function typeCommaList($value, array $params, array $field)
  189     {
  190         return \is_array($value) ? true : self::typeText($value, $params, $field);
  191     }
  192 
  193     protected static function filterLower($value, array $params)
  194     {
  195         return strtolower($value);
  196     }
  197 
  198     protected static function filterUpper($value, array $params)
  199     {
  200         return strtoupper($value);
  201     }
  202 
  203 
  204     /**
  205      * HTML5 input: textarea
  206      *
  207      * @param  mixed  $value   Value to be validated.
  208      * @param  array  $params  Validation parameters.
  209      * @param  array  $field   Blueprint for the field.
  210      * @return bool   True if validation succeeded.
  211      */
  212     public static function typeTextarea($value, array $params, array $field)
  213     {
  214         if (!isset($params['multiline'])) {
  215             $params['multiline'] = true;
  216         }
  217 
  218         return self::typeText($value, $params, $field);
  219     }
  220 
  221     /**
  222      * HTML5 input: password
  223      *
  224      * @param  mixed  $value   Value to be validated.
  225      * @param  array  $params  Validation parameters.
  226      * @param  array  $field   Blueprint for the field.
  227      * @return bool   True if validation succeeded.
  228      */
  229     public static function typePassword($value, array $params, array $field)
  230     {
  231         return self::typeText($value, $params, $field);
  232     }
  233 
  234     /**
  235      * HTML5 input: hidden
  236      *
  237      * @param  mixed  $value   Value to be validated.
  238      * @param  array  $params  Validation parameters.
  239      * @param  array  $field   Blueprint for the field.
  240      * @return bool   True if validation succeeded.
  241      */
  242     public static function typeHidden($value, array $params, array $field)
  243     {
  244         return self::typeText($value, $params, $field);
  245     }
  246 
  247     /**
  248      * Custom input: checkbox list
  249      *
  250      * @param  mixed  $value   Value to be validated.
  251      * @param  array  $params  Validation parameters.
  252      * @param  array  $field   Blueprint for the field.
  253      * @return bool   True if validation succeeded.
  254      */
  255     public static function typeCheckboxes($value, array $params, array $field)
  256     {
  257         // Set multiple: true so checkboxes can easily use min/max counts to control number of options required
  258         $field['multiple'] = true;
  259 
  260         return self::typeArray((array) $value, $params, $field);
  261     }
  262 
  263     protected static function filterCheckboxes($value, array $params, array $field)
  264     {
  265         return self::filterArray($value, $params, $field);
  266     }
  267 
  268     /**
  269      * HTML5 input: checkbox
  270      *
  271      * @param  mixed  $value   Value to be validated.
  272      * @param  array  $params  Validation parameters.
  273      * @param  array  $field   Blueprint for the field.
  274      * @return bool   True if validation succeeded.
  275      */
  276     public static function typeCheckbox($value, array $params, array $field)
  277     {
  278         $value = (string)$value;
  279         $field_value = (string)($field['value'] ?? '1');
  280 
  281         return $value === $field_value;
  282     }
  283 
  284     /**
  285      * HTML5 input: radio
  286      *
  287      * @param  mixed  $value   Value to be validated.
  288      * @param  array  $params  Validation parameters.
  289      * @param  array  $field   Blueprint for the field.
  290      * @return bool   True if validation succeeded.
  291      */
  292     public static function typeRadio($value, array $params, array $field)
  293     {
  294         return self::typeArray((array) $value, $params, $field);
  295     }
  296 
  297     /**
  298      * Custom input: toggle
  299      *
  300      * @param  mixed  $value   Value to be validated.
  301      * @param  array  $params  Validation parameters.
  302      * @param  array  $field   Blueprint for the field.
  303      * @return bool   True if validation succeeded.
  304      */
  305     public static function typeToggle($value, array $params, array $field)
  306     {
  307         if (\is_bool($value)) {
  308             $value = (int)$value;
  309         }
  310 
  311         return self::typeArray((array) $value, $params, $field);
  312     }
  313 
  314     /**
  315      * Custom input: file
  316      *
  317      * @param  mixed  $value   Value to be validated.
  318      * @param  array  $params  Validation parameters.
  319      * @param  array  $field   Blueprint for the field.
  320      * @return bool   True if validation succeeded.
  321      */
  322     public static function typeFile($value, array $params, array $field)
  323     {
  324         return self::typeArray((array)$value, $params, $field);
  325     }
  326 
  327     protected static function filterFile($value, array $params, array $field)
  328     {
  329         return (array)$value;
  330     }
  331 
  332     /**
  333      * HTML5 input: select
  334      *
  335      * @param  mixed  $value   Value to be validated.
  336      * @param  array  $params  Validation parameters.
  337      * @param  array  $field   Blueprint for the field.
  338      * @return bool   True if validation succeeded.
  339      */
  340     public static function typeSelect($value, array $params, array $field)
  341     {
  342         return self::typeArray((array) $value, $params, $field);
  343     }
  344 
  345     /**
  346      * HTML5 input: number
  347      *
  348      * @param  mixed  $value   Value to be validated.
  349      * @param  array  $params  Validation parameters.
  350      * @param  array  $field   Blueprint for the field.
  351      * @return bool   True if validation succeeded.
  352      */
  353     public static function typeNumber($value, array $params, array $field)
  354     {
  355         if (!is_numeric($value)) {
  356             return false;
  357         }
  358 
  359         if (isset($params['min']) && $value < $params['min']) {
  360             return false;
  361         }
  362 
  363         if (isset($params['max']) && $value > $params['max']) {
  364             return false;
  365         }
  366 
  367         $min = $params['min'] ?? 0;
  368 
  369         return !(isset($params['step']) && fmod($value - $min, $params['step']) === 0);
  370     }
  371 
  372     protected static function filterNumber($value, array $params, array $field)
  373     {
  374         return (string)(int)$value !== (string)(float)$value ? (float) $value : (int) $value;
  375     }
  376 
  377     protected static function filterDateTime($value, array $params, array $field)
  378     {
  379         $format = Grav::instance()['config']->get('system.pages.dateformat.default');
  380         if ($format) {
  381             $converted = new \DateTime($value);
  382             return $converted->format($format);
  383         }
  384         return $value;
  385     }
  386 
  387 
  388     /**
  389      * HTML5 input: range
  390      *
  391      * @param  mixed  $value   Value to be validated.
  392      * @param  array  $params  Validation parameters.
  393      * @param  array  $field   Blueprint for the field.
  394      * @return bool   True if validation succeeded.
  395      */
  396     public static function typeRange($value, array $params, array $field)
  397     {
  398         return self::typeNumber($value, $params, $field);
  399     }
  400 
  401     protected static function filterRange($value, array $params, array $field)
  402     {
  403         return self::filterNumber($value, $params, $field);
  404     }
  405 
  406     /**
  407      * HTML5 input: color
  408      *
  409      * @param  mixed  $value   Value to be validated.
  410      * @param  array  $params  Validation parameters.
  411      * @param  array  $field   Blueprint for the field.
  412      * @return bool   True if validation succeeded.
  413      */
  414     public static function typeColor($value, array $params, array $field)
  415     {
  416         return preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u', $value);
  417     }
  418 
  419     /**
  420      * HTML5 input: email
  421      *
  422      * @param  mixed  $value   Value to be validated.
  423      * @param  array  $params  Validation parameters.
  424      * @param  array  $field   Blueprint for the field.
  425      * @return bool   True if validation succeeded.
  426      */
  427     public static function typeEmail($value, array $params, array $field)
  428     {
  429         $values = !\is_array($value) ? explode(',', preg_replace('/\s+/', '', $value)) : $value;
  430 
  431         foreach ($values as $val) {
  432             if (!(self::typeText($val, $params, $field) && filter_var($val, FILTER_VALIDATE_EMAIL))) {
  433                 return false;
  434             }
  435         }
  436 
  437         return true;
  438     }
  439 
  440     /**
  441      * HTML5 input: url
  442      *
  443      * @param  mixed  $value   Value to be validated.
  444      * @param  array  $params  Validation parameters.
  445      * @param  array  $field   Blueprint for the field.
  446      * @return bool   True if validation succeeded.
  447      */
  448 
  449     public static function typeUrl($value, array $params, array $field)
  450     {
  451         return self::typeText($value, $params, $field) && filter_var($value, FILTER_VALIDATE_URL);
  452     }
  453 
  454     /**
  455      * HTML5 input: datetime
  456      *
  457      * @param  mixed  $value   Value to be validated.
  458      * @param  array  $params  Validation parameters.
  459      * @param  array  $field   Blueprint for the field.
  460      * @return bool   True if validation succeeded.
  461      */
  462     public static function typeDatetime($value, array $params, array $field)
  463     {
  464         if ($value instanceof \DateTime) {
  465             return true;
  466         }
  467         if (!\is_string($value)) {
  468             return false;
  469         }
  470         if (!isset($params['format'])) {
  471             return false !== strtotime($value);
  472         }
  473 
  474         $dateFromFormat = \DateTime::createFromFormat($params['format'], $value);
  475 
  476         return $dateFromFormat && $value === date($params['format'], $dateFromFormat->getTimestamp());
  477     }
  478 
  479     /**
  480      * HTML5 input: datetime-local
  481      *
  482      * @param  mixed  $value   Value to be validated.
  483      * @param  array  $params  Validation parameters.
  484      * @param  array  $field   Blueprint for the field.
  485      * @return bool   True if validation succeeded.
  486      */
  487     public static function typeDatetimeLocal($value, array $params, array $field)
  488     {
  489         return self::typeDatetime($value, $params, $field);
  490     }
  491 
  492     /**
  493      * HTML5 input: date
  494      *
  495      * @param  mixed  $value   Value to be validated.
  496      * @param  array  $params  Validation parameters.
  497      * @param  array  $field   Blueprint for the field.
  498      * @return bool   True if validation succeeded.
  499      */
  500     public static function typeDate($value, array $params, array $field)
  501     {
  502         if (!isset($params['format'])) {
  503             $params['format'] = 'Y-m-d';
  504         }
  505 
  506         return self::typeDatetime($value, $params, $field);
  507     }
  508 
  509     /**
  510      * HTML5 input: time
  511      *
  512      * @param  mixed  $value   Value to be validated.
  513      * @param  array  $params  Validation parameters.
  514      * @param  array  $field   Blueprint for the field.
  515      * @return bool   True if validation succeeded.
  516      */
  517     public static function typeTime($value, array $params, array $field)
  518     {
  519         if (!isset($params['format'])) {
  520             $params['format'] = 'H:i';
  521         }
  522 
  523         return self::typeDatetime($value, $params, $field);
  524     }
  525 
  526     /**
  527      * HTML5 input: month
  528      *
  529      * @param  mixed  $value   Value to be validated.
  530      * @param  array  $params  Validation parameters.
  531      * @param  array  $field   Blueprint for the field.
  532      * @return bool   True if validation succeeded.
  533      */
  534     public static function typeMonth($value, array $params, array $field)
  535     {
  536         if (!isset($params['format'])) {
  537             $params['format'] = 'Y-m';
  538         }
  539 
  540         return self::typeDatetime($value, $params, $field);
  541     }
  542 
  543     /**
  544      * HTML5 input: week
  545      *
  546      * @param  mixed  $value   Value to be validated.
  547      * @param  array  $params  Validation parameters.
  548      * @param  array  $field   Blueprint for the field.
  549      * @return bool   True if validation succeeded.
  550      */
  551     public static function typeWeek($value, array $params, array $field)
  552     {
  553         if (!isset($params['format']) && !preg_match('/^\d{4}-W\d{2}$/u', $value)) {
  554             return false;
  555         }
  556 
  557         return self::typeDatetime($value, $params, $field);
  558     }
  559 
  560     /**
  561      * Custom input: array
  562      *
  563      * @param  mixed  $value   Value to be validated.
  564      * @param  array  $params  Validation parameters.
  565      * @param  array  $field   Blueprint for the field.
  566      * @return bool   True if validation succeeded.
  567      */
  568     public static function typeArray($value, array $params, array $field)
  569     {
  570         if (!\is_array($value)) {
  571             return false;
  572         }
  573 
  574         if (isset($field['multiple'])) {
  575             if (isset($params['min']) && \count($value) < $params['min']) {
  576                 return false;
  577             }
  578 
  579             if (isset($params['max']) && \count($value) > $params['max']) {
  580                 return false;
  581             }
  582 
  583             $min = $params['min'] ?? 0;
  584             if (isset($params['step']) && (\count($value) - $min) % $params['step'] === 0) {
  585                 return false;
  586             }
  587         }
  588 
  589         // If creating new values is allowed, no further checks are needed.
  590         if (!empty($field['selectize']['create'])) {
  591             return true;
  592         }
  593 
  594         $options = $field['options'] ?? [];
  595         $use = $field['use'] ?? 'values';
  596 
  597         if (empty($field['selectize']) || empty($field['multiple'])) {
  598             $options = array_keys($options);
  599         }
  600         if ($use === 'keys') {
  601             $value = array_keys($value);
  602         }
  603 
  604         return !($options && array_diff($value, $options));
  605     }
  606 
  607     protected static function filterArray($value, $params, $field)
  608     {
  609         $values = (array) $value;
  610         $options = isset($field['options']) ? array_keys($field['options']) : [];
  611         $multi = $field['multiple'] ?? false;
  612 
  613         if (\count($values) === 1 && isset($values[0]) && $values[0] === '') {
  614             return null;
  615         }
  616 
  617 
  618         if ($options) {
  619             $useKey = isset($field['use']) && $field['use'] === 'keys';
  620             foreach ($values as $key => $val) {
  621                 $values[$key] = $useKey ? (bool) $val : $val;
  622             }
  623         }
  624 
  625         if ($multi) {
  626             foreach ($values as $key => $val) {
  627                 if (\is_array($val)) {
  628                     $val = implode(',', $val);
  629                     $values[$key] =  array_map('trim', explode(',', $val));
  630                 } else {
  631                     $values[$key] =  trim($val);
  632                 }
  633             }
  634         }
  635 
  636         if (isset($field['ignore_empty']) && Utils::isPositive($field['ignore_empty'])) {
  637             foreach ($values as $key => $val) {
  638                 if ($val === '') {
  639                     unset($values[$key]);
  640                 } elseif (\is_array($val)) {
  641                     foreach ($val as $inner_key => $inner_value) {
  642                         if ($inner_value === '') {
  643                             unset($val[$inner_key]);
  644                         }
  645                     }
  646                 }
  647 
  648                 $values[$key] = $val;
  649             }
  650         }
  651 
  652         return $values;
  653     }
  654 
  655     public static function typeList($value, array $params, array $field)
  656     {
  657         if (!\is_array($value)) {
  658             return false;
  659         }
  660 
  661         if (isset($field['fields'])) {
  662             foreach ($value as $key => $item) {
  663                 foreach ($field['fields'] as $subKey => $subField) {
  664                     $subKey = trim($subKey, '.');
  665                     $subValue = $item[$subKey] ?? null;
  666                     self::validate($subValue, $subField);
  667                 }
  668             }
  669         }
  670 
  671         return true;
  672     }
  673 
  674     protected static function filterList($value, array $params, array $field)
  675     {
  676         return (array) $value;
  677     }
  678 
  679     public static function filterYaml($value, $params)
  680     {
  681         if (!\is_string($value)) {
  682             return $value;
  683         }
  684 
  685         return (array) Yaml::parse($value);
  686 
  687     }
  688 
  689     /**
  690      * Custom input: ignore (will not validate)
  691      *
  692      * @param  mixed  $value   Value to be validated.
  693      * @param  array  $params  Validation parameters.
  694      * @param  array  $field   Blueprint for the field.
  695      * @return bool   True if validation succeeded.
  696      */
  697     public static function typeIgnore($value, array $params, array $field)
  698     {
  699         return true;
  700     }
  701 
  702     public static function filterIgnore($value, array $params, array $field)
  703     {
  704         return $value;
  705     }
  706 
  707     /**
  708      * Input value which can be ignored.
  709      *
  710      * @param  mixed  $value   Value to be validated.
  711      * @param  array  $params  Validation parameters.
  712      * @param  array  $field   Blueprint for the field.
  713      * @return bool   True if validation succeeded.
  714      */
  715     public static function typeUnset($value, array $params, array $field)
  716     {
  717         return true;
  718     }
  719 
  720     public static function filterUnset($value, array $params, array $field)
  721     {
  722         return null;
  723     }
  724 
  725     // HTML5 attributes (min, max and range are handled inside the types)
  726 
  727     public static function validateRequired($value, $params)
  728     {
  729         if (is_scalar($value)) {
  730             return (bool) $params !== true || $value !== '';
  731         }
  732 
  733         return (bool) $params !== true || !empty($value);
  734     }
  735 
  736     public static function validatePattern($value, $params)
  737     {
  738         return (bool) preg_match("`^{$params}$`u", $value);
  739     }
  740 
  741 
  742     // Internal types
  743 
  744     public static function validateAlpha($value, $params)
  745     {
  746         return ctype_alpha($value);
  747     }
  748 
  749     public static function validateAlnum($value, $params)
  750     {
  751         return ctype_alnum($value);
  752     }
  753 
  754     public static function typeBool($value, $params)
  755     {
  756         return \is_bool($value) || $value == 1 || $value == 0;
  757     }
  758 
  759     public static function validateBool($value, $params)
  760     {
  761         return \is_bool($value) || $value == 1 || $value == 0;
  762     }
  763 
  764     protected static function filterBool($value, $params)
  765     {
  766         return (bool) $value;
  767     }
  768 
  769     public static function validateDigit($value, $params)
  770     {
  771         return ctype_digit($value);
  772     }
  773 
  774     public static function validateFloat($value, $params)
  775     {
  776         return \is_float(filter_var($value, FILTER_VALIDATE_FLOAT));
  777     }
  778 
  779     protected static function filterFloat($value, $params)
  780     {
  781         return (float) $value;
  782     }
  783 
  784     public static function validateHex($value, $params)
  785     {
  786         return ctype_xdigit($value);
  787     }
  788 
  789     public static function validateInt($value, $params)
  790     {
  791         return is_numeric($value) && (int)$value == $value;
  792     }
  793 
  794     protected static function filterInt($value, $params)
  795     {
  796         return (int)$value;
  797     }
  798 
  799     public static function validateArray($value, $params)
  800     {
  801         return \is_array($value) || ($value instanceof \ArrayAccess && $value instanceof \Traversable && $value instanceof \Countable);
  802     }
  803 
  804     public static function filterItem_List($value, $params)
  805     {
  806         return array_values(array_filter($value, function($v) { return !empty($v); } ));
  807     }
  808 
  809     public static function validateJson($value, $params)
  810     {
  811         return (bool) (@json_decode($value));
  812     }
  813 }