MODX – FormIt (письмо с вложением)

Статья, в которой рассмотрим, как в MODX Revolution создать форму обратной связи (FormIt + AjaxForm) с возможностью прикрепления к ней файлов. Кроме этого, для защиты формы от вложения в неё нежелательных файлов, разработаем дополнительный валидатор, с помощью которого сниппет FormIt будет проверять каждый файл на то, соответствует ли он необходимому размеру и указанному расширению.

Если вы не знакомы с дополнением FormIt, то разбираться с ним желательно начать с изучения статьи, в которой рассматривается создание простой AJAX формы обратной связи. Сам по себе компонент FormIt не обеспечивает работу с ним по технологии AJAX. Для того чтобы это обеспечить можно воспользоваться ещё одним дополнением MODX – AjaxForm.

Разрабатывать контактную форму с вложениями начнём с выполнения подготовительных действий:

  1. Создание копии чанка tpl.AjaxForm.example (например, с именем tpl.AjaxForm.Attach).
    <form action="" method="post" class="ajax_form af_example">
      <div class="form-group">
        <label class="control-label" for="af_name">[[%af_label_name]]</label>
        <div class="controls">
          <input type="text" id="af_name" name="name" value="[[+fi.name]]" placeholder="" class="form-control"/>
          <span class="error_name">[[+fi.error.name]]</span>
        </div>
      </div>
      <div class="form-group">
        <label class="control-label" for="af_email">[[%af_label_email]]</label>
        <div class="controls">
          <input type="email" id="af_email" name="email" value="[[+fi.email]]" placeholder="" class="form-control"/>
          <span class="error_email">[[+fi.error.email]]</span>
        </div>
      </div>
      <div class="form-group">
        <label class="control-label" for="af_message">[[%af_label_message]]</label>
        <div class="controls">
          <textarea id="af_message" name="message" class="form-control" rows="5">[[+fi.message]]</textarea>
          <span class="error_message">[[+fi.error.message]]</span>
        </div>
      </div>
      <div class="form-group">
        <div class="controls">
          <button type="reset" class="btn btn-default">[[%af_reset]]</button>
          <button type="submit" class="btn btn-primary">[[%af_submit]]</button>
        </div>
      </div>
      [[+fi.success:is=`1`:then=`
       <div class="alert alert-success">[[+fi.successMessage]]</div>
      `]]
      [[+fi.validation_error:is=`1`:then=`
        <div class="alert alert-danger">[[+fi.validation_error_message]]</div>
      `]]
    </form>
  2. Создание ресурса, в котором необходимо отобразить контактную форму с вложениями. В ресурсе или связанном с ним шаблоном необходимо поместить вызов сниппета AjaxForm.
    [[!AjaxForm? 
      &snippet=`FormIt` 
      &form=`tpl.AjaxForm.Attach` 
      &hooks=`FormItSaveForm,email`
      &emailSubject=`Тема письма`
      &emailTo=`my@email.ru`
      &emailFrom=`no-reply@mysite.ru`
      &emailFromName=`Мой сайт`
      &emailTpl=`tpl.email.attach`
      &validate=`name:required,email:required,message:required`
      &validationErrorMessage=`Пожалуйста, исправьте ошибки!`
      &successMessage=`Ваше сообщение успешно отправлено`
    ]]
  3. Разработка чанка tpl.email.attach, который будет определять тело (шаблон) письма.
    <p>Сообщение с формы обратной связи:</p>
    <hr>
    <p>От кого: [[+name]]</p>
    <p>E-mail: [[+email]]</p>
    <p>Сообщение: [[+message]]</p>
    

Прикрепление файлов к форме FormIt

Для отправки формы с вложениями необходимо указать для неё метод кодирования данных multipart/form-data. Это осуществляется в чанке tpl.AjaxForm.Attach.

