Asked  7 Months ago    Answers:  5   Viewed   84 times

I have a lot of problem to upload multiple images using AJAX. I write this code:

HTML

<form id="upload" method="post" enctype="multipart/form-data">
    <div id="drop" class="drop-area">
        <div class="drop-area-label">
            Drop image here
        </div>
        <input type="file" name="file" id="file" multiple/>
    </div>

    <ul class="gallery-image-list" id="uploads">
    <!-- The file uploads will be shown here -->
    </ul>
</form>
<div id="listTable"></div>

jQuery/AJAX

$(document).on("change", "input[name^='file']", function(e){
    e.preventDefault();
    var This    =   this,
        display =   $("#uploads");

    // list all file data
    $.each(This.files, function(i, obj){
        // for each image run script asynchronous
        (function(i) {
            // get data from input file
            var file = This.files[i],
                name = file.name,
                size = file.size,
                type = file.type,
                lastModified        =   file.lastModified,
                lastModifiedDate    =   file.lastModifiedDate,
                webkitRelativePath  =   file.webkitRelativePath,
                slice               =   file.slice,
                i = i;

            // DEBUG
       /*
            var acc = []
            $.each(file, function(index, value) {
                acc.push(index + ": " + value);
            });
            alert(JSON.stringify(acc));
        */

            $.ajax({
                url:'/ajax/upload.php',
                contentType: "multipart/form-data",
                data:{
                        "image":
                        {
                            "name":name,
                            "size":size,
                            "type":type,
                            "lastModified":lastModified,
                            "lastModifiedDate":lastModifiedDate,
                            "webkitRelativePath":webkitRelativePath,
                            //"slice":slice,
                        }
                    },
                type: "POST",
                // Custom XMLHttpRequest
                xhr: function() {
                    var myXhr = $.ajaxSettings.xhr();
                    // Check if upload property exists
                    if(myXhr.upload)
                    {
                        // For handling the progress of the upload
                        myXhr.upload.addEventListener("progress",progressHandlingFunction, false); 
                    }
                    return myXhr;
                },
                cache: false,
                success : function(data){
                    // load ajax data
                    $("#listTable").append(data);
                }
            });
            // display progress
            function progressHandlingFunction(e){
                if(e.lengthComputable){
                    var perc = Math.round((e.loaded / e.total)*100);
                    perc = ( (perc >= 100) ? 100 : ( (perc <= 0) ? 0 : 0 ) );
                $("#progress"+i+" > div")
                    .attr({"aria-valuenow":perc})
                        .css("width", perc+"%");
                }
            }
            // display list of files
            display.append('<li>'+name+'</li><div class="progress" id="progress'+i+'">'
                    +'<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">'
                    +'</div></div>');
        })(i);
    }); 
});

I've tried a various versions and I never succeed to send multiple data through ajax. I have tried in this way what you see above, and now I get only POST informations. I understand why i get POST but I need to send FILES information and I do not know where I'm wrong.

I not work the first time with ajax and often use it for most projects but I have never used to send multiple files and that bothering me now.

Thanks!

 Answers

81

Try utilizing json to upload , process file object

html

<div id="drop" class="drop-area ui-widget-header">
  <div class="drop-area-label">Drop image here</div>
</div>
<br />
<form id="upload">
  <input type="file" name="file" id="file" multiple="true" accepts="image/*" />
  <ul class="gallery-image-list" id="uploads">
    <!-- The file uploads will be shown here -->
  </ul>
</form>
<div id="listTable"></div>

css

  #uploads {
      display:block;
      position:relative;
  } 

  #uploads li {
      list-style:none;
  }

  #drop {
      width: 90%;
      height: 100px;
      padding: 0.5em;
      float: left;
      margin: 10px;
      border: 8px dotted grey;
  }

  #drop.hover {
      border: 8px dotted green;
  }

  #drop.err {
      border: 8px dotted orangered;
  }

js

