Drag and drop загрузка файлов на сайт

/ 👁 2920

Сегодня сделаем Drag and Drop форму для загрузки изображения на сайт.

Для ее реализации используем плагин Bootstrap File Input от Krajee.

Документация у плагина довольно обширная (правда вся она на английском), вы можете посмотреть ее по ссылке выше. Плагин предоставляет много возможностей. В рамках одной статьи рассмотреть их нереально. Но это и не является целью данной статьи.

Здесь я вам покажу, как мы можем реализовать форму с Drag and Drop полем, которое будет загружать изображение в определенную папку.

Сразу скажу, что в уроке я не буду подключать базу данных, чтобы не перегружать пост. Вместо сохранения в базе данных я буду просто сохранять картинку в папку, а когда мы повторно попадаем на страницу, буду отображать ее также подтягивая из папки.

На практике вы скорее всего будете сохранять имя картинки в базе данных, а после доставать его оттуда. Но в этом уроке для упрощения я этого делать не буду.

Итак начнем.

Подключаем всё необходимое для Drag and Drop зоны.

Во первых давайте разберемся со структурой нашего мини проекта. В папке проекта у меня будут всего 2 файла:

  • form.php – файл, где будем моя форма
  • index.php – файл-обработчик отправки формы.

Кроме этого мне понадобиться папка для хранения изображения. Назову ее images.

Откроем файл form.php и создадим базовую разметку. Здесь будет подключение всех необходимых внешних скриптов и стилей, которые обеспечат работу плагина, подключение скриптов и стилей самого плагина.

Также мы создадим форму.

Первый input должен иметь type=”file”. Также мы пропишем ему атрибут data-browse-on-zone-click=”true”, который обеспечит чувствительность drag&drop зоны к клику.

Сама форма должна иметь атрибут enctype=”multipart/form-data”. Это нужно для того, чтобы могли работать с глобальным массивом $__FILE в нашем обработчике. Метод у формы будет post, а в качестве action укажем наш файл обработчик index.php.

Также у нашей формы должен быть input типа submit. Это наша кнопка, которая будет отправлять форму.

На данном этапе у нас должен получится вот такой код.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Krajee</title>
  <!-- bootstrap 5.x or 4.x is supported. You can also use the bootstrap css 3.3.x versions -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" crossorigin="anonymous">
  <!-- default icons used in the plugin are from Bootstrap 5.x icon library (which can be enabled by loading CSS below) -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.min.css" crossorigin="anonymous">
  <!-- the fileinput plugin styling CSS file -->
  <link href="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.5/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />

  <!-- the jQuery Library -->
  <script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
  <!-- sortable.min.js is only needed if you wish to sort / rearrange files in initial preview.
    This must be loaded before fileinput.min.js -->
  <script src="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.5/js/plugins/sortable.min.js" type="text/javascript"></script>

  <!-- bootstrap.bundle.min.js below is needed if you wish to zoom and preview file content in a detail modal
      dialog. bootstrap 5.x or 4.x is supported. You can also use the bootstrap js 3.3.x versions. -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>

  <!-- the main fileinput plugin script JS file -->
  <script src="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.5/js/fileinput.min.js"></script>

</head>
<body>

<div class="container">
   <form action="index.php" method="post" enctype="multipart/form-data">
        <input id="main_slider" required name="main_slider" type="file" accept="image/*" data-browse-on-zone-click="true">
       <input type="submit" value="SEND">
   </form>
</div>


</body>
</html>

 Вызываем скрипт Drag&Drop

Пока что ничего интересного мы в браузере не увидим.

Чтобы увидеть Drag and drop зону мы должны написать немного js скрипта.

Пропишем его до закрывающего тега body нашей страницы.

 

<script>
  
    $("#main_slider").fileinput({
        showUpload: false,
        showRemove: true,
        initialPreviewShowDelete: false,
        allowedFileExtensions: ["jpg", "png", "gif"],
    });
</script>

