简体   繁体   中英

Drag and Drop Sortable Image Upload Solution

I am working on web page where I want to use drag an drop image upload system with options for remove and sort images before upload.

I would like to ask you about your opinion.

I do not know if this system will have some troubles in future bcz all systems which I found have different logic.

  1. My logic :

My system is based mainly on JS and images will be UPLOAD to folder AFTER FORM SUBMIT when whole form (other data about user as name, phone, etc) is filled in. Every modification as remove or change order is done by modify object data via JS.

  1. Web sources :

They are based on UPLOAD images immediately AFTER DROP/SELECT IMAGE and upload to server folder via PHP.

DIFFERENCE : My system no need to send data to PHP every time if one of this actions is happened - new image is added, or deleted or order is changed.

I will be very thankful even if you help me find some other problems. Also I hope it can help someone who is building own system.

Here is my code:

JS:

/* DRAG AND DROP IMG UPLOAD */

// preventing page from redirecting
$("html").on("dragover", function(e) {
    e.preventDefault();
    e.stopPropagation();
});

$("html").on("drop", function(e) { e.preventDefault(); e.stopPropagation(); });

// Drag enter
$('.add-item__upload-area').on('dragenter', function (e) {
    e.stopPropagation();
    e.preventDefault();
});

// Drag over
$('.add-item__upload-area').on('dragover', function (e) {
    e.stopPropagation();
    e.preventDefault();
    $('.add-item__dropzone').css({border: '2px dashed #111'});
});

$('.add-item__upload-area').on('dragleave', function (e) {
    e.stopPropagation();
    e.preventDefault();
    $('.add-item__dropzone').css({border: '2px dashed #888'});

});

// Open file browser
$('.add-item__add-photo-btn').click(function() {
    $('#input-files').trigger('click'); // execute input type file after click on button
    event.preventDefault();
});

// create object to keep img files for modification
var data = {};


// Files added by drop to dropzone area
$('.add-item__upload-area').on('drop', function (e) {
    e.stopPropagation();
    e.preventDefault();

    var totalFiles = e.originalEvent.dataTransfer.files.length;

    // fill form by files from input
    for (var i = 0; i < totalFiles; i++) {

        var file = e.originalEvent.dataTransfer.files[i]; // Get list of the files dropped to area

        // fill object for file modifications by img files
        data['file_'+i] = file;

        // create temp url to img object for creating thumbnail and append img with temp src to thumbnail__wraper div
        $('.thumbnail__wrapper').append('<div class="thumbnail" id="file_'+ i +'"><img class="imageThumb" src="' + URL.createObjectURL(file) + '" title="' + file.name + '"/><br/><a class="remove">Zmazať</a></div>');

        $('.add-item__add-photo-btn-area').find('p').hide();
    }

});

// Files added by selecting in file browser
$('#input-files').on('change', function(){

    var totalFiles = $('#input-files')[0].files.length; // get number of uploaded files from input element

    // modify ordering of fields inside data object according to order from sortable ui
    for (var i = 0; i < totalFiles; i++) {
        // By appending [0] to the jQuery object will return the first DOM element. Get <input> element from object.
        var file = $('#input-files')[0].files[i]; // Get first file from list of files selected with the <input type="file">

        // fill object for file modifications by img files
        data['file_'+i] = file;

        // create temp url to img object for creating thumbnail and append img with temp src to thumbnail__wraper div
        $('.thumbnail__wrapper').append('<div class="thumbnail" id="file_'+ i +'"><img class="imageThumb" src="' + URL.createObjectURL(file) + '" title="' + file.name + '"/><br/><a class="remove">Zmazať</a></div>');

        $('.add-item__add-photo-btn-area').find('p').hide();
    }

    //console.log(data);
    //uploadData(formData); // send data via ajax to upload.php

});

