При создании форм обратной связи часто возникает потребность в отправке файла. Например, мы хотим отправить рисунок, для заказа печати плакатов в копицентре. Помимо отправки, может еще потребоваться проверить файл на размер и формат. В нашем примере мы ограничим форматы только файлами изображений (png, jpg, jpeg, svg), а также можно задать максимальный размер 20 Мб (чтобы не перегружать сервер).

Полезные ссылки

Эта статья — четвертая из серии статей про формы обратной связи. В предыдущей статье реализовали отправку сообщения без перезагрузки страницы. Поэтому писать код будем на основе исходника из третьей статьи. Вам необходимо склонировать репозиторий:

git clone https://github.com/toni-wheel/youtube-responsive-contact-form-v3

Ссылки на предыдущие статьи:

  1. Форма обратной связи: пишем основу на HTML и CSS: https://codelab.pro/forma-obratnoj-svyazi-pishem-osnovu-na-html-i-css/
  2. Форма обратной связи: валидация формы на JS: https://codelab.pro/forma-obratnoj-svyazi-validacziya-formy-na-js/
  3. Форма обратной связи: отправка формы на почту без перезагрузки: https://codelab.pro/forma-obratnoj-svyazi-otpravka-formy-na-pochtu-bez-perezagruzki/

Разметка

Вся разметка находится в элементе с классом file-box:

<div class="file-box">
  <div class="file__field">
    <input type="file" name="file" id="file" />
    <label class="file__btn" id="file_btn" for="file">Выберите файл</label>
    <div class="file__info">
      <div class="file__name" id="file_name"></div>
      <div class="file__btn-close" id="file_btn_close"></div>
    </div>
  </div>
  <div class="file__hint">
    <span>Максимум 20 Мб;</span>
    <span>В формате jpeg, jpg, png, gif, svg</span>
  </div>
</div>

Здесь:

  • file__btn — кнопка для выбора файла
  • file__name — имя файла (после его загрузки)
  • file__close — кнопка для удаления файла
  • file__hint — требования к загружаемому файлу

Мы не будем использовать стандартный инпут (далее в стилях его уберем). Вместо этого создадим свою кнопку file__btn, которая будет ссылаться на инпут.

Стили

Комментарии приведены в коде.

/* Стилизуем бокс для загрузки файла */
.file-box {
  display: flex;
  flex-direction: column;
  width: 100%;
  margin-bottom: 30px;
}

/* Стилизуем поле с кнопкой и названием файла */
.file__field {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
}

/* Убираем дефолтный инпут */
#file {
  display: none;
}

/* Стилизуем кнопку загрузки файла */
.file__btn {
  display: inline-block;
  color: #fff;
  font-size: 15px;
  background-color: #3e2093;
  outline: none;
  border: none;
  padding: 10px 20px;
  border-radius: 7px;
  transition: 0.2s;
  cursor: pointer;
}

.file__btn:hover {
  background-color: #4517c2;
}

/* Стилизуем поле с названием файла и кнопкой закрыть */
.file__info {
  display: flex;
  align-items: center;
  padding: 0 10px;
  margin-left: 10px;
}

.file__name {
  margin-bottom: 4px;
  color: #888;
  font-size: 14px;
  word-spacing: 1px;
  user-select: none;
}

.file__btn-close {
  background: none;
  outline: none;
  border: none;
  font-size: 20px;
  color: red;
  margin-left: 5px;
  cursor: pointer;
  padding: 3px;
  font-weight: bold;
}

/* Стилизуем поле с подсказками */
.file__hint {
  color: #516d7b;
  font-size: 14px;
}

Скрипт

Комментарии даны в коде.

// Считываем нужные элементы
const file = document.querySelector("#file");
const fileName = document.querySelector("#file_name");
const fileBtnClose = document.querySelector("#file_btn_close");
// Задаем максимальный размер файла 20 Мб
const maxSize = 20 * 1024 * 1024;

// При загрузки файла - вызываем функцию проверки файла
file.addEventListener("change", (e) => {
  checkFile(file.files[0]);
});

// Обработчик кнопки удаления файла
fileBtnClose.addEventListener("click", (e) => {
  e.preventDefault();
  fileReset();
});

// Функция проверки файла
function checkFile(file) {
  // проверяем тип файла
  if (
    ![
      "image/jpeg",
      "image/jpg",
      "image/png",
      "image/gif",
      "image/svg+xml",
    ].includes(file.type)
  ) {
    alert("Разрешены только указанные форматы");
    fileReset();
    return;
  }

  // проверяем размер файла (<20 Мб)
  if (file.size > maxSize) {
    alert("Файл должен быть менее 20 Мб");
    fileReset();
    return;
  }
  showFileName(file);
}

// Сброс полей поля файла
function fileReset() {
  file.value = ""; // удаляем сам файл
  fileName.textContent = ""; // удаляем имя файла
  fileBtnClose.textContent = ""; // убираем кнопку удаления
}

// Выводим имя файла и кнопку удаления
function showFileName(file) {
  fileName.textContent = file.name;
  fileBtnClose.textContent = "×";
}

Чтобы файл отправлялся, необходимо в существующую функцию formSubmit добавить код.

async function formSubmit() {
  const data = serializeForm(form);
  data.append("image", file.files[0]); // добавить
  //   остальной код ..
}

Добавляем файл к письму

В скрипте send_mail.php необходимо добавить PHP-код, для того, чтобы приложить файл к письму.

// .. остальной код

if (!empty($_FILES["image"]["tmp_name"])) {
    // путь загрузки файла
    $filePath = __DIR__ . "/" . $_FILES["image"]["name"];
    // грузим файл
    if (copy($_FILES["image"]["tmp_name"], $filePath)) {
        $fileAttach = $filePath;
        $mail->addAttachment($fileAttach);
    }
}

// .. остальной код

Исходник из урока

Скачать исходный код из данного урока вы можете по ссылке из моего GitHub.

 

 


Warning: Undefined variable $aff_bottom_mark in /sites/codelab.pro/wp-content/themes/myTheme/dist/partials/post/post_base.php on line 81

Warning: Undefined variable $aff_bottom_info in /sites/codelab.pro/wp-content/themes/myTheme/dist/partials/post/post_base.php on line 85