Как вы могли заметить, у нашего input есть id. Благодаря этому мы подключаем к нему fileinput. В подключении мы указываем, что:

  • не хотим отображать кнопку upload,
  • хотим отображать кнопку remove,
  • не хотим отображать кнопку удаления у превьюшки (но это мы увидим чуть позже),
  • и указываем допустимые типы файлов для загрузки.

Теперь мы увидим следующее, если откроем нашу страницу в браузере.

Пробуем выбрать изображение и вот такой результат получаем.

Сохраняем картинку в папке

Всё отлично, но если мы нажмем на кнопу Send, то ничего не произойдет, потому что мы еще не написали обработчик для отправки нашей формы.

Вы помните, что в качестве action для формы мы указали index.php. Пришло время написать в нем код.

Итак, что мы хотим?

Мы хотим получить картинку, закодировать ей новое имя и сохранить ее в папке images.

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

В этом примере я это делаю для того, чтобы не усложнять урок добавлением имени картинки в базу данных, а всегда извлекать картинку для отображения из папки. Для этого мне нужно, чтобы в папке всегда была только 1 картинка. На практике, вам вероятно это будет не нужно.

Код файла index.php с комментариями:

 

<?php

if(isset($_FILES['main_slider']) && $_FILES['main_slider']['name'] != ""){
    //очищаю директорию
        array_map('unlink', glob("images/*"));
        // кодирую имя картинке
        $image_code = md5(rand(10000, 10000000));
        // разделяю path на части, чтобы извлечь разрешение файла
        $path_parts = pathinfo($_FILES['main_slider']['name']);
        // перемещаю файл в папку
        move_uploaded_file($_FILES['main_slider']['tmp_name'], 'images/' . $image_code . '.'.$path_parts['extension']);
        // редирект обратно на страницу
    header('Location: form.php');
}

В принципе здесь комментарий к каждой строке, поэтому больше особо добавить нечего.

Теперь при сохранении файл будет сохраняться в папке images, но попав обратно на страницу мы его не увидим. А нам хотелось бы видеть превью загруженного файла.

Для этого вернемся в файл form.php и немного его модифицируем.

Во-первых я извлеку имя файла, который лежит в папке. Для этого добавлю вот такой php-код. (Напоминаю, что вы вероятно будете извлекать имя файла из базы данных).

 

<?php
if ($handle = opendir(__DIR__.'/images')) {
    $files = scandir(__DIR__.'/images');
    $file = '';

    foreach($files as $v){
        if($v != '.' && $v != '..'){
            $file = $v;
        }
    }
    closedir($handle);
}
?>

Теперь в переменной $file у меня лежит имя загруженного файла.

Мне нужно передать его в javascript код и добавить некоторые параметры в вызов fileinput.

Вот так будет выглядеть модифицированный крипт, который мы ранее прописали до закрывающего тега body.

 

<script>
    let url = "images/<?php echo $file;?>"; //передаем переменную $file в javascript
    $("#main_slider").fileinput({
        showUpload: false,
        showRemove: true,
        initialPreviewShowDelete: false,
        allowedFileExtensions: ["jpg", "png", "gif"],
        initialPreviewAsData: true, 
        initialPreview: [url], //наш файл
        initialPreviewConfig: [
            {downloadUrl: url},

        ],
    });
</script>

Мы формируем переменную url – это путь к нашей картинке. Здесь же мы передаем переменную $file из php.

Далее мы устанавливаем параметры для initialPreview.

  • initialPreviewAsData: true – чтобы отобразить превью
  • initialPreview – массив с путями к файлам (в данном случае у нас только 1 файл)
  • nitialPreviewConfig – массив объектов. В данном случает у нас только 1 файл и поэтому только 1 объект. Мы указали в нем только downloadUrl, но там может быть и другая информация, такая как title и прочее. Подробнее можете посмотреть в примерах документации.

После всего этого мы можем загружать картинки и при редиректе, попадая обратно на страницу мы будем видеть их превью в форме.

Если загрузим новый файл, то старый затрется и мы увидим превью нового файла. Соответственно в папку попадет новый файл.

Надеюсь этот урок был вам полезен.

Leave a Reply