// Remove field of data obj after click on remove button
$('.add-item__dropzone').on('click','.remove', function() {
    // remove choosen field
    delete data[$(this).parent().attr('id')];
    $(this).parent('.thumbnail').remove();
    //console.log($(this).parent().attr('id'));
    //console.log(data);
});

// Make images sortable
$('.thumbnail__wrapper').sortable({
    axis: 'x', // axis in which sort is possible
    update: function (event, ui) {
        // get all ids (item-1, ....) from li elements (setted as sortable) of list in form item[]=1&item[]=2

        var reorderList = $(this).sortable('serialize');

        //console.log(reorderList);
        // fill FormData object by files from data array after order change
        var formData = new FormData();
        var dataLength = Object.keys(data).length;

        //console.log(data);
        data = changeOrder(data, reorderList);
        //console.log(data);

    }
})

// Change order of files inside object data
function changeOrder(obj, order) {
    var newObject = {};
    // if the g flag is used, all results matching the complete regular expression will be returned, but capturing groups will not.
    var matches = order.match(/=/g);
    var count = matches.length;
    // file[]=1&file[]=0&file[]=2 => ["file[]=1", "file[]=0", "file[]=2"]
    var arrayOfOrderValues = order.split('&');

    // console.log(arrayOfOrderValues);
    for (var i = 0; i < count; i++) {

        // get values in appropriate format ["file[]=1", "file[]=0", "file[]=2"] => file_1, file_0, file_2
        orderKey = 'file_' + arrayOfOrderValues[i].substring(arrayOfOrderValues[i].lastIndexOf("=") + 1);

        // console.log(orderKeyValue);
        // check if object contains key(property) as orderKeyValue and then do next step
        if(obj.hasOwnProperty(orderKey)) {
            // fill value of obj['file_1'] to newObject['file_0'] - ex. in first loop
            newObject['file_'+i] = obj[orderKey];
        }

    }
    return newObject;
}

// Sending AJAX request and upload file
function uploadData(formdata){

    $.ajax({
        url: '_inc/upload.php',
        type: 'post',
        data: formdata,
        contentType: false,
        processData: false,
        dataType: 'json',
        success: function(response){
            //addThumbnail(response); // if success - create thumbnail
        }
    })
}

$('.test').on('submit', function() {
    event.preventDefault();

    var formData = new FormData(); // Create form
    console.log(data);

    var count = Object.keys(data).length; // count fields of object

    for (var i = 0; i < count; i++) {
        formData.append('files[]', data['file_'+i]); // append data to form -> (key, value), file[0] first file from list of files !!! key must have [] for array
    }
    console.log(count);

    uploadData(formData); // send data via ajax to upload.php

})

PHP:

<?php

require($_SERVER['DOCUMENT_ROOT'] . '/bazar/_inc/DBController.php'); 
// inicialize object
$db_handler = new DBController();

// get total number of files in file list
$total_files = count($_FILES['files']['name']);
// array(5) { ["name"]=> array(2) { [0]=> string(23) "IMG_20190916_105311.jpg" [1]=> string(19) "20180525_115635.jpg" } ["type"]=> array(2) { [0]=> string(10) "image/jpeg" [1]=> string(10) "image/jpeg" } ["tmp_name"]=> array(2) { [0]=> string(28) "/home/gm016900/tmp/phpdU58AU" [1]=> string(28) "/home/gm016900/tmp/phpIqWoaQ" } ["error"]=> array(2) { [0]=> int(0) [1]=> int(0) } ["size"]=> array(2) { [0]=> int(306091) [1]=> int(2315700) } }

// Create array for jQuery information
$return_arr = array();

$images_names = array_filter($_FILES['files']['name']); // filter just values for $key = name
// -> array(2) { [0]=> string(23) "IMG_20190916_105311.jpg" [1]=> string(19) "20180525_115635.jpg" }
//var_dump($images_names);

/* BATCH FILE UPLOAD */

