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

Александр Мальцев
17K
4

Статья, в которой рассмотрим, как в 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 (до версии 2.2.11) существует ошибка, которая не позволяет отправлять один файл с помощью элемента 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 - Пользовательский валидатор для проверки файлов на сервере

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

  1. Сергей
    Сегодня в 08:16

    itchief.ru/assets/uploadify/1/0/f/10f16846960502829918780c02862abe.jpg

    Все работает спасибо вам за работу. Только кнопке «обзор» хотелось бы придать цвет в общем вот эти стали class=«zakazat» подскажите пожалуйста как это сделать. к комментарию картинку пробовал прикрепить если получилось посмотрите. Прикрепление файла для одного те первый вариант с вашего сайта.
    1. Александр Мальцев
      3 часа назад
      Пожалуйста! Стилизация элемента input с type="file" очень сильна ограничена в большинстве браузеров. Чтобы это выполнить обычно используют следующий подход, который заключается в скрытии оригинального input с type="file" и использовании для этого элемента label (пример).
      1. Сергей
        3 минуты назад
        спасибо работает
    2. Александр
      17 ноября 2020, 14:08
      Здравствуйте! Добавил к существующей форме, все работает, кроме одного, кнопка отображается как «выбрать файл», после присвоения класса и стилей, поверх этой кнопки появляется нужная, но при этом «выберите файл» так и остается. Подскажите, пожалуйста, как можно исправить. П.С. — я новичок и скорее всего просто не догоняю, что делаю не так. Часть кода с кнопкой:

      <div class="form-group">
       <label for="upload__button" class="production__button">Прикрепить файл</label>
              <span class="bar"></span>
              <input name="files[]" type="file" id="upload__button" multiple="multiple">
              <p class="error_files">[[+fi.error.files]]</p>
      </div>
      
      1. Александр Мальцев
        18 ноября 2020, 15:01
        Здравствуйте!
        Всё правильно, вы отображаете label, a input скрываете. Как в этом случае что-то может появиться в label? Здесь необходимо использовать JavaScript.
        Например:
        <script>
        const uploadBtn = document.querySelector('#upload__button');
        uploadBtn.onchange = (e) => {
          let nameFile = '';
          const $target = e.target;
          if ($target.files && $target.files.length > 1)
            nameFile = `Выбрано файлов: ${$target.files.length}`;
          else {
            nameFile = $target.value.split('\\').pop();
          }
          const $label = $target.parentElement.querySelector('label');
          nameFile = nameFile ? nameFile : 'Выбрать файлы';
          $label.textContent = nameFile;
        }
        </script>
        
      2. Максим
        25 августа 2020, 12:23
        Александр, добрый день.
        Сделал проверку «расширений и размеров файлов на сервере»
        По вашему описанию, но она не работает.
        Подключение AjaxForm:
        [[AjaxForm?
        &snippet=`FormIt`
        &hooks=`spam,email`
        &customValidators=`formit1checkfile`
        &emailFrom=`мой адрес`
        &form=`tpl.AjaxForm`
        &emailTpl=`modal-zv-tpl`
        &emailTo=`мой адрес`
        &emailSubject=`Отклик на вакансию`
        &validate=`phone-zv:required, name-zv:required, upload: formit1checkfile`
        &validationErrorMessage=`Пожалуйста, заполните поля помеченные *`
        &successMessage=`Сообщение успешно отправлено, наш специалист свяжется с вами!`
        ]]

        Чанк:


        [[+fi.error.upload]]



        Снипет:

        <?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;
        1. Владислав
          30 июля 2020, 20:27
          Александр, добрый вечер. Подскажите пожалуйста а как можно сделать вывод об успешной загрузке всех файлов? То есть когда все файлы прошли валидацию — вывести «Файлы успешно загружены», подскажите что необходимо исправить для массива файлов?
          1. Дмитрий
            20 февраля 2020, 19:33
            Александр, добрый вечер!
            У меня на сайте byantipov.ru есть блок с
            id="interview"
            . Это, грубо говоря, опросник из нескольких шагов для точного расчета стоимости кухни. На последнем шаге есть окно с возможностью добавления файла, например, картинки. На самом последнем шаге, при нажатии на кнопку «Заказать» скриптом собираются значения всех инпутов, которые отправляются в соответствующие
            <input type="hidden">
            , которые уже дальше отправляются на почту и администратору и клиенту. Только файл не отправляется, вместо файла приходит только путь, по которому находится этот файл.
            Подскажите, как можно сделать чтобы отправлялся именно файл.
            1. Александр Мальцев
              21 февраля 2020, 14:59
              Добрый день! Как это сделать описано в этой статье: Форма с вложением
            2. Виталий
              09 июля 2018, 20:43
              Александр, здравствуйте!
              Спасибо за Ваш труд, узнал у Вас много полезного.
              У меня вопрос: при мультизагрузке все файлы загружаются и отправляются, но если поставить валидацию
              &validate=`name:required,email:required,files:required:formit2checkfiles`
              , сообщение об ошибке выводится, но после добавления файла(ов) не пропадает, и файлы не отправляются. В одиночной загрузке валидация работает прекрасно.

              Весть код для теста скопировал с Вашего сайта, все по дефолту.

              Не подскажете, где рыть? Буду очень благодарен Вам!
              1. Виталий
                09 июля 2018, 20:47
                PS: FormIt 4.1.0, AjaxForm 1.1.9, Modx 2.6.4
                1. Александр Мальцев
                  10 июля 2018, 14:40
                  Добрый день!
                  Собрал новую сборку с указанными выше версиями; оба варианта отрабатывают отлично. Как с использованием атрибута multiple, так и с использованием нескольких input с type, равным file. Может что-то где-то пропустили. Обратите внимание, что для проверки формы с одним input и несколькими используются разные валидаторы.
                  Версия PHP: 7.1.12
                  1. Виталий
                    10 июля 2018, 14:59
                    Добрый день!
                    Спасибо Вам за быстрый ответ!
                    Может я не корректно описал проблему.
                    У меня тоже все работает, НО если не ставить
                    files:required
                    В моей форме должны быть обязательно прикрепленные файлы.
                    Вы проверяли с
                    files:required
                    ?
                    Извините, если морочаю Вам голову…
                    Версия PHP: 7.2.х64
                    1. Александр Мальцев
                      10 июля 2018, 15:23
                      Можно все условия прописать в formit2checkfiles. Например, на определённое количество файлов. Функция required скорее всего в данном случае не позволяет это сделать.
                      1. Виталий
                        10 июля 2018, 15:25
                        Спасибо! Буду рыть дальше :)
                        1. Александр Мальцев
                          10 июля 2018, 16:49
                          А что там рыть. Необходимо просто добавить счётчик (например, необходимо чтобы пользователь прикрепил к сообщению не менее 3 файлов).
                          <?php
                          $output = true;
                          $count_files = 0; // счётчик файлов
                          $errorMsg = ''; // сообщение об ошибке
                          $allowedExt = array('jpg','png'); // разрешённые расширения файлов
                          $maxFileSize = 512 * 1024; // максимальный размер файла (512 Кбайт)
                          if (isset($_FILES[$key])) {
                            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)) {
                                  if (!empty($errorMsg)) {
                                    $errorMsg .= '; ';
                                  }
                                  $errorMsg .= 'Файл ' . $fileName . ' имеет не разрешённый тип.';
                                  continue;
                                }
                                if ($fileSize > $maxFileSize) {
                                  if (!empty($errorMsg)) {
                                    $errorMsg .= '; ';
                                  }
                                  $errorMsg .= 'Файл '. $fileName .' имеет не разрешённый размер.';
                                  continue;
                                }
                                $count_files++; // увеличиваем на 1
                              } else {
                                if (!empty($errorMsg)) {
                                  $errorMsg .= '; ';
                                }
                                $errorMsg .= 'Произошла ошибка при загрузке файла ' . $fileName .' на сервер.';
                              }
                            }
                          }
                          if ($count_files < 3) {
                            if (!empty($errorMsg)) {
                              $errorMsg .= '; ';
                             }
                             $errorMsg .= 'К сообщению необходимо прикрепить 3 файла!';
                          }
                          if (!empty($errorMsg)) {
                            $validator->addError($key,$errorMsg);
                            $output = false; // возвращаем false
                          }
                          return $output;
                          
                          Конструкции break заменил на continue, чтобы отображались сразу все ошибки, а не по одной.
                          1. Виталий
                            10 июля 2018, 18:24
                            Супер! Большое Вам Спасибо!!!
              2. Anna Shishkina
                04 марта 2018, 09:14
                Александр, здравствуйте!
                Спасибо за статьи, очень помогают.
                Вопрос по самой первой теме — при мультизагрузке загружается только последний прикрепленный файл. Думала может дело в моем коде, но скопировала ваш код — тоже не подгружаются все файлы. Хотя Formit переустановила на версию 2.2.11. Версия MODx 2.6.1. Что еще может быть причиной?
                1. Владислав
                  05 июня 2017, 20:30
                  Приветствую! Огромное спасибо за статью! Получилось вывести форму и отправить файл, но есть проблема — отправляется только один файл, который загружен последним. Использую метод с name=«files[]». Вот код чанка (для удобства оставил только проблемное поле):
                  <form action="" method="post" enctype="multipart/form-data">
                  
                      <div class="file-upload">
                          <label for="uploadbtn1" class="uploadbtn">Загрузить файл</label>
                          <span class="bar"></span>
                          <input style="display:none;" name="files[]" type="file" id="uploadbtn1" multiple="multiple">
                      </div>
                      <div class="clear"></div>
                      <p class="error_files">[[+fi.error.files]]</p>
                      
                      <div class="wrap-submit">
                          <div class="wrap-contacts-form-submit">
                              <input class="contacts-form-submit" type="submit" value="Отправить" /><span></span>
                          </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>
                  
                  Вот так вывожу сниппет:
                  [[!AjaxForm?
                  &snippet=`FormIt`
                  &form=`lid-form`
                  &hooks=`FormItSaveForm,email`
                  &emailSubject=`Заявка с сайта`
                  &emailTo=`vladklevtsov@gmail.com`
                  &emailFrom=`no-reply@mysite.ru`
                  &emailFromName=`Сайт Get All`
                  &emailTpl=`email_tpl`
                  &validate=`name:required,phone:required`
                  &validationErrorMessage=`Пожалуйста, исправьте ошибки!`
                  &successMessage=`Ваше сообщение успешно отправлено`
                  ]]

                  Подскажите, пожалуйста, в чем может быть причина? Почему не прикрепляется несколько файлов, а только один?
                  1. Владислав
                    06 июня 2017, 10:02
                    Обновил AjaxForm на свою голову… Теперь совсем файлы не отправляются
                    1. Александр Мальцев
                      06 июня 2017, 15:28
                      Дело не AjaxForm, а в FormIt. Чтобы всё это работало, используйте FormIt 2.2.11. Попробовал обновить FormIt до 3.0.2 — multiple файлы не прикрепляются. Откатился назад до 2.2.11 — всё отлично.
                      1. Владислав
                        07 июня 2017, 20:27
                        Александр, Ты крут! Все получилось, файлы отправляются!
                  2. Kira
                    29 мая 2017, 11:04
                    Здравствуйте
                    Если прикрепляю к форме файлы размером около 10 Мб, то в одном случае появляется сообщение об ошибке — «Не указан ключ формы (action).» или же форма просто зависает. В чем может быть причина?
                    1. Александр Мальцев
                      29 мая 2017, 11:24
                      Здравствуйте. Это ограничение устанавливается на стороне сервера.
                      Например, в файле .htaccess (до 30Мбайт):
                      php_value post_max_size 30M
                      php_value upload_max_filesize 30M
                      
                      1. Kira
                        29 мая 2017, 12:07
                        Спасибо. Да, дело действительно связано с этим. Получается, если размер файла будет больше значения прописанного в .htaccess, то будет появляться сообщение «Не указан ключ формы (action).», независимо от значения прописанного в formit2checkfile?
                        1. Александр Мальцев
                          29 мая 2017, 16:27
                          Да, если вы укажите эти параметры, то никакие php-скрипты не будут обрабатывать эту форму, если её длина POST будет превышать 30М. Т.е. в php вы это не сделаете, т.к. он просто не получит управление.

                          Такую обработку необходимо выполнять в браузере (JavaScript). Т.е. после выбора файла вы проверяете его размер, и если он превышает допустимый, то выводите соответствующее сообщение и отменяете отправку формы на сервер.
                    2. Владимир
                      02 мая 2017, 05:33
                      Добрый день, не понимаю как сделать мультизагрузку через эту кнопку, используя saveFile
                      <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>
                      Если использовать этот метод, то хук Хук saveFile уже не работает.
                      Мне необходима возможность отправлять файлы на почту и вдобавок сохранять файлы в папке и вытаскивать их имена:
                      $_FILES['upload']['name'];
                      $_FILES['upload1']['name'];
                      $_FILES['upload2']['name'];
                      1. Александр Мальцев
                        03 мая 2017, 15:44
                        1. Создать сниппет saveFiles. Например, со следующим содержимым:
                        <?php
                        if(isset($_FILES['uploads'])) {
                          $files = array();
                          foreach ($_FILES['uploads']['error'] as $key => $error) {  
                            if ($error == UPLOAD_ERR_OK) {
                              $nameFile = $_FILES['uploads']['name'][$key];
                              $extFile = mb_strtolower(pathinfo($nameFile, PATHINFO_EXTENSION));
                              $newNameFile = 'assets/uploads/'. uniqid('',true).'.'.$extFile; 
                              if (copy($_FILES['uploads']['tmp_name'][$key],MODX_BASE_PATH.$newNameFile)) {
                                $files[] = $modx->getChunk('tpl.email.uploads', array(
                                  'name' => $nameFile,
                                  'url' => MODX_BASE_PATH.$newNameFile
                                ));
                              }
                            }
                          }
                          $output = implode("
                        ", $files);
                          $hook->setValue('uploadFiles',$output);
                        }
                        return true;
                        
                        2. Создать чанк tpl.email.uploads (для оформления отдельной ссылки на файл в теле письма):
                        <a href="[[+url]]">[[+name]]</a>
                        3. Добавить в tpl.email.attach плейсхолдер [[+uploadFiles]], в который будут выводиться ссылки на файлы:
                        <p>Сообщение с формы обратной связи:</p>
                        <hr>
                        <p>От кого: [[+name]]</p>
                        <p>E-mail: [[+email]]</p>
                        <p>Сообщение: [[+message]]</p>
                        <p>Файлы:</p>
                        [[+uploadFiles]]
                        
                        4. Добавить перед email созданный хук:
                        [[!AjaxForm? 
                          &snippet=`FormIt` 
                          &form=`tpl.AjaxForm.Attach` 
                          &hooks=`saveFiles,email`
                          ...
                        
                        1. martFormS
                          24 декабря 2018, 22:28
                          Шеф спасибо вам! Сделал, работает, но вот я еще сделал чтоб заявку и в телегу падали, и цепляю данные форм через хук и отсылаю в telegram чат, вот вопрос — возможно ли как через $modx->getOption подтянуть туда еще и [[+uploadFiles]] — хотябы линки на сохр. файлы, пробовал сам, ошибки лезут, да и не смогу, думаю многим тоже интересна тема такая, чтобы прикрепленные картинки падали не только в мыло но и в телегу и админку (тут ссылки и название файла тока на сохранный файл).
                          А если есть способ еще и в приложение в админку saveFormIt туда картинки выводить — вообще красота будет, искал гуглом на эту тему — тоже тишина, неужели никому не надо такое?

                          &hooks=`FormItSaveForm,savefiles,gramm-biggestForm,email,redirect`
                          1. martFormS
                            24 декабря 2018, 22:47
                            нашел ответ на одну часть $upl = $hook->getValue('uploadFiles',$output);
                        2. Владимир
                          02 мая 2017, 07:33
                          .
                          1. Владимир
                            02 мая 2017, 07:54
                            Вроде такой код работает. Может его можно как нибудь улучшить?

                            if (isset($_FILES['upload'])) {
                              if ($_FILES['upload']['error']==0) {
                                $nameFile = $_FILES['upload']['name'];
                                $extFile = mb_strtolower(pathinfo($nameFile, PATHINFO_EXTENSION));
                                $uniqNameFile = uniqid('file_', true).'.'.$extFile;
                                $newNameFile = 'assets/uploads/'. $nameFile;
                                if (copy($_FILES['upload']['tmp_name'],MODX_BASE_PATH.$newNameFile)) {
                                  $hook->setValue('uploadFile',$modx->config['site_url'].$newNameFile);
                                  $hook->setValue('uploadFileName',$nameFile);
                                 
                                }
                              }
                            }
                            
                            if (isset($_FILES['upload1'])) {
                              if ($_FILES['upload1']['error']==0) {
                                $nameFiles = $_FILES['upload1']['name'];
                                $extFiles = mb_strtolower(pathinfo($nameFiles, PATHINFO_EXTENSION));
                               $newNameFiles = 'assets/uploads/'. $nameFiles;
                              if (copy($_FILES['upload1']['tmp_name'],MODX_BASE_PATH.$newNameFiles)) {
                                  $hook->setValue('uploadFile',$modx->config['site_url'].$newNameFiles);
                                  $hook->setValue('uploadFileName',$nameFiles);
                                  return true;
                                }
                              }
                            }
                            return false;
                            1. Владимир
                              02 мая 2017, 08:11
                              Или так?

                              if (isset($_FILES['upload'])) {
                              
                              
                              if ($_FILES['upload']['error']==0) {
                                  $nameFile = $_FILES['upload']['name'];
                                  $extFile = mb_strtolower(pathinfo($nameFile, PATHINFO_EXTENSION));
                                 $newNameFile = 'assets/uploads/'. $nameFile;
                                  
                              
                              if (copy($_FILES['upload']['tmp_name'],MODX_BASE_PATH.$newNameFile)) {
                                    $hook->setValue('uploadFile',$modx->config['site_url'].$newNameFile);
                                    $hook->setValue('uploadFileName',$nameFile);
                              }
                              }
                              }
                              
                              if (isset($_FILES['upload1'])) {
                                if ($_FILES['upload1']['error']==0) {
                                  $nameFiles = $_FILES['upload1']['name'];
                                  $extFiles = mb_strtolower(pathinfo($nameFiles, PATHINFO_EXTENSION));
                                 $newNameFiles = 'assets/uploads/'. $nameFiles;
                                if (copy($_FILES['upload1']['tmp_name'],MODX_BASE_PATH.$newNameFiles)) {
                                    $hook->setValue('uploadFile',$modx->config['site_url'].$newNameFiles);
                                    $hook->setValue('uploadFileName',$nameFiles);
                                   
                                  }
                                }
                              } return true;
                              1. Владимир
                                03 мая 2017, 14:52
                                Не понял как этим методом
                                <input type="file" name="uploads[]">
                                записать несколько файлов в папку :(
                                а потом вытащить имена файлов
                                $_FILES['uploads']['name']
                        3. Серый
                          19 марта 2017, 20:30
                          Умоляю, подскажите как сделать так, что бы вложенное изображение можно было отобразить в теле письма.
                          Делаю <img src="[[+pic]]" — не пашет. Делаю <img src=«cid:[[+pic]]» — та ж фигня.
                          Что еще попробовать, что бы на мэйлре и гмэйле норм отображалось??
                          1. Александр Мальцев
                            21 марта 2017, 11:45
                            Для этого необходимо написать hook для FormIt.
                            Например, для элемента input с именем upload:
                            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. Создать сниппет, например, имеющим имя saveFile:
                            <?php
                            if (isset($_FILES['upload'])) {
                              if ($_FILES['upload']['error']==0) {
                                $nameFile = $_FILES['upload']['name'];
                                $extFile = mb_strtolower(pathinfo($nameFile, PATHINFO_EXTENSION));
                                $uniqNameFile = uniqid('file_', true).'.'.$extFile;
                                $newNameFile = 'assets/uploads/'. $uniqNameFile;
                                if (move_uploaded_file($_FILES['upload']['tmp_name'], MODX_BASE_PATH.$newNameFile)) {
                                  $hook->setValue('upload',$modx->config['site_url'].$newNameFile);
                                  $hook->setValue('uploadName',$uniqNameFile);
                                  return true;
                                }
                              }
                            }
                            return false;
                            
                            Данный снипет (хук) будет перемещать файл под уникальным именем в каталог /assets/uploads и устанавливать значения ключам upload (URL файла) и uploadName (имя файла).
                            3. Добавить в вызов сниппета AjaxForm только что созданный хук (saveFile) перед email:
                            [[!AjaxForm? 
                              ...
                              &hooks=`saveFile,email`
                              ...
                            
                            4. В шаблон письма добавить:
                            <p><a href="[[+upload]]">[[+uploadName]]</a></p>
                            
                            1. Серый
                              29 марта 2017, 10:25
                              Александр, спасибо! Сработало!!!
                              Еще один малюсенький вопросик, а как сделать так, что бы при этой нашей манипуляции загружаемый в форму файл из атача письма не пропадал? Потому что если удалить из набора хуков наш saveFile — то картинка в атаче письма есть, а если вернуть — картинка есть в теле письма через ссылку, но отсутствует в атаче((
                              Помогите пожалуйста!

                              Для тех кто пойдет моим путем — сообщаю — папку /assets/uploads нужно создавать вручную ;)
                              1. Александр Мальцев
                                30 марта 2017, 16:33
                                Для этого файл необходимо не перемещать, а копировать. Иначе он не достанется хуку email. А также изменить ключ при установке хуком значения.
                                Хук saveFile будет иметь следующий код:
                                <?php
                                if (isset($_FILES['upload'])) {
                                  if ($_FILES['upload']['error']==0) {
                                    $nameFile = $_FILES['upload']['name'];
                                    $extFile = mb_strtolower(pathinfo($nameFile, PATHINFO_EXTENSION));
                                    $uniqNameFile = uniqid('file_', true).'.'.$extFile;
                                    $newNameFile = 'assets/uploads/'. $uniqNameFile;
                                    if (copy($_FILES['upload']['tmp_name'],MODX_BASE_PATH.$newNameFile)) {
                                      $hook->setValue('uploadFile',$modx->config['site_url'].$newNameFile);
                                      $hook->setValue('uploadFileName',$uniqNameFile);
                                      return true;
                                    }
                                  }
                                }
                                return false;
                                
                                В чанке письма изменить имена плейсхолдеров на следующие:
                                <p><a href="[[+uploadFile]]">[[+uploadFileName]]</a></p>
                                
                                1. Серый
                                  29 марта 2017, 14:38
                                  Вобщем, глобальная идея в том, что бы в тело письма вставлять миниатюру (я её каким-нибудь pThumb`ом в tpl`ке письма организую) и прилагать оригинал фото. Типа досье такое)
                                  Заранее большое человеческое спасибо
                                2. Серый
                                  21 марта 2017, 11:57
                                  Александр, спасибо за ответ!
                                  Скажите, пользовались ли вы AjaxUpload? Есть рецепт присоединения его к AjaxForm, правда я его до конца еще не испробовал
                                  Мне очень нравится, что он показывает что фото загружено, но не нравится, что он не прячет кнопку «Загрузить» после последнего загруженного файла из числа дозволенных, и еще он какой-то корявенький))) Там видно, что есть возможность загрузки драг-н-дропом, но она спрятана и не работает)))
                                  А еще языки не переключаются...((
                                  Но вы просто ниндзя, я такие хуки писать покамест не умею(
                                  1. Александр Мальцев
                                    21 марта 2017, 12:16
                                    Не пользовался. Может быть, это там как-то настраивается.
                                    При желании, если не понравиться, можно же использовать и какой-то другой.
                              2. surfrider
                                11 февраля 2017, 00:20
                                Нет в fihooks строки if(count($v['name']) > 1){

                                FormIt 2.2.11
                                1. Александр Мальцев
                                  13 февраля 2017, 13:55
                                  Эту ошибку (#104) исправили в последнем обновлении 2.2.11. Поэтому в дополнении FormIt начиная с версии 2.2.11 ничего исправлять не надо.
                                2. Ivan
                                  13 января 2017, 15:37
                                  Текст в письмах не сохраняет пользовательское форматирование (принудительный перенос строк, лишние пробелы). В письме весь текст идет одним абзацем. Оборачивал
                                  <textarea>
                                  в
                                  <pre>
                                  но не помогло. Как исправить?
                                  1. Александр Мальцев
                                    15 января 2017, 02:04
                                    Это сделано из-за безопасности.
                                    Чтобы это отключить нужно к полю message добавить allowSpecialChars:
                                    &validate=`name:required,email:required,message:required:allowTags:allowSpecialChars,files:formit2checkfiles`
                                    
                                    1. Ivan
                                      15 января 2017, 14:20
                                      что-то не работает, у меня вот такая строка:
                                      &validate=`nameFF:required,contactFF:required,messageFF:required,g-recaptcha-response:required`
                                      а после добавления вот так:
                                      &validate=`nameFF:required,contactFF:required,messageFF:required:allowTags:allowSpecialChars,g-recaptcha-response:required`
                                      1. Александр Мальцев
                                        16 января 2017, 13:07
                                        Не знаю, должно работать.
                                  Войдите, пожайлуста, в аккаунт, чтобы оставить комментарий.