Zend_Filter_Input совершенно незаслуженно был обойдён вниманием со стороны разработчиков. На практике он способен во многих ситуациях заменить уже ставший привычным Zend_Form.

Что это и зачем оно нам?

Процитирую документацию:

Zend_Filter_Input предоставляет интерфейс для объединения фильтров и валидаторов, применяемых к коллекциям данных, и возвращает переданные значения после того, как они обработаны фильтрами и валидаторами.

Таким образом, мы передаём в Zend_Filter_Input данные, они нужным нам образом обрабатываются, и получаем мы уже проверенные данные. Если данные не прошли валидацию, мы получаем сообщения об ошибках. Обработка данных состоит из трёх элементов:

Фильтры
Основная задача – вырезать некорректные данные. Например, теги, или же недопустимые символы. .
Валидаторы
Валидаторы занимаются проверкой данных на корректность. Их отличие от фильтров в том, что они не изменяют исходные данные. Например, валидатор Zend_Validate_Alpha не пропустит строку ‘foo123′, выдав сообщение об ошибке. В это же время фильтр Zend_Filter_Alpha просто вырежет лишнее, оставив строку ‘foo’. .
Эскейперы
Эскейперы занимаются преобразованием данных в корректные значения. Например, замена символов < и > на соответствующие HTML-сущности. В отличие от фильтров, они не просто удаляют некорректные значения, а заменяют их на допустимое.

Благодаря Zend_Filter_Input, мы можем объединить фильтры, валидаторы и эскейперы для обработки нужных нам данных.

Как мы можем это использовать?

Следуя мудрости предков, я лучше покажу вам пример, чем буду объяснять элементарные вещи словами.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$filters = ();
$validators = (
    'firstName' => (
        'Alpha',  // Zend_Validate_Alpha
        ('StringLength', 3, 20), // Zend_Validate_StringLength
        'presence'=>'required'  // обязательный параметр
    ),
    'lastName' => (
        'Alpha',
        ('stringLength', 3, 30);
    ),
    'email' => (
        'EmailAddress',
        'presence'=>'required'  //обязательный параметр
    ),
    'password' => (
        'StringEquals',
        'fields' => ('password', 'password-confirm')
    )
);
$options = ('escapeFilter' => 'StringTrim');

$input = new Zend_Filter_Input($filters, $validators, $_POST, $options);

if ($input->isValid()) {
    $firstName = $input->firstName; // обработанное эскейпером значение (в нашем случае StringTrim)
    $lastName = $input->getUnescaped('firstName'); //необработанное эскейпером значение
    $email = $Input->getEscaped('email'); // ещё один способ получить обработанное эскейпером значение
    // записываем в БД
} else {
    $errorsMessages = $input->getMessages();
    // информируем пользователя об ошибках
}

Как видите, всё просто. Не так громоздко, как использование Zend_Form, особенно когда он не нужен.
Но следует рассказать про несколько тонкостей, с которыми я столкнулся.

  1. Используемый по умолчанию эскейпер – Zend_Filter_HtmlEntities. Мне неизвестно, почему разработчики так поступили, но я всегда заменяю его на Zend_Filter_StringTrim.
  2. Для локализации сообщений об ошибках можно использовать те же способы, что и для Zend_Form/Zend_Validate. Я обычно сохраняю Zend_Translate-адаптер в Zend_Registry с именем “Zend_Translate”

Если интересно – могу расширить тему, оставляйте пожелания в комментариях.
Имейте в виду, это лишь вводная статья. Подробности ищите в .