// if $_FILES contains image then do foreach
if ( !empty($images_names) ) {
    for($i = 0; $i < $total_files; $i++) {

        // Get reference to uploaded image
        $image_file = $_FILES["files"];

        // Get image name
        $image_name = $_FILES["files"]["name"][$i];

        // Get file size
        $image_size = $_FILES["files"]["size"][$i];


        /* BASIC CONTROL */

        // Exit if no file uploaded or image name contains unvalid characters /, \\
        if ( ( !strpos($image_name, '/') || !strpos($image_name, '\\') ) && isset($image_file) ) {
            // define variables if image in correct format is uploaded
            $errors = array();
            $maxsize = 10485760;
            $acceptable = array(
                'image/jpeg',
                'image/jpg',
                'image/gif',
                'image/png'
            );
        } else {
            die('No image uploaded.');
        }

        // Exit if image file is zero bytes or if image size is more then 10 MB
        if (getimagesize($image_file["tmp_name"][$i]) <= 0) {
            die('Uploaded file has no contents.');
        } elseif ($image_size >= $maxsize) {
            die('Image is too large. Image must be less than 10 megabytes.');
        }

        // Determine the type of an image int|false
        $image_type = exif_imagetype($image_file["tmp_name"][$i]);

        // Exit if is not a valid image file or image has not supported type
        if (!$image_type) {
            die('Uploaded file is not an image.');
        } elseif ( !in_array($image_file["type"][$i], $acceptable) ) {
            die('Image has not supported type JPG, PNG, GIF.');
        } else {
            $src = "default.png";
        }


        /* CREATE RANDOM IMAGE NAME INSTEDAOF $_FILES['files']['name'] */

        // Get file extension based on file type, to prepend a dot we pass true as the second parameter
        $image_extension = image_type_to_extension($image_type, true);

        // Create a unique image name
        $random_image_name = bin2hex(random_bytes(16)) . $image_extension;


        /* DEFINE LOCATION */

        // 1st create adress with new img random name
        $relative_location = "/bazar/assets/img/photos/".$random_image_name;

        $absolute_location = dirname(__DIR__, 2).$relative_location;

        //var_dump($image_file["tmp_name"][$i]);
        //var_dump($absolute_location);


        /* MOVE TEMP IMG TO PHOTOS FOLDER */

        // 2nd move img with tmp_name to new location under new random name added from 1st step
        if (move_uploaded_file($image_file["tmp_name"][$i], $absolute_location)) {

            $item_id = 1; 

            $src = $relative_location;

            $query = "INSERT INTO photos (item_id, file_name) VALUES (?, ?)";

            $inserted = $db_handler->runQuery( $query, 'is', array($item_id, $src) );
            
            var_dump($inserted);
            
            //$return_arr .= array("name" => $random_image_name,"size" => $image_size, "src"=> $src);
        }

    }
}

//echo json_encode($return_arr);

Here is code from one Web Source:

$(document).ready(function()
{
 $("#drop-area").on('dragenter', function (e){
  e.preventDefault();
  $(this).css('background', '#BBD5B8');
 });

 $("#drop-area").on('dragover', function (e){
  e.preventDefault();
 });

 $("#drop-area").on('drop', function (e){
  $(this).css('background', '#D8F9D3');
  e.preventDefault();
  var image = e.originalEvent.dataTransfer.files;
  createFormData(image);
 });
});

function createFormData(image)
{
 var formImage = new FormData();
 formImage.append('userImage', image[0]);
 uploadFormData(formImage);
}

function uploadFormData(formData) 
{
 $.ajax({
 url: "upload_image.php",
 type: "POST",
 data: formData,
 contentType:false,
 cache: false,
 processData: false,
 success: function(data){
  $('#drop-area').html(data);
 }});
}

You can do it either way, HTML does handle files as inputs and as such the whole form can handle doing it all at once, but it's completely up to you the author whethere you want to seperate this or not. I've seen projects that do it both ways. Dropzone is the best I recommend this to anyone doing file uploads

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM