
📤 Загрузка файлов перетаскиванием с Dropzone.js и PHP
Пользователи ждут, что файлы на сайт можно закинуть просто перетащив их в окно браузера. Кнопка «Выберите файл» и проводник уже воспринимаются как лишнее движение. Но писать drag-and-drop с нуля на JavaScript, это несколько сотен строк кода, прогресс-бары, превью и обработка ошибок. К счастью, есть готовая библиотека, которая закрывает всё это из коробки.
Dropzone.js, open-source JavaScript-библиотека для загрузки файлов перетаскиванием. Показывает превью изображений, прогресс-бар и не требует jQuery. Работает с любым серверным языком: PHP, Node.js, Python. В этом руководстве, полный цикл от установки до продакшен-настройки за шесть шагов.
💡 Быстрый обзор:
- В чём смысл: библиотека Dropzone.js превращает любой HTML-элемент в зону для перетаскивания файлов с AJAX-отправкой на сервер.
- Как установить: CDN-ссылка (unpkg или jsDelivr) либо npm-пакет, оба варианта рассмотрены в первом шаге.
- Как обработать на сервере: PHP-скрипт принимает файл через
$_FILES, как обычную форму, третий шаг с готовым кодом. - Где применить: контактные формы с вложениями, загрузка аватаров, массовый импорт изображений в галерею WordPress.
Шаг 1: Установка Dropzone.js
Самый быстрый способ, подключить библиотеку через CDN. Добавьте этот тег в <head> страницы:
1 <script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
CSS-файл подключается отдельно:
1 <link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" />
Если пользуетесь сборщиком, устанавливайте через npm:
1 npm install dropzone
И импортируйте в своём JS-файле:
1 import Dropzone from "dropzone";
Обратите внимание: версия 5.9, последняя стабильная на начало 2026 года. Шестая версия в статусе beta, для продакшена пока не рекомендуется. Репозиторий проекта теперь живёт по адресу github.com/dropzone/dropzone (ранее был enyo/dropzone).
Шаг 2: Базовая HTML-разметка и инициализация
Создайте форму с классом dropzone. Dropzone автоматически найдёт её и превратит в зону для перетаскивания:
1 <form action="/upload.php" 2 class="dropzone" 3 id="my-dropzone"></form>
Всё. Когда пользователь перетащит файл в эту форму, библиотека отправит его AJAX-запросом по адресу из атрибута action. На серверной стороне файл попадёт в $_FILES['file'], точно как при обычной отправке через <input type="file">.