20 Comments

  1. power man says:

    Лично я столкнулся с одной проблемой. А именно кодировка получаемых данных после $Input->getEscaped(‘email’); если у нас utf-8 и строка написана на русском. В итоге решение оказалось простым.
    $data = new Zend_Filter_Input($this->_filters, $this->_validators, $data);
    $data->setDefaultEscapeFilter(new Zend_Filter_HtmlEntities(ENT_COMPAT, ‘utf-8′));

  2. Сергей Митрошин says:

    Не сталкивался с этой проблемой. Возможно, следует указать utf-8 как кодировку по умолчанию в iconv.

  3. Artem says:

    Сергей, а можно ли сделать средствами Zend_Fiter_Input валидацию с зависимостью на другие поля формы?

    Например если у нас есть 3 поля даты (день, мес., год). Если все поля пустые, то всё впорядке, а если одно из полей введено, то нужно провалидировать введённое и все остальные поля (т.е. остальные поля становятся обязательными).

  4. Юрий Истомин says:

    Если я хочу использовать встроенную проверку на обязательные поля, и при этом чтобы сообщения об ошибках были по-русски, придумался такой вариант:
    $filters = array();
    $validators = array(
    ‘Автор’ => array(
    Zend_Filter_Input::PRESENCE => Zend_Filter_Input::PRESENCE_REQUIRED,
    Zend_Filter_Input::FIELDS => ‘author’,
    ),
    );
    $options = array(
    Zend_Filter_Input::NOT_EMPTY_MESSAGE => ‘Поле “%rule%” обязательно для заполнения’,
    );
    $input = new Zend_Filter_Input($filters, $validators, $this->_request->getPost(), $options);

  5. Сергей Митрошин says:

    2 Артём:
    К сожалению, не могу сказать. Видимо, копать надо в сторону своего валидатора, по аналогии с StringEquals:
    $validators = array(
    ‘password’ => array(
    ‘StringEquals’,
    ‘fields’ => array(‘password1′, ‘password2′)
    )
    );

    2 Юрий Истомин:
    Неплохой вариант, но сообщения надо выносить в конфиги. Хранить такие вещи в контроллерах – это хардкод.

  6. Юрий Истомин says:

    Согласен – конфиг или словарики, здесь я для примера захардкодил по-русски. Я ж предполагал просто передать имя поля, а валидатор чтобы сам перевел имя поля на русский язык и сформировал сообщение об ошибке. Кстати, я не нашел, где в Zend_Filter_Input прикручивается экземпляр Zend_Translate

  7. Сергей Митрошин says:

    Надо в Zend_Registry положить с именем ‘Zend_Translate’. Валидаторы сами достанут его и будут использовать.

  8. Юрий Истомин says:

    Как я подружил Zend_Filter_Input и Zend_Captcha.

    $validators = array(
    ‘captcha’ => array(
    $this->_getCaptcha(), // метод создает и настраивает класс капчи
    Zend_Filter_Input::FIELDS => array(‘captcha’, ”),
    ),
    );

    Суть проблемы вот в чем: Zend_Captcha принимает от пользователя массив с ключами id – идентификатор капчи и input – введенное пользователем значение капчи.
    А вот Zend_Filter_Input, если ему передать массив, пытается провалидировать каждый элемент массива по очереди. То есть, Zend_Captcha::isValid() получает на вход сначала значение id, потом значение input – и два раза ругается “Empty captcha value”, поскольку ожидает на вход массив.
    Но его можно обмануть. Если в настройке валидатора, в метакомманде ‘fields’, указать больше одной переменной для валидатора (как в примере проверки пароля с помощью StringEquals) – то Zend_Filter_Input передает значения валидатору как есть – массивом, не разбивая его по элементам. А если в массиве полей попадутся несуществующие, то Zend_Filter_Input их передавать валидатору не будет. Поэтому я и указал Zend_Filter_Input::FIELDS => array(‘captcha’, ”) – массив $_POST['captcha'] передастся как есть, а несуществующее поле $_POST[''] передаваться и не будет.

  9. IgorN says:

    Полезная статья

  10. юлий says:

    столкнулся с проблемой валидации двух необязательных полей, с проверкой заполненности хотябы одного из них. проблема состоит в следующем – если поле не отмечено как required(true), то мой валидатор не срабатывает, т.е. в необязательном поле не хочет проверять оба поля, ниже кусок кода

    public function isValid($value, $context = null) {

    //cheсking if both fields are not empty
    if (strlen($context[$this->_field1]) == 0 && strlen($context[$this->_field2]) == 0){
    $this->_messages[] = $this->_errorMessage;
    return false;
    }

  11. Юрий Истомин says:

    В ZF 1.9 немного поменялась валидация в Zend_Filter_Input – теперь проверка на пустое значение производится автоматически: если для правила указано Zend_Filter_Input::ALLOW_EMPTY => false, то Zend_Validate_NotEmpty добавляется в цепочку валидаторов, а если Zend_Filter_Input::ALLOW_EMPTY => true и проверка Zend_Validate_NotEmpty дает false (то есть поле пустое), валидация поля на этом заканчивается.
    Проблема, собственно, в том, что для конкретного поля нельзя задать персональное сообщение о том, что поле надо заполнять – можно только указать общую для всех опцию Zend_Filter_Input::NOT_EMPTY_MESSAGE => ‘Поле “%rule%” обязательно для заполнения’. Для того, чтобы можно было задать более грамотное сообщение, я сделал дочерний класс:

    class My_FilterInput extends Zend_Filter_Input
    {
    protected function _getNotEmptyMessage($rule, $field)
    {
    if (isset($this->_validatorRules[$rule][Zend_Filter_Input::NOT_EMPTY_MESSAGE])) {
    return $this->_validatorRules[$rule][Zend_Filter_Input::NOT_EMPTY_MESSAGE];
    } else {
    return parent::_getNotEmptyMessage($rule, $field);
    }
    }
    }

    И теперь можно задать для конкретного правила конкретное сообщение:

    ‘comment’ => array(
    Zend_Filter_Input::NOT_EMPTY_MESSAGE => ‘Введите текст комментария’,
    Zend_Filter_Input::ALLOW_EMPTY => false,
    ),
    ‘email’ => array(
    new Zend_Validate_EmailAddress(),
    Zend_Filter_Input::MESSAGES => array(
    array(Zend_Validate_EmailAddress::INVALID_FORMAT => ‘Введите корректный e-mail адрес’),
    ),
    Zend_Filter_Input::ALLOW_EMPTY => false,
    Zend_Filter_Input::NOT_EMPTY_MESSAGE => ‘Укажите e-mail’,
    )

  12. andrey says:

    Добрый день. Можно подробнее про Zend_Filter_Input и Zend_Captcha.
    У меня в html-файле(форма)
    ‘captcha’,
    ‘wordLen’ => 6,
    ‘timeout’ => 300,
    ));
    $captcha->setFont(‘../library/Fonts/tahoma.ttf’);
    $id = $captcha->generate();
    ?>
    render($this);?>
    Enter code *:

    <input type="hidden" name="captcha[id]" value="”/>

    в акшине

    if($request = $this->getRequest()->isPost()) {
    $captcha = new Zend_Captcha_Image(array(
    ‘name’ => ‘captcha-image’,
    ‘wordLen’ => 6,
    ‘timeout’ => 300,
    ));
    $captcha->setFont(‘../library/Fonts/tahoma.ttf’);

    $filters = array();
    $validators = array(
    // ‘name’ => array(
    // ‘Alpha’, // Zend_Validate_Alpha
    // array(‘StringLength’, 3, 20), // Zend_Validate_StringLength
    // ‘presence’=>’required’ // обязательный параметр
    // ),
    // ‘phone’ => array(
    // ‘Alpha’,
    // array(‘stringLength’, 6, 15)
    // ),
    // ‘email’ => array(
    // ‘EmailAddress’,
    // ‘presence’=>’required’), //обязательный параметр
    ‘captcha’ => array(
    $captcha, // метод создает и настраивает класс капчи
    Zend_Filter_Input::FIELDS => array(‘captcha’,”))

    );
    $options = array(‘escapeFilter’ => ‘StringTrim’);

    $input = new Zend_Filter_Input($filters, $validators, $_POST, $options);

    if ($input->isValid()) {
    $this->view->successMessages = “Thank you!”;
    } else {
    $this->view->errorMessages = $input->getMessages();
    $this->view->params = $_POST;
    }
    }

    Cообщение об ошибке Empty captcha value
    хотя выдаст
    [captcha] => Array ( [id] => a7ff8d38f7542ebaba39f0887f7f1d07 [input] => fghfd

  13. andrey says:

    работает если поля имеют имя
    <input type="hidden" name="id" value="”/>

    а в фильтре
    Zend_Filter_Input::FIELDS => array(‘id’,'input’))
    если поменять на другие – не работает

  14. andrey says:

    работает если поля имеют имя

    а в фильтре
    Zend_Filter_Input::FIELDS => array(’id’,’input’))
    если поменять на другие – не работает

  15. andrey says:

    что-то теги режутся

    работает если поля имеют имя

    а в фильтре
    Zend_Filter_Input::FIELDS => array(’id’,’input’))
    если поменять на другие – не работает

  16. andrey says:

    короче id для id капчи и input для введённого значения

  17. Lyuba says:

    Помогите мне пожалуйста!!!!!!!!!!! Мне нужно как-то поменять кодировку в zend studio for eclipse 6.1.0 а то у меня русские слова отображаются непонятными символами.

  18. excalibur says:

    Если как escapeFilter Вы используете StringTrim (а это как раз подходит, например для формы комментирование, где используется визуальный редактор и должен сохраняться html-код в базу данных), то какой фильтр Вы используете чтобы экранировать кавычки? Ими занимается как раз Zend_Filter_HtmlEntities, но его использование неудобно для случая, который я описал выше. Если я что-то упустил – буду признателен за совет.

  19. юра says:

    Поправьте “new Zend_Fiter_Input” на “new Zend_Filter_Input” !

  20. Сергей Митрошин says:

    Спасибо Юра, исправил.

Leave a Reply

info@zend-framework.ru