var display = $("#uploads"); // cache `#uploads`, `this` at `$.ajax()`
var droppable = $("#drop")[0]; // cache `#drop` selector
$.ajaxSetup({
    context: display,
    contentType: "application/json",
    dataType: "json",
    beforeSend: function (jqxhr, settings) {
        // pre-process `file`
        var file = JSON.parse(
                   decodeURIComponent(settings.data.split(/=/)[1])
                   );
        // add `progress` element for each `file`
        var progress = $("<progress />", {
                "class": "file-" + (!!$("progress").length 
                         ? $("progress").length 
                         : "0"),
                "min": 0,
                "max": 0,
                "value": 0,
                "data-name": file.name
        });
        this.append(progress, file.name + "<br />");
        jqxhr.name = progress.attr("class"); 
    }
});

var processFiles = function processFiles(event) {
    event.preventDefault();
    // process `input[type=file]`, `droppable` `file`
    var files = event.target.files || event.dataTransfer.files;
    var images = $.map(files, function (file, i) {
        var reader = new FileReader();
        var dfd = new $.Deferred();
        reader.onload = function (e) {
            dfd.resolveWith(file, [e.target.result])
        };
        reader.readAsDataURL(new Blob([file], {
            "type": file.type
        }));
        return dfd.then(function (data) {
            return $.ajax({
                type: "POST",
                url: "/echo/json/",
                data: {
                    "file": JSON.stringify({
                            "file": data,
                            "name": this.name,
                            "size": this.size,
                            "type": this.type
                    })
                },
                xhr: function () {
                    // do `progress` event stuff
                    var uploads = this.context;
                    var progress = this.context.find("progress:last");
                    var xhrUpload = $.ajaxSettings.xhr();
                    if (xhrUpload.upload) {
                        xhrUpload.upload.onprogress = function (evt) {
                            progress.attr({
                                    "max": evt.total,
                                    "value": evt.loaded
                            })
                        };
                        xhrUpload.upload.onloadend = function (evt) {
                            var progressData = progress.eq(-1);
                            console.log(progressData.data("name")
                                    + " upload complete...");
                            var img = new Image;
                            $(img).addClass(progressData.eq(-1)
                            .attr("class"));
                            img.onload = function () {
                                if (this.complete) {
                                  console.log(
                                      progressData.data("name")
                                      + " preview loading..."
                                  );
                                };

                            };
                        uploads.append("<br /><li>", img, "</li><br />");
                        };
                    }
                    return xhrUpload;
                }
            })
            .then(function (data, textStatus, jqxhr) {
                console.log(data)
                this.find("img[class=" + jqxhr.name + "]")
                .attr("src", data.file)
                .before("<span>" + data.name + "</span><br />");
                return data
            }, function (jqxhr, textStatus, errorThrown) {
                console.log(errorThrown);
                return errorThrown
            });
        })
    });
    $.when.apply(display, images).then(function () {
        var result = $.makeArray(arguments);
        console.log(result.length, "uploads complete");
    }, function err(jqxhr, textStatus, errorThrown) {
        console.log(jqxhr, textStatus, errorThrown)
    })
};

$(document)
.on("change", "input[name^=file]", processFiles);
// process `droppable` events
droppable.ondragover = function () {
    $(this).addClass("hover");
    return false;
};

droppable.ondragend = function () {
    $(this).removeClass("hover")
    return false;
};

droppable.ondrop = function (e) {
    $(this).removeClass("hover");
    var image = Array.prototype.slice.call(e.dataTransfer.files)
        .every(function (img, i) {
        return /^image/.test(img.type)
    });
    e.preventDefault();
    // if `file`, file type `image` , process `file`
    if (!!e.dataTransfer.files.length && image) {
            $(this).find(".drop-area-label")
            .css("color", "blue")
            .html(function (i, html) {
            $(this).delay(3000, "msg").queue("msg", function () {
                $(this).css("color", "initial").html(html)
            }).dequeue("msg");
            return "File dropped, processing file upload...";
        });
        processFiles(e);
    } else {
            // if dropped `file` _not_ `image`
            $(this)
            .removeClass("hover")
            .addClass("err")
            .find(".drop-area-label")
            .css("color", "darkred")
            .html(function (i, html) {
            $(this).delay(3000, "msg").queue("msg", function () {
                $(this).css("color", "initial").html(html)
                .parent("#drop").removeClass("err")
            }).dequeue("msg");
            return "Please drop image file...";
        });
    };
};