Если нужен fallback для браузеров без JavaScript, добавьте внутрь формы обычное поле:
1 <form action="/upload.php" class="dropzone"> 2 <input name="file" type="file" multiple /> 3 </form>
Кнопка «Выберите файл» будет показана только когда JavaScript недоступен. При включённом JS Dropzone скроет её и отобразит свою зону перетаскивания.
Шаг 3: Обработка файлов на сервере
PHP-скрипт принимает загрузку так же, как обычную форму. Минимальный рабочий вариант:
1 <?php 2 if (!empty($_FILES)) { 3 $uploadDir = __DIR__ . '/uploads/'; 4 5 if (!is_dir($uploadDir)) { 6 mkdir($uploadDir, 0755, true); 7 } 8 9 $originalName = basename($_FILES['file']['name']); 10 $targetPath = $uploadDir . time() . '_' . $originalName; 11 12 if (move_uploaded_file($_FILES['file']['tmp_name'], $targetPath)) { 13 http_response_code(200); 14 echo json_encode(['status' => 'ok', 'file' => $targetPath]); 15 } else { 16 http_response_code(500); 17 echo json_encode(['status' => 'error', 'message' => 'Не удалось сохранить файл']); 18 } 19 }
Что здесь происходит:
- Скрипт создаёт папку
uploads/, если её нет. - К оригинальному имени файла добавляется
time(), это предотвращает конфликт имён. basename()обрезает возможные path-traversal-атаки (попытки выйти за пределы папки через../).- Dropzone ждёт от сервера HTTP 200, иначе считает загрузку проваленной и показывает ошибку.
Для продакшена добавьте ещё проверку расширения и MIME-типа:
1 $allowed = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'zip']; 2 $ext = strtolower(pathinfo($originalName, PATHINFO_EXTENSION)); 3 4 if (!in_array($ext, $allowed)) { 5 http_response_code(400); 6 echo json_encode(['status' => 'error', 'message' => 'Недопустимый тип файла']); 7 exit; 8 }
Шаг 4: Ограничение количества, размера и типа файлов
Три самые востребованные настройки Dropzone настраиваются через JavaScript-конфиг:
1 Dropzone.options.myDropzone = { 2 maxFiles: 10, 3 maxFilesize: 5, // В мегабайтах 4 acceptedFiles: 'image/*,.pdf', 5 dictDefaultMessage: 'Перетащите файлы сюда или кликните для выбора' 6 };
Разбор опций:
- maxFiles, сколько файлов пользователь может загрузить за раз. По умолчанию, без ограничений, в примере, не больше 10.
- maxFilesize, максимальный размер одного файла в мегабайтах. Значение 5 означает 5 МБ. В старых версиях библиотеки по умолчанию стояло 256 МБ, в актуальной 5.x, 256 тоже, поэтому явно укажите свой лимит.
- acceptedFiles, строка с MIME-типами через запятую. Шаблон
image/*разрешает любые изображения,.pdfдобавляет PDF к списку. Полный список MIME-типов смотрите в документации Dropzone. - dictDefaultMessage, RU-текст, который видит пользователь в пустой зоне загрузки.
Ключ myDropzone в Dropzone.options.myDropzone, это camelCase-версия HTML-атрибута id="my-dropzone". Дефисы отбрасываются, каждое следующее слово с заглавной: my-dropzone → myDropzone, file-upload-area → fileUploadArea.
Опция resizeWidth и resizeHeight позволяет уменьшать изображения на клиенте до отправки. Это экономит трафик пользователя и разгружает сервер, особенно когда посетители загружают фотографии с телефона по 10-15 МБ каждая. Указывайте оба параметра одновременно:
1 Dropzone.options.myDropzone = { 2 resizeWidth: 1200, 3 resizeHeight: 1200, 4 resizeQuality: 0.8, 5 resizeMethod: 'contain' 6 };
Метод contain вписывает изображение в заданные границы без обрезки, crop обрезает до точных размеров. Качество 0.8 на практике неотличимо от исходника, но уменьшает размер файла в 4-7 раз. Важно: ресайз работает только с image-файлами, PDF и архивы пропускаются как есть. Браузер выполняет ресайз через Canvas API, дополнительные библиотеки не нужны.
Шаг 5: Ручная отправка файлов
По умолчанию Dropzone отправляет файл на сервер сразу после добавления. Это не всегда удобно: бывает нужно дать пользователю заполнить поля формы рядом с зоной загрузки, а отправить всё одной кнопкой.
Отключаем автозагрузку флагом autoProcessQueue: false и вешаем отправку на внешнюю кнопку:
1 Dropzone.options.myDropzone = { 2 autoProcessQueue: false, 3 maxFilesize: 5, 4 init: function () { 5 const myDropzone = this; 6 const submitBtn = document.querySelector('#btnUpload'); 7 8 submitBtn.addEventListener('click', function () { 9 if (myDropzone.getQueuedFiles().length === 0) { 10 alert('Нет файлов для загрузки'); 11 return; 12 } 13 myDropzone.processQueue(); 14 }); 15 16 this.on('success', function (file, response) { 17 console.log('Файл загружен:', file.name); 18 }); 19 } 20 };
Ключевой момент здесь, метод processQueue(). Он запускает отправку всех файлов, накопленных в очереди. Событие success срабатывает для каждого файла отдельно, можно обновить интерфейс или записать ID загруженного файла в скрытое поле формы.
Шаг 6: Передача дополнительных данных вместе с файлом
Бывает нужно прикрепить к загрузке служебные параметры: ID пользователя, статус документа, выбранную категорию. В Dropzone для этого есть событие sending:
1 Dropzone.options.myDropzone = { 2 init: function () { 3 this.on('sending', function (file, xhr, formData) { 4 formData.append('status', 'draft'); 5 formData.append('user_id', currentUserId); 6 }); 7 8 this.on('success', function (file, responseText) { 9 console.log('Готово:', responseText); 10 }); 11 } 12 };
Событие sending вызывается прямо перед XMLHttpRequest-отправкой. Третий аргумент formData, стандартный объект FormData, к которому можно добавить любые пары «ключ-значение» через append(). На серверной стороне эти параметры читаются из $_POST['status'] и $_POST['user_id'].
Практический сценарий: пользователь выбирает альбом в выпадающем списке рядом с Dropzone-зоной, и ID альбома уходит вместе с каждым файлом, сервер сразу раскладывает загрузки по нужным папкам.
Безопасность: три правила, которые нельзя игнорировать
Перед тем как отдавать Dropzone на продакшен, проверьте три момента.
Первое. Всегда валидируйте тип и размер файла на серверной стороне, даже если уже настроили acceptedFiles и maxFilesize в JS. Клиентские ограничения обходятся за минуту через консоль браузера. Серверный фильтр, единственная реальная защита.
Второе. Храните загруженные файлы за пределами document root или в папке с выключенным выполнением скриптов. Например, структура:
1 /public_html ← document root ( index.php ) 2 /uploads ← папка с загруженными файлами (вне web-доступа)
Тогда прямой URL к файлу не сработает, браузер отдаёт файл только через PHP-скрипт-посредник, который проверяет права доступа.
Третье. Генерируйте уникальные имена файлов на сервере. Не доверяйте имени, которое прислал клиент: оно может содержать ../, нулевые байты или спецсимволы. basename() + time() + случайная строка, минимальный уровень.
Четвёртое. Проверяйте содержимое файла, а не только расширение. Злоумышленник может переименовать shell.php в photo.jpg и обойти фильтр по pathinfo(). Надёжный способ: определить реальный MIME-тип через finfo_file() (встроенный PHP-модуль Fileinfo) и сверить с белым списком. Для изображений дополнительно проверьте, что getimagesize() возвращает валидные размеры, это отсеет битые файлы и маскирующиеся скрипты. На высоконагруженных проектах стоит вынести загрузку в отдельный микросервис за реверс-прокси, который принимает поток, сканирует антивирусом (например, ClamAV) и только потом отдаёт основному приложению.
Короткое демо-видео выше показывает весь процесс в действии: HTML-разметка, PHP-обработчик и результат в браузере за три минуты.
⁉️🤔 Частые вопросы
Dropzone.js работает без jQuery?
Да, библиотека полностью независима от jQuery. Начиная с версии 5.x, все зависимости удалены, см. раздел Installation на dropzone.dev. При этом есть отдельный jQuery-враппер для тех, кто привык к
$('.dropzone').dropzone(), он лежит в том же npm-пакете, путьdist/min/dropzone-jquery.min.js.
Как поменять текст ошибки, когда файл слишком большой?
Используйте опцию
dictFileTooBig. Пример:dictFileTooBig: 'Файл слишком большой. Максимальный размер, {{maxFilesize}} МБ'. Шаблон{{maxFilesize}}автоматически подставит значение из вашей конфигурации. Полный список dict-ключей для локализации есть в документации.
Можно ли грузить файлы частями для больших объёмов?
Да, в Dropzone v5 есть встроенная поддержка чанковой загрузки через опции
chunking: true,chunkSize(в байтах) иforceChunking. Сервер при этом должен уметь собирать чанки: принимать каждый кусок с заголовкамиdzchunkindexиdztotalchunkcount, сохранять временно и склеивать после получения последнего. Для PHP готовый пример сборки чанков есть в репозитории Dropzone.
Как удалить превью файла после успешной загрузки?
Вызовите
myDropzone.removeFile(file)в обработчике событияsuccess. Файл исчезнет из интерфейса, но на сервере останется. Если нужно удалить и с сервера, добавьте AJAX-запрос в тот же обработчик передremoveFile.
Dropzone совместим с WordPress?
Да, библиотеку можно подключить через
wp_enqueue_script()в теме или плагине. Типичный сценарий для WordPress: замена стандартного загрузчика медиафайлов в пользовательской админ-странице или на фронтенд-форме. Нужно лишь указать корректный URL обработчика, обычноadmin_url('admin-ajax.php')с зарегистрированным AJAX-экшном.
Стоит ли брать Dropzone.js под ваш проект
Если вам нужна загрузка файлов перетаскиванием «здесь и сейчас», Dropzone.js закрывает задачу быстрее, чем любой самописный код. Пять причин, по которым библиотека остаётся актуальной в 2026 году:
- Никаких зависимостей. Ни jQuery, ни Bootstrap, ни React. Подключил один JS-файл, и работает.
- Кроссбраузерность. Поддерживает браузеры вплоть до IE11, gracefully degradable без JavaScript.
- Готовая визуализация. Превью картинок, прогресс-бары, иконки успеха/ошибки, из коробки, без CSS-вёрстки.
- Документация. Актуальное GitBook и активный репозиторий на GitHub (1 700+ звёзд на момент 2026 года).
- Гибкость. От простого ресайза картинок перед отправкой до чанковой загрузки гигабайтных файлов, всё настраивается через конфиг.
Когда Dropzone не лучший выбор: если вы уже используете React/Vue и хотите нативный компонент без DOM-манипуляций извне. В экосистеме React есть react-dropzone, во Vue, vue-dropzone. Но для чистого JavaScript, jQuery-проектов и WordPress-сайтов Dropzone.js, проверенный инструмент, который не подведёт.
Практический пример интеграции. Один из типовых сценариев на WordPress-сайте: страница «Загрузить документы» в личном кабинете клиента. Пользователь перетаскивает сканы паспорта, договора и фото объекта. Dropzone подключается через wp_enqueue_script() в functions.php темы, обработчиком выступает кастомный AJAX-экшн, зарегистрированный через wp_ajax_nopriv_. Каждый успешно загруженный файл записывается в медиабиблиотеку через wp_insert_attachment(), а его ID сохраняется в user meta. Весь фронтенд-код умещается в 30 строк, серверная часть, в 50. Для сравнения: самописный drag-and-drop с теми же возможностями занял бы 400-600 строк JavaScript и 2-3 дня разработки.
Что касается альтернатив: Uppy (от создателей Transloadit) предлагает модульную архитектуру с плагинами для React, Svelte и загрузки в S3, но требует больше зависимостей и настройки. Fine Uploader больше не поддерживается с 2018 года, форки живут, но без гарантий безопасности. Dropzone.js выигрывает балансом «возможности на единицу сложности»: один файл, минимум конфигурации, результат виден через пять минут после подключения.
Несколько дополнительных возможностей, которые стоит знать перед стартом. Dropzone предоставляет полный цикл событий: addedfile, thumbnail, uploadprogress, complete и queuecomplete. Последнее особенно полезно: оно срабатывает когда все файлы из очереди обработаны, и вы можете показать пользователю итоговое сообщение или перенаправить на другую страницу. Для сетевых сбоев есть встроенный retry: при ошибке загрузки Dropzone показывает кнопку «Повторить» рядом с превью файла, повторная отправка идёт через тот же обработчик без дублирования кода. Интерфейс полностью локализуется через словарь dict-опций: dictCancelUpload, dictRemoveFile, dictMaxFilesExceeded и ещё два десятка ключей, поддержка русского языка делается за пять минут копированием объекта из документации. Библиотека весит 28 КБ в сжатом виде (gzip), что добавляет менее 0.1 секунды к загрузке страницы на мобильном 4G. Все эти свойства делают Dropzone.js стандартом де-факто для drag-and-drop загрузки в проектах без фреймворков: миллион загрузок npm в неделю по данным на начало 2026 года, использование в админках WordPress, Laravel и Symfony.



