При создании форм обратной связи часто возникает потребность в отправке файла. Например, мы хотим отправить рисунок, для заказа печати плакатов в копицентре. Помимо отправки, может еще потребоваться проверить файл на размер и формат. В нашем примере мы ограничим форматы только файлами изображений (png, jpg, jpeg, svg), а также можно задать максимальный размер 20 Мб (чтобы не перегружать сервер).
Полезные ссылки
Эта статья — четвертая из серии статей про формы обратной связи. В предыдущей статье реализовали отправку сообщения без перезагрузки страницы. Поэтому писать код будем на основе исходника из третьей статьи. Вам необходимо склонировать репозиторий:
git clone https://github.com/toni-wheel/youtube-responsive-contact-form-v3
Ссылки на предыдущие статьи:
- Форма обратной связи: пишем основу на HTML и CSS: https://codelab.pro/forma-obratnoj-svyazi-pishem-osnovu-na-html-i-css/
- Форма обратной связи: валидация формы на JS: https://codelab.pro/forma-obratnoj-svyazi-validacziya-formy-na-js/
- Форма обратной связи: отправка формы на почту без перезагрузки: 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.