<form action="" method="post" class="ajax_form af_example" enctype="multipart/form-data">

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

  1. Один файл (в необходимое место HTML формы):
    <div class="form-group">
      <label for="upload">Прикрепить файл</label>
      <input type="file" name="upload">
      <p class="error_upload">[[+fi.error.upload]]</p>
    </div>
  2. Несколько файлов (с помощью нескольких элементов input):
    <div class="form-group">
      <label for="uploads">Прикрепить файлы</label>
      <input type="file" name="uploads[]">
      <input type="file" name="uploads[]">
      <input type="file" name="uploads[]">
      <p class="error_uploads">[[+fi.error.uploads]]</p>
    </div>
  3. Несколько файлов (с помощью одного элемента input):
    <div class="form-group">
      <label for="files">Прикрепить файлы</label>
      <input type="file" name="files[]" multiple="multiple">
      <p class="error_files">[[+fi.error.files]]</p>
    </div>

После выполнения 2 этих простых шагов форма обратной связи сможет отправлять письма на указанный адрес электронный почты (email) с вложениями.

MODX - Контактная форма с вложением
MODX - Контактная форма с вложением
MODX - Письмо с контактной формы
MODX - Письмо с контактной формы
В компоненте FormIt существует ошибка, которая не позволяет отправлять один файл с помощью элемента input, если у него установлен атрибут multiple. Чтобы его поправить необходимо, найти файл fihooks.class, который расположен в следующем каталоге:
\core\components\formit\model\formit\
Открыть его, найти в нём строчку:
if(count($v['name']) > 1){
Изменить эту строчку на следующую:
if(is_array($v['name']) && (count($v['name']) >= 1)){

Проверка расширений и размеров файлов на сервере

При загрузке файлов на сервер, FormIt не проверяет их тип и размер. Чтобы осуществить данную возможность необходимо написать пользовательский валидатор, который будет проверять загруженные файлы на сервере и выдавать ошибки, если хотя бы один из них не соответствует указанным требованиям. Это позволит защитить форму от нежелательных файлов.

Создадим 2 валидатора (сниппета). Первый (formit2checkfile) предназначен для использования с формой, которая может прикрепить максимум один файл (для 1 варианта). Второй валидатор (formit2checkfiles) будем использовать для проверки массива файлов, т.е. когда на форме используем 2 или 3 вариант.

Код валидатора formit2checkfile для проверки одного файла (не массива):

<?php
// инициализируем переменную output, отвечающую за результат работы валидатора, со значением true
$output = true;
// разрешённые расширения файлов
$allowedExt = array('jpg','png');
// максимальный размер файла (512 Кбайт)
$maxFileSize = 512 * 1024;
// имя файла
$fileName = basename( $_FILES[$key]['name'] );
// размер
$fileSize = filesize( $_FILES[$key]['tmp_name'] );
// расширение файла
$fileExt = mb_strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
// если имя файла не пустое
if ($fileName != '') {
  if(!in_array($fileExt, $allowedExt)) {
    // файл имеет недопустимый тип
    $errorMsg = 'Файл ' . $fileName . ' имеет не разрешённый тип.';
    $validator->addError($key, $errorMsg);
    $output = false; // возвращаем false
  }
  if($fileSize > $maxFileSize) {
    // файл имеет размер больше максимального
    $errorMsg = 'Размер файла '. $fileName .' превышает 512 Кбайт.';
    $validator->addError($key,$errorMsg);
    $output = false; // возвращаем false
  }
}
return $output;

Код валидатора formit2checkfiles для проверки нескольких файлов (массива):

<?php
// инициализируем переменную output, отвечающую за результат работы хука, со значением true
$output = true;
// разрешённые расширения файлов
$allowedExt = array('jpg','png');
// максимальный размер файла (512 Кбайт)
$maxFileSize = 512 * 1024;
// если ассоциатианый массив $_FILES[$keys] существует, то
if(isset($_FILES[$key]["error"])) {
  // переберём все файлы (изображения)
  foreach ($_FILES[$key]["error"] as $fkey => $error) {
    // если ошибок не возникло, т.е. файл был успешно загружен на сервер, то...
    if ($error == UPLOAD_ERR_OK) {
      // имя файла
      $fileName = basename($_FILES[$key]['name'][$fkey]);
      // расширение файла
      $fileExt = mb_strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
      // размер файла
      $fileSize = filesize($_FILES[$key]['tmp_name'][$fkey]);
      // проверка расширения файла
      if(!in_array($fileExt, $allowedExt)) {
        // файл имеет недопустимый тип
        $errorMsg = 'Файл ' . $fileName . ' имеет не разрешённый тип.';
        $validator->addError($key, $errorMsg);
        $output = false; // возвращаем false
        break;
      }
      if($fileSize > $maxFileSize) {
        // файл имеет размер больше максимального
        $errorMsg = 'Файл '. $fileName .' имеет не разрешённый размер.';
        $validator->addError($key,$errorMsg);
        $output = false; // возвращаем false
        break;
      }
    } else {
      // произошла ошибка при загрузке файла на сервер
      $errorMsg = 'Произошла ошибка при загрузке файла ' . $fileName .' на сервер.';
      $validator->addError($key,$errorMsg);
      $output = false; // возвращаем false
      break;
    }
  }
}
return $output;
Настройка вышеприведённых сниппетов осуществляется с помощью изменения значений следующих переменных:
// валидные типы файлов для загрузки
$allowedExt = array('jpg','png'); 
// максимальный размер файла (512 Кбайт)
$maxFileSize = 512 * 1024;

Подключения созданного валидатора к форме осуществляется с помощью параметра customValidators, а файл, который необходимо проверить в параметре validate. При этом если пользователь не указал файл, то валиадатор это не считает это за ошибку. Т.к. прикрепление файла или файлов к форме обратной связи в этом примере считается не обязательным.

Проверка формы с одним файлом (input с name, равным upload):

[[!AjaxForm? 
  &snippet=`FormIt` 
  &form=`tpl.AjaxForm.Attach` 
  &hooks=`FormItSaveForm,email`
  &customValidators=`formit2checkfile`
  &emailSubject=`Тема письма`
  &emailTo=`my@email.ru`
  &emailFrom=`no-reply@mysite.ru`
  &emailFromName=`Мой сайт`
  &emailTpl=`tpl.email.attach`
  &validate=`name:required,email:required,message:required,upload: formit2checkfile`
  &validationErrorMessage=`Пожалуйста, исправьте ошибки!`
  &successMessage=`Ваше сообщение успешно отправлено`
]]
MODX - Форма обратной связи (файл не прошёл проверку на сервере - недопустимый тип файла)
MODX - Форма обратной связи (файл не прошёл проверку на сервере - недопустимый тип файла)
MODX - Форма обратной связи (файл не прошёл проверку на сервере - размер файла не укладывается в 512 Кбайт)
MODX - Форма обратной связи (файл не прошёл проверку на сервере - размер файла не укладывается в 512 Кбайт)

Проверка формы с возможностью загрузки нескольких файлов (элементы input с name, равным uploads):

[[!AjaxForm? 
  &snippet=`FormIt` 
  &form=`tpl.AjaxForm.Attach` 
  &hooks=`FormItSaveForm,email`
  &customValidators=`formit2checkfiles`
  &emailSubject=`Тема письма`
  &emailTo=`my@email.ru`
  &emailFrom=`no-reply@mysite.ru`
  &emailFromName=`Мой сайт`
  &emailTpl=`tpl.email.attach`
  &validate=`name:required,email:required,message:required,uploads:formit2checkfiles`
  &validationErrorMessage=`Пожалуйста, исправьте ошибки!`
  &successMessage=`Ваше сообщение успешно отправлено`
]]
MODX FormIt - Валидация файлов вложенных в форму на сервере
MODX FormIt - Валидация файлов вложенных в форму на сервере

Проверка формы с возможностью загрузки нескольких файлов (элемент input с name, равным files[]):

[[!AjaxForm? 
  &snippet=`FormIt` 
  &form=`tpl.AjaxForm.Attach` 
  &hooks=`FormItSaveForm,email`
  &customValidators=`formit2checkfiles`
  &emailSubject=`Тема письма`
  &emailTo=`my@email.ru`
  &emailFrom=`no-reply@mysite.ru`
  &emailFromName=`Мой сайт`
  &emailTpl=`tpl.email.attach`
  &validate=`name:required,email:required,message:required,files:formit2checkfiles`
  &validationErrorMessage=`Пожалуйста, исправьте ошибки!`
  &successMessage=`Ваше сообщение успешно отправлено`
]]
MODX FormIt - Пользовательский валидатор для проверки файлов на сервере
MODX FormIt - Пользовательский валидатор для проверки файлов на сервере


   MODX Revo 0    612 +1

Комментарии (0)

    Вы должны авторизоваться, чтобы оставлять комментарии.