php

<?php
  if (isset($_POST["file"])) {
    // do php stuff
    // call `json_encode` on `file` object
    $file = json_encode($_POST["file"]);
    // return `file` as `json` string
    echo $file;
  };

jsfiddle http://jsfiddle.net/guest271314/0hm09yqo/

Tuesday, June 1, 2021
 
KingCrunch
answered 7 Months ago
75

File upload is not possible through AJAX.
You can upload file, without refreshing page by using IFrame.
You can check further details here.


UPDATE

With XHR2, File upload through AJAX is supported. E.g. through FormData object, but unfortunately it is not supported by all/old browsers.

FormData support starts from following desktop browsers versions.

  • IE 10+
  • Firefox 4.0+
  • Chrome 7+
  • Safari 5+
  • Opera 12+

For more detail, see MDN link.

Tuesday, June 1, 2021
 
Vlad
answered 7 Months ago
27

Note: I totally reviewed my answer and made it better!

HTML

First we make a traditional form without a confirm button. Instead we make a button.

<form enctype="multipart/form-data" id="myform">    
    <input type="text" name="some_usual_form_data" />
    <br>
    <input type="file" accept="image/*" multiple name="img[]" id="image" /> <sub>note that you have to use [] behind the name or php wil only see one image</sub>
    <br>
    <input type="button" value="Upload images" class="upload" />
</form>
<progress value="0" max="100"></progress>
<hr>
<div id="content_here_please"></div>

Javascript/jquery upload side

than here is the Javascript.. o yes and Jquery to upload the images and the other form data:

    $(document).ready(function () { 
        $('body').on('click', '.upload', function(){
            // Get the form data. This serializes the entire form. pritty easy huh!
            var form = new FormData($('#myform')[0]);

            // Make the ajax call
            $.ajax({
                url: 'action.php',
                type: 'POST',
                xhr: function() {
                    var myXhr = $.ajaxSettings.xhr();
                    if(myXhr.upload){
                        myXhr.upload.addEventListener('progress',progress, false);
                    }
                    return myXhr;
                },
                //add beforesend handler to validate or something
                //beforeSend: functionname,
                success: function (res) {
                    $('#content_here_please').html(res);
                },
                //add error handler for when a error occurs if you want!
                //error: errorfunction,
                data: form,
                // this is the important stuf you need to overide the usual post behavior
                cache: false,
                contentType: false,
                processData: false
            });
        });
    }); 

    // Yes outside of the .ready space becouse this is a function not an event listner!
    function progress(e){
        if(e.lengthComputable){
            //this makes a nice fancy progress bar
            $('progress').attr({value:e.loaded,max:e.total});
        }
    }

PHP processing side

And for those who need the php side to do something with those images here is the php code to loop trough:

<?php

    $succeed = 0;
    $error = 0;
    $thegoodstuf = '';
    foreach($_FILES["img"]["error"] as $key => $value) {
        if ($value == UPLOAD_ERR_OK){
            $succeed++;

            // get the image original name
            $name = $_FILES["img"]["name"][$key];

            // get some specs of the images
            $arr_image_details = getimagesize($_FILES["img"]["tmp_name"][$key]); 
            $width = $arr_image_details[0];
            $height = $arr_image_details[1];
            $mime = $arr_image_details['mime'];

            // Replace the images to a new nice location. Note the use of copy() instead of move_uploaded_file(). I did this becouse the copy function will replace with the good file rights and  move_uploaded_file will not shame on you move_uploaded_file.
            copy($_FILES['img']['tmp_name'][$key], './upload/'.$name);

            // make some nice html to send back
            $thegoodstuf .= "
                                <br>
                                <hr>
                                <br>

                                <h2>Image $succeed - $name</h2>
                                <br>
                                specs,
                                <br>
                                width: $width  <br>
                                height: $height <br>
                                mime type: $mime <br>
                                <br>
                                <br>
                                <img src='./upload/$name' title='$name' />
            ";
        }
        else{
            $error++;
        }
    }

    echo 'Good lord vader '.$succeed.' images where uploaded with success!<br>';

    if($error){
        echo 'shameful display! '.$error.' images where not properly uploaded!<br>';
    }

    echo 'O jeah there was a field containing some usual form data: '. $_REQUEST['some_usual_form_data'];

    echo $thegoodstuf;

