ФорумПрограммированиеPHP для идиотов → Валидатор

Валидатор

  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 21 марта 2010 г. 21:35, спустя 4 минуты 23 секунды

    Валидатор инициируется набором поименованных правил. Каждое правило может содержать один или несколько регекспов + текстовое описание ошибки.

    Для проверки значений конкретной формы используется список вида:
    имя-атрибута => имена-правил-через-запятую

    На выходе валидатора либо пустой массив — признак успеха, либо список
    имя-атрибута => ошибка
    который можно использовать при запросе на исправление ошибок


    <?php

    error_reporting(E_ALL | E_STRICT);
    mb_internal_encoding('utf-8');

    class QbSimpleValidator
    {
    private
    $_rules;

    public function __construct(array $rules = array())
    {
    $this->_rules = $rules;
    }

    public function check($values, $appliedRules)
    {
    $result = array();

    foreach ($values as $var => $value) {

    if (!isset($appliedRules[$var]))
    continue;

    $list = array_map('trim', explode(',', $appliedRules[$var]));
    foreach ($list as $ruleName) {
    if (!isset($this->_rules[$ruleName]))
    throw new Exception('Validation rule "'.$ruleName.'" not defined');

    $rr = $this->_rules[$ruleName];
    $message = array_pop($rr);
    foreach ($rr as $r) {
    if (!preg_match($r, $value)) {
    $result[$var] = $message;
    break 2; // leave foreach $list
    }
    }

    }

    }

    return $result;
    }
    }

    $rules = array(
    'LOGIN' => array('/^[a-z0-9]{3,20}$/i',
    'Username should have from 3 till 20 alpha-numeric characters'),
    'PASSWORD' => array('/^[a-z0-9]{6,}$/i',
    'Password should be between 6 and 20 character length'),
    'MIXCASE' => array('/[A-Z]/', '/[a-z]/', '/[0-9]/',
    'Password must have letters in both cases and digits'),
    'NOTEMPTY' => array('/.+/',
    'Field cannot be empty'),
    'Y-M-D' => array('/\d{4}-\d{2}-\d{2}/',
    'Date must be in YYYY-MM-DD format'),
    'NAMEDOT' => array('/^[a-z0-9]+(\.[a-z0-9]+)*$/',
    'Document name should contain one or more lowercase word(s) divided by comma'),
    );

    $v = new QbSimpleValidator($rules);

    $errors = $v->check(
    // form values
    array(
    'user_name' => 'Vaska',
    'user_password' => 'Secret9',
    'doc_name' => 'naming.standard',
    'doc_date' => '2010-03-01'
    ),
    // applied rules
    array(
    'user_name' => 'LOGIN',
    'user_password' => 'PASSWORD, MIXCASE',
    'doc_name' => 'NOTEMPTY',
    'doc_date' => 'Y-M-D')
    );

    if (empty($errors)) {
    echo 'All right';
    } else {
    foreach ($errors as $var => $error) {
    echo $var . ': <em>' . $error . "</em><br />\n";
    }
    }


    Прошу обсудить
    ιιlllιlllι унц-унц
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 21 марта 2010 г. 21:03, спустя 23 часа 27 минут 54 секунды

    1) нужно какие-то предустановленные правила сделать. Не писать же каждый раз хуеву гору регекспов.
    2) на основе первого - расширение правил $validator->addValidator(new myValidators($db));
    3) в error messages можно было б подставлять какие-то параметры: название поля, прочие опции:
    Поле %field% не может быть длинее %length% символов

    я тоже на неделе буду переписывать свой валидатор.
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 21 марта 2010 г. 21:10, спустя 7 минут 16 секунд

    1 - конечно. хуева туча регекспов должна задаваться в конфиге. куча одна на все варианты проверок
    2 - ненужная сложность. для этого есть список "применяемые правила" — второй параметр метода check
    3 - возможно. только спинной мозг мне подскажывает, что параметры приведут к усложнению общей схемы в разы
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 21 марта 2010 г. 21:31, спустя 20 минут 27 секунд

    Как я уже писал в другой теме про валидаторы, я стремлюсь задавать правила валидации (applied rules) в шаблоне формы. Что-то типа:

    Шаблон:

    <input type="password" name="user_password" value="{$user_password}" />
    {rule user_password="PASSWORD, MIXCASE"}

    На выходе из шаблонизатора должно получиться две вещи: php-файл рисующий форму и сериализованный массив применяемых правил. Контроллер будет подхватывать этот массив и в случае ошибок заново вызывать форму. Если хорошенько помозговать, можно и js-валидацию из того же списка генерировать.

    Скомпилированная форма:

    <input type="password" name="user_password" value="<?php echo $user_password ?>" />
    <?php if (isset($errors['user_password'])): echo '<p class="error">'.$errors['user_password'].'</p>'; endif ?>

    Как-то так
    ιιlllιlllι унц-унц
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 21 марта 2010 г. 21:38, спустя 6 минут 51 секунду

    js-валидация на основе описанной через пых - круто, я тоже за это выступаю.

    задавать в конфиге все варианты проверок? хех, прикольно. Может это и правда удобно, но че-то я сомневаюсь в этом.

    А еще, вот хотя бы взять такое правило: уникальный логин. Как ты его на основе регулярок проверять будешь?
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 21 марта 2010 г. 21:58, спустя 20 минут 10 секунд

    никто не обнимет необъятного
    ιιlllιlllι унц-унц
  • LIFF

    Сообщения: 188 Репутация: N Группа: Адекваты

    Spritz 21 марта 2010 г. 22:12, спустя 14 минут 25 секунд

    artoodetoo, считаю лишним описание правил в шаблоне(imho).
    По моему это только в контроллере прописывать надо, если проверка только на стороне сервера.
  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz 21 марта 2010 г. 23:11, спустя 58 минут 14 секунд

    PASSWORD'  => array('/^[a-z0-9]{6,}$/i',
    'Password should be between 6 and 20 character length'),

    {6,20}?
  • LIFF

    Сообщения: 188 Репутация: N Группа: Адекваты

    Spritz 22 марта 2010 г. 0:16, спустя 1 час 5 минут 15 секунд

    SpartakuS, баг, с кем небывает)
  • kostyl

    Сообщения: 5210 Репутация: N Группа: Джедаи

    Spritz 22 марта 2010 г. 0:54, спустя 37 минут 48 секунд

    я такой иногда юзаю:
    class Validator {
    /**
    * @var array
    */
    private $_Rules;

    public function __construct()
    {
    $this->_Rules = array();
    }
    /**
    * @param int $RuleId
    * @param bool $RuleResult
    * @param string $RuleMessage ''
    */
    public function AddRule($RuleId, $RuleResult, $RuleMessage = '')
    {
    if(array_key_exists($RuleId, $this->_Rules)) {
    $this->_Rules[$RuleId][0] = ($this->_Rules[$RuleId][0] && $RuleResult);
    $this->_Rules[$RuleId][1] .= ($RuleMessage && (!$RuleResult)) ? ' ' . $RuleMessage : '';
    }
    else {
    $this->_Rules[$RuleId] = array($RuleResult, (($RuleMessage && (!$RuleResult)) ? ' ' . $RuleMessage : ''));
    }
    }
    /**
    * @return bool
    */
    public function IsValid()
    {
    $Result = TRUE;
    foreach($this->_Rules as $Rule) {
    if(!$Rule[0]) {
    $Result = FALSE;
    }
    }
    unset($Rule);
    return $Result;
    }
    /**
    * @return array
    */
    public function GetRules()
    {
    return $this->_Rules;
    }
    }

    $Validator = new Validator();
    $Validator->AddRule('login_error', (preg_match(USER_LOGIN_MATCH, Request::Post('login'))));
    $Validator->AddRule('login_error', (preg_match(USER_PSWD_MATCH, Request::Post('pswd'))));

    if($Validator->IsValid() && (User::LogIn(Request::Post('login'), Request::Post('pswd')))) {

    }
    Спустя 149 сек.
    блин, а нельзя редактировать сообщения?
    и еще когда отвечаешь в топике не через быстры ответ, предпросмотр обрубывается вроде на знаках &&
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 22 марта 2010 г. 7:26, спустя 6 часов 32 минуты 18 секунд

    SpartakuS, ага, пропустил. ну хоть кто-то всмотрелся в код ;)
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 22 марта 2010 г. 7:59, спустя 32 минуты 50 секунд

    LIFF, это дело вкуса. по мне контроллер должен быть "худым". Собственно акт валидации будет происходить в контроллере, НО список применяемых правил, imho, удобнее держать рядом с описанием полей. В контроллере достаточно написать что-то вроде

    Псевдокод контроллера:

    $form = new MyForm($formId);
    if ($form->posted()) {
    $vars = $form->getVars();
    $validator = new MyValidator(Config::get('validator.rules_definition'));
    $errors = $validator->check($vars, $form->getAppliedRules());
    if (empty($errors)) {
    MyModel::save($vars);
    MyApp::redirect('newpage'); // end here
    } else {
    $vars['errors'] = $errors;
    }
    }
    // …
    $form->render($vars);



    Описывать правила хочется один раз, т.к. правила то одни и те же! Для проверки на клиентской стороне надо будет генерить массив в JSON. С регулярками JS тоже работает :)

    ?>
    <script type="text/javascript">
    var rules = <?php array2json($this->getAppliedRules()) ?>
    </script>
    <script src="./javascripts/jsformvalidator.js" type="text/javascript"></script>

    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 22 марта 2010 г. 8:57, спустя 58 минут 21 секунду

    artoodetoo, очень хороший вопрос поднял, сейчас задумался даже, что правильно? иметь валидацию в обработчике формы, или в хтмле коде формы .. хорошийй вопрос …
    Сапожник без сапог
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 22 марта 2010 г. 9:05, спустя 7 минут 37 секунд

    раньше я был за описание правил валиации прямо около формы, сейчас думаю что в другом месте, ибо хер сменишь дизайн не затрагивая форму бизнес логику
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 22 марта 2010 г. 9:28, спустя 23 минуты 29 секунд

    phpdude, Подсказки выдавать надо? — надо! Как ты укажешь место выдачи строки "телефон записан в неправильном формате"? Полюбому или ты должен
    а) в шаблоне формы пометить место под сообщение про атрибут "телефон" или
    б) выводить все подобные сообщения только в шапке формы. для пользователя это менее удобно. или
    в) всю форму синтезировать из протезов типа $form->addField("телефон", …)
    Последний вариант вообще убивает понятие о дизайне. IMHO

    Помоему нереально добиться абсолютной независимости компонент друг от друга. Можно только "расслабить" эти зависимости и за счет этого уменьшить количество набиваемого кода.
    ιιlllιlllι унц-унц

Пожалуйста, авторизуйтесь, чтобы написать комментарий!