developer.co.ua

Holy Copypasters
15.10.2008
Сергей Харчишин и Ольга Харчишина

Валидация форм в symfony 0.34

The symfony Forms Book: Глава 2. Валидация форм

В главе 1 мы изучили как создать и отобразить форму обратной связи. В этой главе Вы изучите как управлять валидацией (проверкой) формы.

Перед тем как мы начнем


Форма обратной связи, созданная в главе 1, не полнофункциональная. Что будет происходить, если пользователь отправляет неверный email адрес или сообщение, отсылаемое пользователем, пустое. В этом случае мы хотели бы отобразить сообщение об ошибке, чтобы попросить пользователя ввести корректные данные, как это показано на рисунке 2–1.

Рисунок 2–1 – Отображение сообщений об ошибках



Вот правила проверки, применимые для формы обратной связи:


Почему мы должны проверять поле subject? Тег <select> уже связывает пользователя с заранее выбранными значениями. Обычно пользователь может выбрать одно значение отображаемого списка, но другие данные могут быть посланы используя инструменты такие как Firefox Developer Toolbar, или отосланы запросом с помощью curl или wget.


Листинг 2–1 показывает шаблон, который мы использовали в Главе 1.

Листинг 2–1 – Шаблон формы Contact
// apps/frontend/modules/contact/templates/indexSucces.php
<form action="<?php echo url_for('contact/index'?>" method="POST">
  <table>
    <?php echo $form ?>
    <tr>
      <td colspan="2">
        <input type="submit" />
      </td>
    </tr>
  </table>
</form>


Рисунок 2–2 показывает взаимосвязь между приложением и пользователем. Первый этап – это предоставление формы пользователю. Когда пользователь отправляет форму и ранее введенные данные валидные, пользователь перенаправляется на страницу thank you. Если же введенные данные неверные, отображается форма с сообщениями об ошибках.

Рисунок 2–2 – Взаимосвязь между приложением и пользователем.


Валидация (Проверка)


Форма symfony состоит из полей. Каждое поле может быть определено уникальным именем, как мы рассматривали в главе 1. Мы подключили виджеты для каждого поля в порядке отображения для пользователя. Теперь давайте посмотрим, как мы можем применить правила валидации для каждого поля.

Класс sfValidatorBase


Проверка каждого поля осуществляется объектами наследуемыми от класса sfValidatorBase. Для того чтобы проверить форму обратной связи, нам необходимо определить валидаторы для каждого из четырех полей: name, email, subject и message. Листинг 2–2 показывает применение этих валидаторов в классе формы используя метод setValidators().

Листинг 2–2 – добавление валидаторов для класса ContactForm
<?php
// lib/form/ContactForm.class.php
class ContactForm extends sfForm
{
  protected static 
$subjects = array('Subject A''Subject B''Subject C');
 
  public function 
configure()
  {
    
$this->setWidgets(array(
      
'name'    => new sfWidgetFormInput(),
      
'email'   => new sfWidgetFormInput(),
      
'subject' => new sfWidgetFormSelect(array('choices' => self::$subjects)),
      
'message' => new sfWidgetFormTextarea(),
    ));
    
$this->widgetSchema->setNameFormat('contact[%s]');
 
    
$this->setValidators(array(
      
'name'    => new sfValidatorString(array('required' => false)),
      
'email'   => new sfValidatorEmail(),
      
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
      
'message' => new sfValidatorString(array('min_length' => 4)),
    ));
  }
}
?>


Мы используем три отдельных валидатора:


Каждый валидатор принимает список значений в качестве первого аргумента. Подобно виджетам, некоторые из этих опций обязательные, некоторые нет. Например, валидатор sfValidatorChoice принимает один обязательный параметр, choices. Каждый валидатор может также принимать опции required и trim, определенные по умолчанию в классе sfValidatorBase:

ОпцияЗначение по умолчаниюОписание
requiredtrueПоле нужно обязательно заполнить
trimfalseАвтоматически удаляет пробелы в начале и в конце строки перед проверкой