?>

live demo at my dev web server which is not always online!

If you want to compress and resize

You need this class:

class SimpleImage{   

        var $image; 
        var $image_type;   

        function load($filename){   
            $image_info = getimagesize($filename); 
            $this->image_type = $image_info[2]; 

            if($this->image_type == IMAGETYPE_JPEG)
            {   
                $this->image = imagecreatefromjpeg($filename); 
            }
            elseif($this->image_type == IMAGETYPE_GIF) 
            {   
                $this->image = imagecreatefromgif($filename); 
            }
            elseif($this->image_type == IMAGETYPE_PNG)
            {   
                $this->image = imagecreatefrompng($filename); 
            }
        } 

        function save($filename, $image_type=IMAGETYPE_JPEG, $compression=75, $permissions=0777){   

            if($image_type == IMAGETYPE_JPEG)
            { 
                $gelukt = imagejpeg($this->image,$filename,$compression); 
            }
            elseif($image_type == IMAGETYPE_GIF)
            {   
                $gelukt = imagegif($this->image,$filename); 
            }
            elseif($image_type == IMAGETYPE_PNG)
            {   
                $gelukt = imagepng($this->image,$filename); 
            } 

            if($permissions != false)
            {   
                chmod($filename,$permissions); 
            }

            return $gelukt; 
        } 

        function output($image_type=IMAGETYPE_JPEG) { 

            if($image_type == IMAGETYPE_JPEG)
            { 
                imagejpeg($this->image); 
            } 
            elseif($image_type == IMAGETYPE_GIF) 
            {   
                imagegif($this->image); 
            }
            elseif($image_type == IMAGETYPE_PNG)
            {   
                imagepng($this->image); 
            } 
        } 

        function getWidth(){   

            return imagesx($this->image);

        } 

        function getHeight(){   

            return imagesy($this->image); 

        } 

        function maxSize($width = 1920, $height = 1080){
            if(($this->getHeight() > $height) && ($this->getWidth() > $width)){
                $ratio = $height / $this->getHeight(); 
                $newwidth = $this->getWidth() * $ratio; 

                if($newwidth > $width){
                    $ratio = $width / $newwidth; 
                    $height = $height * $ratio;
                    $newwidth = $width;
                }

                $this->resize($newwidth,$height);
                return true;
            }
            elseif($this->getHeight() > $height){
                $ratio = $height / $this->getHeight(); 
                $width = $this->getWidth() * $ratio; 

                $this->resize($width,$height);
                return true;
            }
            elseif($this->getWidth() > $width){
                $ratio = $width / $this->getWidth(); 
                $height = $this->getheight() * $ratio;  

                $this->resize($width,$height);
                return true;
            }
            return false;
        }

        function resizeToHeight($height){   
            $ratio = $height / $this->getHeight(); 
            $width = $this->getWidth() * $ratio; 
            $this->resize($width,$height); 
        }   

        function resizeToWidth($width){ 
            $ratio = $width / $this->getWidth(); 
            $height = $this->getheight() * $ratio; 
            $this->resize($width,$height); 
        }   

        function scale($scale){ 
            $width = $this->getWidth() * $scale/100; 
            $height = $this->getheight() * $scale/100; 
            $this->resize($width,$height); 
        }   

