$cfg) { if (is_string($cfg)) $cfg = array('*' => $cfg); $value = (isset($data[$name])) ? $data[$name] : FALSE; if (is_string($value)) $value = trim($value); if ($value) { if (is_array($value)) { // Поле в виде массива - // проверяем каждый элемент по очереди $fn = __FUNCTION__ ; foreach ($value as $v) $errors = array_merge( $errors, $fn( array($name => $cfg), array($name => $v) ) ); continue; // Перебрав массив, // переходим к следующему полю формы } foreach ($cfg as $filter => $instructions) { # звездочка ( '*' => Ошибка, когда поле не заполнено ) if ($filter === '*') // ===, а то числовой ключ 0 срабатывает $check = TRUE; // Уже выяснили, что поле заполнено # функция прямо в конфигурационном массиве // Внимание! Проверка значения $instructions, а не $filter elseif (is_callable($instructions)) { $result = $instructions($data, $name); // сюда весь массив и имя текущего поля if ($result) { $check = (!$result); if (is_array($result)) $errors = array_merge($errors, $result); else $errors[] = $result; } else $check = TRUE; } # Сравнение с числом ('>= 0.2' и др.) elseif (preg_match('"((?:>|<)=?)\s*(.+)"', $filter, $matches)) switch ($matches[1]) { case '>': $check = ($value > $matches[2]); break; case '>=': $check = ($value >= $matches[2]); break; case '<': $check = ($value < $matches[2]); break; case '<=': $check = ($value <= $matches[2]); break; } # Регулярное выражение - /.../. elseif (preg_match('"^/.+/\w*$"', $filter)) $check = preg_match($filter, $value); # 'имя функции()' - просто проверка; '+имя функции()'- дописывает массив ошибок elseif (preg_match('"^(\+?)(\w+)\(\)$"', $filter, $matches)) { $fn = $matches[2]; if (!is_array($instructions) OR !isset($instructions['args'])) $args = array($value); // Одной проверки isset недостаточно, // т.к. для строк она работает неожиданно. else { $args = $instructions['args']; if (FALSE !== ($k = array_search('{*value*}', $args, TRUE) ) ) $args[$k] = $value; unset($k); } $result = call_user_func_array($fn, $args); if ($matches[1] AND is_array($result) ) // + - режим дописывания ошибок $errors = array_merge($errors, $result); else // режим простой проверки $check = $result; } # Простая проверка на равенство else $check = ($filter == $value); if (!$check AND !is_callable($instructions)) { $text = FALSE; if (is_string($instructions)) $text = $instructions; elseif (isset($instructions['text'])) $text = $instructions['text']; if ($text !== FALSE) { $text = str_replace('{*value*}', $value, $text); $errors[] = $text; } } else { if (is_array($instructions) AND isset($instructions['>>'])) { $fn = __FUNCTION__ ; $child = $instructions['>>']; if (isset($child['^R'])) { $child[$name] = $child['^R']; unset($child['^R']); } $errors = array_merge( $errors, $fn($child, $data, $files) ); } } } } elseif (isset($files[$name])) { $F = $files[$name]; if (!is_array(reset($F))) { // Обычное файловое поле $file_errors = array(); // Здесь потом будем заменять метки // на параметры файла if ($F['error']) { // При загрузке файла возникла некая ошибка - // дальнейшие проверки не проводим if (isset($cfg['*'])) $cfg['error'][UPLOAD_ERR_NO_FILE] = is_string($cfg['*']) ? $cfg['*'] : $cfg['*']['text']; if (isset($cfg['error']) AND $cfg['error']) { if ($cfg['error'] === TRUE) // Всё по умолчанию $cfg['error'] = array(); elseif (is_string($cfg['error'])) $cfg['error'] = array(UPLOAD_ERR_NO_FILE => $cfg['error']); // Дополняем стандартными сообщениями // см. http://www.php.net/manual/ru/features.file-upload.errors.php $cfg['error'] += array( UPLOAD_ERR_NO_FILE => 'Не выбран файл для загрузки.', UPLOAD_ERR_INI_SIZE => 'Размер файла {*name*} не должен превышать ' . ini_get('upload_max_filesize') . 'б.', ); $text_found = FALSE; foreach ($cfg['error'] as $code => $text) if ($F['error'] == $code) { $file_errors[] = $text; $text_found = TRUE; break; } if (!$text_found) $file_errors[] = "При загрузке файла {*name*} возникли технические проблемы (код ошибки: {*error*})."; } } else { // Для проверки свойств загруженного файла // пользуемся этой же функцией: $fn = __FUNCTION__ ; if (isset($cfg['image'])) { $img_cfg = $cfg['image']; if (is_string($img_cfg)) $img_cfg = array('*' => $img_cfg); if (isset($img_cfg['width'])) $img_cfg[0] = $img_cfg['width']; if (isset($img_cfg['height'])) $img_cfg[1] = $img_cfg['height']; $img_data = getimagesize($F['tmp_name']); if (!$img_data) { if (isset($img_cfg['*'])) $file_errors[] = $img_cfg['*']; } else { unset($img_cfg['*']); // Приходится убирать вручную, // чтобы реализовать удобную структуру // массива - без излишней вложенности $file_errors = array_merge( $file_errors, $fn($img_cfg, $img_data) ); } unset($cfg['image']); } unset($cfg['*'], $cfg['error']); // В дочернем вызове эти ключи мешают $file_errors = array_merge( $file_errors, $fn($cfg, $F) ); foreach ($file_errors as $i => $text) $file_errors[$i] = str_replace( array('{*name*}', '{*error*}'), array($F['name'], $F['error']), $text ); } $errors = array_merge( $errors, $file_errors ); } else { // имеем дело с полем-массивом $keys = array_keys($F); foreach ($F['name'] as $i => $v) { $tmp = array(); foreach ($keys as $k) $tmp[$k] = $F[$k][$i]; $normalized_files[$i] = $tmp; } $fn = __FUNCTION__ ; foreach ($normalized_files as $i => $tmp) { $errors = array_merge( $errors, $fn( array($name => $cfg), $data, array($name => $tmp) ) ); } } } else { // Если поле отсутствует или не заполнено - // выясняем только обязательность заполнения, // а остальные проверки не делаем if (isset($cfg['*'])) { if (is_string($cfg['*'])) $errors[] = $cfg['*']; elseif (isset($cfg['*']['text'])) $errors[] = $cfg['*']['text']; } continue; } // У $_FILES проверка на структуру - множественное поле: // $tmp = reset($files); if (is_array($tmp['name']) - множественный) // но пока это не будем } $errors = array_values(array_unique($errors)); // array_values - чтобы была сплошная нумерация, // а то бывает неудобно делать json return $errors; } ?>