Давайте посмотрим на опции валидаторов, которые мы только что использовали:

ВалидаторОбязательные опцииНеобязательные опции
sfValidatorString
max_length
min_length
sfValidatorEmail
pattern
sfValidatorChoicechoices

Если Вы попытаетесь отправить форму с неправильными значениями, Вы не увидите никаких изменений в поведении. Вам нужно обновить модуль contact для проверки посланных данных, как показано в листинге 2–3.

Листинг 2–3 – Применение валидаторов в модуле contact
<?php
class contactActions extends sfActions
{
  public function 
executeIndex($request)
  {
    
$this->form = new ContactForm();
 
    if (
$request->isMethod('post'))
    {
      
$this->form->bind($request->getParameter('contact'));
      if (
$this->form->isValid())
      {
        
$this->redirect('contact/thankyou?'.http_build_query($this->form->getValues()));
      }
    }
  }
 
  public function 
executeThankyou()
  {
  }
}

?>


Листинг 2–3 представляет нам много новых идей:

<?php
$this
->form = new ContactForm();
?>

<?php
if ($request->isMethod('post'))
{
  
$this->form->bind($request->getParameter('contact'));


Когда форма находится в начальном состоянии, метод isValid() всегда возвращает false, а метод getValues() всегда возвращает пустой массив.


Рисунок 2–3 показывает код, выполненный на протяжении взаимодействия между приложением и пользователем.

Рисунок 2–3 – Код, выполненный на протяжении взаимодействия между приложением и пользователем.

Предназначение валидаторов


Вы наверное заметили, что во время перенаправления на страницу thank you, мы используем не $request->getParameter('contact'), а $this->form->getValues(). Фактически, $request->getParameter('contact') возвращает данные пользователя, тогда как $this->form->getValues() возвращает проверенные данные.

Если форма валидна, почему эти два утверждения не могут быть идентичны? Каждый валидатор на самом деле имеет две задачи: валидация, а так же очистка. Метод getValues() фактически возвращает проверенные и очищенные данные.

Процесс очистки состоит из двух действий: нормализация и преобразование введенных данных.

Мы уже встречались со случаем нормализации данных, а именно с trim опцией. Но нормализация намного важнее для поля даты. Например, sfValidatorDate проверяет дату. Этот валидатор принимает много форматов входящих данных (timestamp; формат, основанный на регулярном выражении, ...). Вместо простого возвращения введенного значения, он по умолчанию преобразует значение в формат Y-m-d H:i:s. По этой причине программист гарантировано получит стабильный формат, несмотря на особенности вводимого формата. Система предоставляет гибкость для пользователя и обеспечивает логичность для разработчика.

Теперь рассмотрим действия преобразования, такие как загрузка файлов. Валидация файлов может быть выполнена с помощью sfValidatorFile. Когда файл загружен, вместо возвращения имени файла, валидатор возвращает объект sfValidatedFile, делая легче понимание информации о файле. Мы увидим позже в этой главе как использовать этот валидатор.

Метод getValues() возвращает массив, содержащий все проверенные и очищенные данные. Но иногда нужно извлечь одно значение, для этого есть метод getValue(): $email = $this->form->getValue('email')

Невалидная форма


Всякий раз, когда в форме есть невалидные поля, отображается шаблон indexSuccess. Рисунок 2–4 показывает нам, что мы получаем если отправляем форму с невалидными данными.

Рисунок 2–4 – невалидная форма


Вызов <?php echo $form ?> оператора автоматически учитывает сообщения об ошибках, ассоциированных с полями и автоматически заполняет поля очищенными данными пользователя.

Когда форма связана с внешними данными методом bind(), форма переходит в связанное состояние. Выполнены следующие действия:


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

Как видно из главы 1, мы можем передать значения по умолчания в конструктор формы. После отправки невалидной формы, значения по умолчанию перезаписаны отправленными значениями, таким образом пользователь может исправить свои ошибки. Поэтому, никогда не используйте введенные данные в качестве значения по умолчанию, как в этом примере: $this->form->setDefaults($request->getParameter('contact')).

Настройка валидатора

Настройка сообщений об ошибках


Как Вы возможно заметили, сообщения об ошибках на рисунке 2–4 не очень удобны. Давайте посмотрим, как сделать их более понятными.

Каждый валидатор может добавлять сообщения об ошибках в форму. Ошибка состоит из кода ошибки и сообщения ошибки. Каждый валидатор имеет required и invalid ошибки, определенные в sfValidatorBase:

КодСообщениеОписание
requiredRequiredПоле обязательное, а значение пустое
invalidInvalid.Поле введено не верно

Вот коды ошибок связанные с валидаторами которые мы уже использовали:

ВалидаторКод ошибки
sfValidatorStringmax_length
min_length
sfValidatorEmail
sfValidatorChoice

Настройка сообщений об ошибках осуществляется передачей второго параметра при создании объекта валидации. Листинг 2–4 настраивает некоторые сообщения об ошибках, а рисунок 2–5 показывает настроенные сообщения об ошибках в действии.

Листинг 2–4 – настройка сообщений об ошибках.
<?php
class ContactForm extends sfForm
{
  protected static 
$subjects = array('Subject A''Subject B''Subject C');
 
  public function 
configure()
  {
    
// ...
 
    
$this->setValidators(array(
      
'name'    => new sfValidatorString(array('required' => false)),
      
'email'   => new sfValidatorEmail(array(), array('invalid' => 'The email address is invalid.')),
      
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
      
'message' => new sfValidatorString(array('min_length' => 4), array('required' => 'The message field is required.')),
    ));
  }
}

?>


Рисунок 2–5 – модифицированные сообщения об ошибках.



Рисунок 2–6 показывает сообщение об ошибке, которое Вы получите, если попытаетесь отправить сообщение слишком коротким (мы установили минимальную длину в 4 символа).

Рисунок 2–6 – слишком короткое сообщение



Стандартное сообщение об ошибке, связано с кодом ошибки (min_length) и отличается от сообщения которое мы уже рассмотрели, так как используются два динамических значения: поле ввода (foo) и минимальное количество символов, которое разрешено для поля (4). Листинг 2–5 задает сообщение об ошибке, используя эти динамические значения. Результат показан на рисунке 2–7.

Листинг 2–5 – Настройка сообщений об ошибках с использованием динамических значений
<?php
class ContactForm extends sfForm
{
  public function 
configure()
  {
    
// ...
 
    
$this->setValidators(array(
      
'name'    => new sfValidatorString(array('required' => false)),
      
'email'   => new sfValidatorEmail(array(), array('invalid' => 'Email address is invalid.')),
      
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
      
'message' => new sfValidatorString(array('min_length' => 4), array(
        
'required'   => 'The message field is required',
        
'min_length' => 'The message "%value%" is too short. It must be of %min_length% characters at least.',
      )),
    ));
  }
}
 
?>


Рисунок 2–7 – Настроенные сообщения об ошибках с использованием динамических значений



В сообщении об ошибке можно использовать динамические значения, заключая имя значения в символ процента (%). Доступные значения – это обычно значения, введенные пользователем (value) и опции значений валидатора, связанные с ошибкой.

Если вы хотите просмотреть все коды ошибок, опции и стандартные сообщения валидатора, перейдите пожалуйста в API онлайн документацию (http://www.symfony-project.org/api/1_1/). Каждый код, опция и сообщение об ошибке детально описаны там вместе со стандартными значениями (например, описание sfValidatorString доступно тут http://www.symfony-project.org/api/1_1/sfValidatorString).

Безопасность валидаторов


По умолчанию форма валидна, только если каждое из полей, отправленное пользователем, имеет валидатор. Это гарантирует, что каждое поле имеет свои правила валидации, и это не дает возможности вводить значения для полей, которые не определены в форме.

Что бы понять это правило безопасности, давайте рассмотрим объект user, показанный в листинге 2–6.

Листинг 2–6 – класс User
<?php
class User
{
  protected
    
$name '',
    
$is_admin false;
 
  public function 
setFields($fields)
  {
    if (isset(
$fields['name']))
    {
      
$this->name $fields['name'];
    }
 
    if (isset(
$fields['is_admin']))
    {
      
$this->is_admin $fields['is_admin'];
    }
  }
 
  
// ...
}

?>


Объект User формирует два свойства: имя пользователя (name), и булевое значение статуса администратора (is_admin). Метод setFields() обновляет два свойства. Листинг 2–7 показывает форму, связанную с классом User, разрешающую пользователю изменять только свойство name.

Листинг 2–7 – форма User
<?php
class UserForm extends sfForm
{
  public function 
configure()
  {
    
$this->setWidgets(array('name' => new sfWidgetFormInputString()));
    
$this->widgetSchema->setNameFormat('user[%s]');
 
    
$this->setValidators(array('name' => new sfValidatorString()));
  }
}

?>


Листинг 2–8 показывает реализацию модуля user с использованием предыдущего определения формы, разрешающего пользователю изменять поле name.

Листинг 2–8 – выполнение модуля user
<?php
class userActions extends sfActions
{
  public function 
executeIndex($request)
  {
    
$this->form = new UserForm();
 
    if (
$request->isMethod('post'))
    {
      
$this->form->bind($request->getParameter('user'));
      if (
$this->form->isValid())
      {
        
$user // retrieving the current user

 



        
$user->setFields($this->form->getValues());
 
        
$this->redirect('...');
      }
    }
  }
}
?>


Если пользователь отправляет форму со значением для поля name и для поля is_admin без каких-либо проверок, наш код будет уязвим. Это легко выполнить используя такой инструмент, как Firebug. Фактически, значение is_admin всегда валидное, потому что поле не имеет валидатора, ассоциированного с ним в форме. Какое бы ни было значение, метод setFields() обновит не только свойство name, но и свойство is_admin.

Если Вы протестируете этот код, передавая значения для обеих полей name и is_admin, Вы получите глобальную ошибку “Extra field name.”, как показано на рисунке 2–8. Система генерировала ошибку, потому что некоторые отправленные поля не имеют валидаторов, ассоциированных с ними; поле is_admin не определено в форме UserForm.

Рисунок 2–8 – ошибка «Недостающий валидатор»


Все валидаторы, которые Вы видели до сих пор, генерируют ошибки, ассоциированные с полями. Откуда появляется эта глобальная ошибка? Когда мы используем метод setValidators(), symfony создает объект sfValidatorSchema. sfValidatorSchema определяет совокупность валидаторов. Вызов setValidators() равноценен следующему коду:

<?php
$this
->setValidatorSchema(new sfValidatorSchema(array(
  
'email'   => new sfValidatorEmail(),
  
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
  
'message' => new sfValidatorString(array('min_length' => 4)),
)));

?>


sfValidatorSchema имеет два правила валидации, которые включены по умолчанию чтобы защитить наш набор валидаторов. Эти правила можно настроить с помощью опций allow_extra_fields и filter_extra_fields.

Опция allow_extra_fields, значение которой по умолчанию равно false, проверяет, имеет ли каждое значение, введенное пользователем, валидатор. Если не имеет, глобальна ошибка “Extra field name.” отображается, как это показано в предыдущем примере. Таким образом при разработке разработчики могут увидеть, если для поля не был определен валидатор.

Вернемся к контактной форме. Давайте изменим правила валидации и сделаем поле name обязательным. Так как стандартное значение опции required — true, мы могли бы изменить валидатор name:

<?php
$nameValidator 
= new sfValidatorString();
?>


Этот валидатор не влияет ни на что, так как он не имеет опций min_length или max_length. В этом случае, мы можем заменить его пустым валидатором:

<?php
$nameValidator 
= new sfValidatorPass();
?>


Вместо определения пустого валидатора, мы могли бы избавиться от него, однако защита по умолчанию, которую мы разобрали ранее, препятствует этому. Листинг 2–9 показывает как отключить защиту, используя опцию allow_extra_fields.

Листинг 2–9 – отключение защиты allow_extra_fields
<?php
class ContactForm extends sfForm
{
  public function 
configure()
  {
    
// ...
 
    
$this->setValidators(array(
      
'email'   => new sfValidatorEmail(),
      
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
      
'message' => new sfValidatorString(array('min_length' => 4)),
    ));
 
    
$this->validatorSchema->setOption('allow_extra_fields'true);
  }
}
?>


Теперь Вы можете проверить форму, как показано на рисунке 2–9.

Рисунок 2–9 – проверка при allow_extra_fields = true


Посмотрев внимательно, Вы заметите, что даже если форма валидна, значение поля name на странице thank you пустое, какие бы ни были отправлены значения. Фактически, значение даже не было установлено в массив, отправленный назад методом $this->form->getValues(). Отключение опции allow_extra_fields дает нам возможность избавиться от ошибок из-за отсутствия валидатора, но метод filter_extra_fields, который по умолчанию равен true, фильтрует эти значения, удаляя их из массива проверенных значений. Конечно же можно изменить такое поведение, как показано в листинге 2–10.

Листинг 2–10 – отключение защиты filter_extra_fields
<?php
class ContactForm extends sfForm
{
  public function 
configure()
  {
    
// ...
 
    
$this->setValidators(array(
      
'email'   => new sfValidatorEmail(),
      
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
      
'message' => new sfValidatorString(array('min_length' => 4)),
    ));
 
    
$this->validatorSchema->setOption('allow_extra_fields'true);
    
$this->validatorSchema->setOption('filter_extra_fields'false);
  }
}

?>


Теперь Вы умеете проверять Вашу форму и возвращать введенные значения на страницу thank you.

В главе 4 мы увидим, как эта защита может быть использована для безопасной сериализации (преобразования) объекта Propel из данных формы.

Логические валидаторы


Для простых полей можно задать несколько валидаторов, используя логические проверки:


Конструктор логических операторов принимает список валидаторов в качестве своего первого аргумента.

Листинг 2–11 использует валидатор sfValidatorAnd, чтобы связать два обязательных валидатора для поля name.

Листинг 2–11 – использование валидатора sfValidatorAnd
<?php
class ContactForm extends sfForm
{
 public function 
configure()
 {
    
// ...
 
    
$this->setValidators(array(
      
// ...
      
'name' => new sfValidatorAnd(array(
        new 
sfValidatorString(array('min_length' => 5)),
        new 
sfValidatorRegex(array('pattern' => '/[w- ]+/')),
      )),
    ));
  }
}
?>


Когда форма отправляется, данные, введенные в поле name, должны содержать не меньше 5 символов и соответствовать регулярному выражению ([w- ]+).

Логические валидаторы могут быть скомбинированы, чтобы определить расширенное логическое выражение, как показано в листинге 2–12.

Listing 2–12 – Совмещение несколько логических операторов
<?php
class ContactForm extends sfForm
{
 public function 
configure()
 {
    
// ...
 
    
$this->setValidators(array(
      
// ...
      
'name' => new sfValidatorOr(array(
        new 
sfValidatorAnd(array(
          new 
sfValidatorString(array('min_length' => 5)),
          new 
sfValidatorRegex(array('pattern' => '/[w- ]+/')),
        )),
        new 
sfValidatorEmail(),
      )),
    ));
  }
}
?>

Глобальные валидаторы


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

В обоих случаях мы должны использовать глобальный валидатор для проверки данных, введенных пользователем. Мы можем размещать глобальный валидатор перед или после индивидуальной проверки полей, используя pre-validator или post-validator соответственно. Обычно лучше использовать post-validator, потому что данные уже будут проверены и очищены. Листинг 2–13 показывает, как применить проверку двух паролей, используя валидатор sfValidatorSchemaCompare.

Листинг 2–13 – использование валидатора sfValidatorSchemaCompare
<?php
$this
->validatorSchema->setPostValidator(new sfValidatorSchemaCompare('password'sfValidatorSchemaCompare::EQUAL'password_again'));
?>


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


Листинг 2–14 показывает нам, как использовать простой валидатор для проверки того, что дата начала ранее даты окончания, и как настроить сообщение об ошибке.

Листинг 2–14 – использование валидатора sfValidatorSchemaCompare
<?php
$this
->validatorSchema->setPostValidator(
  new 
sfValidatorSchemaCompare('start_date'sfValidatorSchemaCompare::LESS_THAN_EQUAL'end_date',
    array(),
    array(
'invalid' => 'The start date ("%left_field%") must be before the end date ("%right_field%")')
  )
);
?>


Использование post-validator гарантирует, что проверка двух дат будет точной. Какие бы форматы дат не были использованы при вводе, start_date и end_date всегда будут конвертированы в пригодный для сравнения формат (Y-m-d H:i:s по умолчанию).

По умолчанию pre-validators и post-validators возвращают глобальные ошибки в форму. Тем не менее, некоторые из них могут ассоциироваться с ошибкой конкретного поля. Например, опция throw_global_error валидатора sfValidatorSchemaCompare позволяет выбрать между глобальной ошибкой (Рисунок 2–10) и ошибкой, ассоциированной с первым полем (рисунок 2–11). Листинг 2–15 показывает, как использовать опцию throw_global_error.

Листинг 2–15 – использование опции throw_global_error
<?php
$this
->validatorSchema->setPostValidator(
  new 
sfValidatorSchemaCompare('start_date'sfValidatorSchemaCompare::LESS_THAN_EQUAL'end_date',
    array(
'throw_global_error' => true),
    array(
'invalid' => 'The start date ("%left_field%") must be before the end date ("%right_field%")')
  )
);
?>


Рисунок 2–10 – глобальная ошибка для глобального валидатора


Рисунок 2–11 – локальная ошибка для глобального валидатора



И наконец, использование логического валидатора дает Вам возможность комбинировать несколько post-validator-ов, как показано в листинге 2–16.

Листинг 2–16 – комбинирование нескольких Post-Validator-ов логическим валидатором
<?php
$this
->validatorSchema->setPostValidator(new sfValidatorAnd(array(
  new 
sfValidatorSchemaCompare('start_date'sfValidatorSchemaCompare::LESS_THAN_EQUAL'end_date'),
  new 
sfValidatorSchemaCompare('password'sfValidatorSchemaCompare::EQUAL'password_again'),
)));
?>

Загрузка файлов


Работа с загрузкой файлов в PHP, как и в каждом веб-ориентированном языке, затрагивает и HTML-код и получение файла на серверной стороне. В этом разделе мы рассмотрим инструменты формы, предлагаемые разработчикам, чтобы облегчить их жизнь :) Мы так же рассмотрим, как не попасть в распространенные ловушки.

Давайте изменим контакт форму так, чтобы разрешить прикреплять файл к сообщению. Для этого мы добавим поле file, как показано в листинге 2–17.

Листинг 2–17 – добавление поля file в форму ContactForm
<?php
// lib/form/ContactForm.class.php
class ContactForm extends sfForm
{
  protected static 
$subjects = array('Subject A''Subject B''Subject C');
 
  public function 
configure()
  {
    
$this->setWidgets(array(
      
'name'    => new sfWidgetFormInput(),
      
'email'   => new sfWidgetFormInput(),
      
'subject' => new sfWidgetFormSelect(array('choices' => self::$subjects)),
      
'message' => new sfWidgetFormTextarea(),
      
'file'    => new sfWidgetFormInputFile(),
    ));
    
$this->widgetSchema->setNameFormat('contact[%s]');
 
    
$this->setValidators(array(
      
'name'    => new sfValidatorString(array('required' => false)),
      
'email'   => new sfValidatorEmail(),
      
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
      
'message' => new sfValidatorString(array('min_length' => 4)),
      
'file'    => new sfValidatorFile(),
    ));
  }
}
?>


Когда в форме есть виджет sfWidgetFormInputFile для загрузки файла, мы должны так же добавить атрибут enctype в тег form, как показано в листинге 2–18

Листинг 2–18 – изменение шаблона с учетом поля file
<?php
<form action="<?php echo url_for('contact/index') ?>" method="POST" enctype="multipart/form-data">
  <
table>
    <?
php echo $form ?>
    <tr>
      <td colspan="2">


        <input type="submit" />
      </td>
    </tr>
  </table>
</form>
?>


Если Вы динамически генерируете шаблон, связанный с формой, метод isMultipart() объекта формы возвращает true, если ей требуется атрибут enctype


В PHP информация о файле не размещена вместе с остальными отправленными данными. Поэтому необходимо изменить вызов метода bind(), передав эту информацию в качестве второго параметра, как показано в листинге 2–19.

Листинг 2–19 – передача загруженных файлов в метод bind()
<?php
class contactActions extends sfActions
{
  public function 
executeIndex($request)
  {
    
$this->form = new ContactForm();
 
    if (
$request->isMethod('post'))
    {
      
$this->form->bind($request->getParameter('contact'), $request->getFiles('contact'));
      if (
$this->form->isValid())
      {
        
$values $this->form->getValues();
        
// do something with the values
 
        // ...
      
}
    }
  }
 
  public function 
executeThankyou()
  {
  }
}
?>


Теперь форма полностью рабочая, но мы все еще должны сделать изменения для того, чтобы разместить загруженный файл на диске. Как мы наблюдали в начале этой главы, sfValidatorFile конвертирует информацию, связанную с файлом в объект sfValidatedFile. Листинг 2–20 показывает, как работать с этим объектом, чтобы разместить файл в директории web/uploads.

Листинг 2–20 – использование объекта sfValidatedFile
<?php
if ($this->form->isValid())
{
  
$file $this->form->getValue('file');
 
  
$filename 'uploaded_'.sha1($file->getOriginalName());
  
$extension $file->getExtension($file->getOriginalExtension());
  
$file->save(sfConfig::get('sf_upload_dir').'/'.$filename.$extension);
 
  
// ...
}
?>


Следующая таблица показывает все методы объекта sfValidatedFile:

МетодОписание
save()Сохраняет загруженный файл
isSaved()Возвращает true если файл сохранен
getSavedName()Возвращает имя сохраненного файла
getExtension()Возвращает расширение файла, согласно mime типу
getOriginalName()Возвращает имя загруженного файла
getOriginalExtension()Возвращает расширение загруженного имени файла
getTempName()Возвращает путь к временной директории
getType()Возвращает mime тип файла
getSize()Возвращает размер файла

Mime типы, предоставленные браузером во время загрузки файла ненадежны. В целях обеспечения максимальной безопасности, в процессе валидации файла последовательно используются функции finfo_open, mime_content_type и file. В крайнем случае, если ни одна из функций не сможет определить mime тип, или же система не поддерживает его, mime тип браузера берется в расчет. Чтобы добавить или изменить функцию, которая определяет mime тип, просто передайте опцию mime_type_guessers в конструктор sfValidatorFile.


Авторы перевода: Сергей Харчишин и Ольга Харчишина
Контакты: kindrosker(at)gmail[dot]com
Дата перевода: 12 октября 2008 года.

1 2 3 4 5

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

Спасибо! Symfo
Спасибо за перевод, очень он помог быстро разобраться с валидацией форм!

Более удобный сервис Tesh
В процессе создания своего сайта нашла более интересный, а главное бесплатный, сервис: http://www.mytaskhelper.ru/. С его помощью можно легко создать любую форму (в том числе и динамическую), настроить её внешний вид и встроить на сайт. Огромным преимуществом является то, что совершенно не нужны знания HTML, php и других языков программирования!

maddogg
занесено в копилку

Обсудить (комментариев: 3)