        function resize($width,$height) { 

            $new_image = imagecreatetruecolor($width, $height); 
            if( $this->image_type == IMAGETYPE_GIF || $this->image_type == IMAGETYPE_PNG )
            { 
                $current_transparent = imagecolortransparent($this->image); 

                if($current_transparent != -1) {
                    $transparent_color = imagecolorsforindex($this->image, $current_transparent); 
                    $current_transparent = imagecolorallocate($new_image, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); 
                    imagefill($new_image, 0, 0, $current_transparent); 
                    imagecolortransparent($new_image, $current_transparent); 
                }
                elseif($this->image_type == IMAGETYPE_PNG)
                { 
                    imagealphablending($new_image, false); 
                    $color = imagecolorallocatealpha($new_image, 0, 0, 0, 127); 
                    imagefill($new_image, 0, 0, $color); 
                    imagesavealpha($new_image, true); 


            } 
        } 

        imagecopyresampled($new_image, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight()); 
        $this->image = $new_image;   
    }
}

you can use it like this:

$succeed = 0;
$error = 0;
$thegoodstuf = '';
foreach($_FILES["img"]["error"] as $key => $value) {
    if ($value == UPLOAD_ERR_OK){
        $succeed++;

        $name = $_FILES["img"]["name"][$key];

        $image = new SimpleImage();
        $image->load($_FILES['img']['tmp_name'][$key]); 
        $chek = $image->maxSize();

        if($chek){
            $move = $image->save('./upload/'.$name);
            $message= 'Afbeelding verkleind naar beter formaat!<br>';
        }
        else{
            $move = copy($_FILES['img']['tmp_name'][$key], './upload/'.$name);
            #$move = move_uploaded_file($_FILES['img']['tmp_name'][$key], './upload/'.$name);
            $message= '';
        }

        if($move){

            $arr_image_details = getimagesize('./upload/'.$name); 
            $width = $arr_image_details[0];
            $height = $arr_image_details[1];
            $mime = $arr_image_details['mime'];

            $thegoodstuf .= "
                            <br>
                            <hr>
                            <br>

                            <h2>Image $succeed - $name</h2>
                            <br>
                            specs,
                            <br>
                            $message
                            width: $width  <br>
                            height: $height <br>
                            mime type: $mime <br>
                            <br>
                            <br>
                            <img src='./upload/$name' title='$name' />
            ";
        }
        else{
            $error++;
        }
    }
    else{
        $error++;
    }
}

echo 'Good lord vader '.$succeed.' images where uploaded with success!<br>';

if($error){
    echo 'shameful display! '.$error.' images where not properly uploaded!<br>';
}

echo 'O jeah there was a field containing some usual form data: '. $_REQUEST['some_usual_form_data'];

echo $thegoodstuf;
Tuesday, June 29, 2021
 
Besnik
answered 6 Months ago
47

In your form, add multiple file inputs. One way is to use an array name - image[]

Image to upload: <input type="file" name="image[]" /><br />
Image to upload: <input type="file" name="image[]" /><br />
Image to upload: <input type="file" name="image[]" /><br />
....  // as many as you want. Just be aware of upload_max_filesize, memory_limit, post_max_size etc.
<br /> 

Then in your uploader.php, wrap your file upload code with a for loop

for($i=0;$i<count($_FILES["image"]["name"]);$i++){

    $fileData = pathinfo(basename($_FILES["image"]["name"][$i]));

     ...

    if (move_uploaded_file($_FILES["image"]["tmp_name"][$i], $target_path))
    {
      ...

      echo "The image {$_FILES['image']['name'][$i]} was successfully uploaded and added to the gallery<br />";

    }
    else
    {
     echo "There was an error uploading the file {$_FILES['image']['name'][$i]}, please try again!<br />";
    }
} // close your foreach

the manual has a great section on common pitfalls when uploading files, especially multiple. http://www.php.net/manual/en/features.file-upload.common-pitfalls.php


