Прикрепление в MODX файлов к форме с помощью FormIt

Содержание:
  1. Прикрепление файлов к форме FormIt
  2. Проверка расширений и размеров файлов на сервере
  3. Комментарии

Статья, в которой рассмотрим, как в 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 - Письмо с контактной формы
В компоненте 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 - Форма обратной связи (файл не прошёл проверку на сервере - размер файла не укладывается в 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 - Валидация файлов вложенных в форму на сервере

Проверка формы с возможностью загрузки нескольких файлов (элемент 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 - Пользовательский валидатор для проверки файлов на сервере

Комментарии: 52

lel
lel
Как сделать так, чтобы несколько файлов в можно было грузить поочередно, а не через ctrl все вместе?
Сергей Сергеевич
Сергей Сергеевич
Спасибо за опубликованное решение.
В моем случае (openserver php 7.2) форма без файлов не отправлялась, т.к ассоциативный массив $_FILES всегда существует.

// если ассоциатианый массив $_FILES[$keys] существует, то
if(isset($_FILES[$key]["error"])) {
Удалил эту ветку и все заработало.

else {
      // произошла ошибка при загрузке файла на сервер
      $errorMsg = 'Произошла ошибка при загрузке файла ' . $fileName .' на сервер.';
      $validator->addError($key,$errorMsg);
      $output = false; // возвращаем false
      break;
    }
Как можно сделать по изящному, проверку в самом начале? Чтобы форма отправлялась без файла?
lel
lel
Такая же проблема
lel
lel
Добавила ветку elseif ($error == UPLOAD_ERR_NO_FILE) {
$output = true;
break;
}

отправляет без файлов
Сергей
Сергей

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

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

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

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

Не подскажете, где рыть? Буду очень благодарен Вам!
Виталий
Виталий
PS: FormIt 4.1.0, AjaxForm 1.1.9, Modx 2.6.4
Александр Мальцев
Александр Мальцев
Добрый день!
Собрал новую сборку с указанными выше версиями; оба варианта отрабатывают отлично. Как с использованием атрибута multiple, так и с использованием нескольких input с type, равным file. Может что-то где-то пропустили. Обратите внимание, что для проверки формы с одним input и несколькими используются разные валидаторы.
Версия PHP: 7.1.12
Виталий
Виталий
Добрый день!
Спасибо Вам за быстрый ответ!
Может я не корректно описал проблему.
У меня тоже все работает, НО если не ставить
files:required
В моей форме должны быть обязательно прикрепленные файлы.
Вы проверяли с
files:required
?
Извините, если морочаю Вам голову…
Версия PHP: 7.2.х64
Александр Мальцев
Александр Мальцев
Можно все условия прописать в formit2checkfiles. Например, на определённое количество файлов. Функция required скорее всего в данном случае не позволяет это сделать.
Виталий
Виталий
Спасибо! Буду рыть дальше :)
Александр Мальцев
Александр Мальцев
А что там рыть. Необходимо просто добавить счётчик (например, необходимо чтобы пользователь прикрепил к сообщению не менее 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, чтобы отображались сразу все ошибки, а не по одной.
Виталий
Виталий
Супер! Большое Вам Спасибо!!!
Anna Shishkina
Anna Shishkina
Александр, здравствуйте!
Спасибо за статьи, очень помогают.
Вопрос по самой первой теме — при мультизагрузке загружается только последний прикрепленный файл. Думала может дело в моем коде, но скопировала ваш код — тоже не подгружаются все файлы. Хотя Formit переустановила на версию 2.2.11. Версия MODx 2.6.1. Что еще может быть причиной?
Владислав
Владислав
Приветствую! Огромное спасибо за статью! Получилось вывести форму и отправить файл, но есть проблема — отправляется только один файл, который загружен последним. Использую метод с 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=`Ваше сообщение успешно отправлено`
]]

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

Такую обработку необходимо выполнять в браузере (JavaScript). Т.е. после выбора файла вы проверяете его размер, и если он превышает допустимый, то выводите соответствующее сообщение и отменяете отправку формы на сервер.
Владимир
Владимир
Добрый день, не понимаю как сделать мультизагрузку через эту кнопку, используя 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'];
Владимир
Владимир
.
Владимир
Владимир
Вроде такой код работает. Может его можно как нибудь улучшить?

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;
Владимир
Владимир
Или так?

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;
Владимир
Владимир
Не понял как этим методом
<input type="file" name="uploads[]">
записать несколько файлов в папку :(
а потом вытащить имена файлов
$_FILES['uploads']['name']
Александр Мальцев
Александр Мальцев
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`
  ...
martFormS
martFormS
Шеф спасибо вам! Сделал, работает, но вот я еще сделал чтоб заявку и в телегу падали, и цепляю данные форм через хук и отсылаю в telegram чат, вот вопрос — возможно ли как через $modx->getOption подтянуть туда еще и [[+uploadFiles]] — хотябы линки на сохр. файлы, пробовал сам, ошибки лезут, да и не смогу, думаю многим тоже интересна тема такая, чтобы прикрепленные картинки падали не только в мыло но и в телегу и админку (тут ссылки и название файла тока на сохранный файл).
А если есть способ еще и в приложение в админку saveFormIt туда картинки выводить — вообще красота будет, искал гуглом на эту тему — тоже тишина, неужели никому не надо такое?

&hooks=`FormItSaveForm,savefiles,gramm-biggestForm,email,redirect`
martFormS
martFormS
нашел ответ на одну часть $upl = $hook->getValue('uploadFiles',$output);
Jstart
Jstart
не подскажешь где нашёл реализацию загрузки файлов для телеграмма?
Серый
Серый
Умоляю, подскажите как сделать так, что бы вложенное изображение можно было отобразить в теле письма.
Делаю <img src="[[+pic]]" — не пашет. Делаю <img src=«cid:[[+pic]]» — та ж фигня.
Что еще попробовать, что бы на мэйлре и гмэйле норм отображалось??
Александр Мальцев
Александр Мальцев
Для этого необходимо написать 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>
Серый
Серый
Александр, спасибо за ответ!
Скажите, пользовались ли вы AjaxUpload? Есть рецепт присоединения его к AjaxForm, правда я его до конца еще не испробовал
Мне очень нравится, что он показывает что фото загружено, но не нравится, что он не прячет кнопку «Загрузить» после последнего загруженного файла из числа дозволенных, и еще он какой-то корявенький))) Там видно, что есть возможность загрузки драг-н-дропом, но она спрятана и не работает)))
А еще языки не переключаются...((
Но вы просто ниндзя, я такие хуки писать покамест не умею(
Александр Мальцев
Александр Мальцев
Не пользовался. Может быть, это там как-то настраивается.
При желании, если не понравиться, можно же использовать и какой-то другой.
Серый
Серый
Александр, спасибо! Сработало!!!
Еще один малюсенький вопросик, а как сделать так, что бы при этой нашей манипуляции загружаемый в форму файл из атача письма не пропадал? Потому что если удалить из набора хуков наш saveFile — то картинка в атаче письма есть, а если вернуть — картинка есть в теле письма через ссылку, но отсутствует в атаче((
Помогите пожалуйста!

Для тех кто пойдет моим путем — сообщаю — папку /assets/uploads нужно создавать вручную ;)
Серый
Серый
Вобщем, глобальная идея в том, что бы в тело письма вставлять миниатюру (я её каким-нибудь pThumb`ом в tpl`ке письма организую) и прилагать оригинал фото. Типа досье такое)
Заранее большое человеческое спасибо
Александр Мальцев
Александр Мальцев
Для этого файл необходимо не перемещать, а копировать. Иначе он не достанется хуку 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>
surfrider
surfrider
Нет в fihooks строки if(count($v['name']) > 1){

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