If you want to do multiple of the others, it can be done the same way (I abbreviated the selects to reduce copy/paste) -

<form enctype="multipart/form-data" action="uploader.php" method="POST">

    // 1st set
    Category: <select class="text" name="dataType[]" />
    ...
    </select><br />
    <br />        

    Caption: <input type="text" name="title[]" /><br />
    <br />

    Image to upload: <input type="file" name="image[]" /><br />
    <br /> 

    // 2nd set
    Category: <select class="text" name="dataType[]" />
    ...
    </select><br />
    <br />        

    Caption: <input type="text" name="title[]" /><br />
    <br />

    Image to upload: <input type="file" name="image[]" /><br />
    <br />  

   // and so on, as many as you want  
   ...
    <input type="submit" value="Upload">
</form>

and your php, put the for loop around all the elements

for($i=0;$i<count($_FILES["image"]["name"]);$i++){

    $dataType = mysql_real_escape_string($_POST["dataType"][$i]);  // get the dataType with the same key - $i
    $title = mysql_real_escape_string($_POST["title"][$i]);   // get the title with the same key - $i

    $fileData = pathinfo(basename($_FILES["image"]["name"][$i]));

     ...

    if (move_uploaded_file($_FILES["image"]["tmp_name"][$i], $target_path))
    {
      ...

      echo "The image {$_FILES['image']['name'][$i]} was successfully uploaded and added to the gallery<br />";

    }
    else
    {
     echo "There was an error uploading the file {$_FILES['image']['name'][$i]}, please try again!<br />";
    }
} // close your foreach

edit
you are almost there. Remove the duplicate code above the for loop. Remove basename(), as this is causing your extension to fail, and pathinfo() will return the ['basename'].

<?php
include($_SERVER['DOCUMENT_ROOT'] . "/connections/dbconnect.php");

for($i=0;$i<count($_FILES["image"]["name"]);$i++){
  if($_FILES["image"]["name"][$i] != ''){ // don't insert if file name empty
    $dataType = mysql_real_escape_string($_POST["dataType"][$i]);
    $title = mysql_real_escape_string($_POST["title"][$i]);

    $fileData = pathinfo($_FILES["image"]["name"][$i]);

    $fileName = uniqid() . '.' . $fileData['extension'];
    $target_path = $_SERVER['DOCUMENT_ROOT'] . "/images/gallery/" . $fileName;

    while(file_exists($target_path)){
       $fileName = uniqid() . '.' . $fileData['extension'];
       $target_path = $_SERVER['DOCUMENT_ROOT'] . "/images/gallery/" . $fileName;
    }     

  if (move_uploaded_file($_FILES["image"]["tmp_name"][$i], $target_path)){    // The file is in the images/gallery folder. 
    // Insert record into database by executing the following query:
     $sql="INSERT INTO images (data_type, title, file_name) "."VALUES('$dataType','$title','$fileName')";
     $retval = mysql_query($sql);

    echo "The image {$_FILES['image']['name'][$i]} was successfully uploaded and added to the gallery<br />
     <a href='index.php'>Add another image</a><br />";
  }
  else
  {
   echo "There was an error uploading the file {$_FILES['image']['name'][$i]}, please try again!<br />";
    }
  }
} // close your foreach
?>
Tuesday, August 3, 2021
 
smogg
answered 4 Months ago
70

You might need to increase the maximum allowed request size on the server as well as the execution timeout of the request using the <httpRuntime> section in your web.config

<system.web>
    <httpRuntime 
        maxRequestLength="size in kbytes"
        executionTimeout="seconds"
    />

    ...
</system.web>

And if you are deploying your application in IIS 7.0+ you might also need to increase the maximum allowed request size using the <requestLimits> node of the <system.webServer> section:

<system.webServer>
    <security>
        <requestFiltering>
            <requestLimits maxAllowedContentLength="size in bytes" />
        </requestFiltering>
    </security>

    ...
</system.webServer>
Monday, September 13, 2021
 
Pratik
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share