Search code examples
javascriptphpajaxcodeigniter-2

How I can create a formless file upload using Javascript?


I have the following form:

$("#multimedia_upload").on('submit',function(e){
            e.preventDefault();
            console.log("files submited");
            
            
            var images = $("#multimedia_upload input[name='images']")[0].files;
            if(images.length == 0){
                uploadStatus.images=true;
                redirect();
            }

            uploadStatus.images=false;
            var status = true;
            var uploadedTimes = images.length

            Array.from(images).forEach(function(img){
                fileReader.onload = function(){

                    $.ajax({
                        method: "post",
                        url: $("#multimedia_upload").attr('action'),
                        processData: false,
                        dataType: "json",
                        data: JSON.stringify({"image": fileReader.result}),
                        success: function(){
                            status = status && true;
                        },
                        fail: function(){
                            status = status && false;
                            alert("Αδυναμία ανεβάσματος εικόνας");
                        },
                        complete: function(){
                            uploadedTimes--;
                            if(uploadedTimes == 0){
                                uploadStatus.images=status;
                                redirect();
                            }
                        }
                    });
                }

                fileReader.onerror = function(){
                    uploadStatus.images=false;
                    alert("Αδυναμία ανεβάσματος εικόνας");
                }

                fileReader.readAsDataURL(img)
            });
        });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<form id="multimedia_upload" action=".p/stores/action-uploadStoreImage"  method="POST">
    <input type="file" style="display:hidden;" name="images" multiple="multiple" accept="image/*"/>
</form>

But the data are uploaded as json containign base64. What I want to do is to replicate a form upload as each image was on its own input fields with it own form.

So do you have any idea how I can do this? The reason why I want to upload the file one at a time is due to server restrictions on maximum uploaded file. Also I want to avoid code ingiter's Disallowed Key Characters. filtering as well via emulating an ajax file upload.

Any solution shown in this question requires to modify codeingiter's core: CodeIgniter Disallowed Key Characters

And I want to avoid that my application is dinosaurs old and too expensive in manhours for my boss to replace the framework.

Update 1

I also tried this:

$("#multimedia_upload").on('submit',function(e){
            e.preventDefault();
            console.log("files submited");
            
            
            var images = $("#multimedia_upload input[name='images']")[0].files;
            if(images.length == 0){
                uploadStatus.images=true;
                redirect();
            }

            uploadStatus.images=false;
            var status = true;
            var uploadedTimes = images.length

            Array.from(images).forEach(function(img){


                    $.ajax({
                        method: "post",
                        url: $("#multimedia_upload").attr('action'),
                        processData: false,
                        data: img,
                        success: function(){
                            status = status && true;
                        },
                        fail: function(){
                            status = status && false;
                            alert("Αδυναμία ανεβάσματος εικόνας");
                        },
                        complete: function(){
                            uploadedTimes--;
                            if(uploadedTimes == 0){
                                uploadStatus.images=status;
                                redirect();
                            }
                        }
                    });
                
            });
        });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<form id="multimedia_upload" action=".p/stores/action-uploadStoreImage"  method="POST">
    <input type="file" style="display:hidden;" name="images" multiple="multiple" accept="image/*"/>
</form>

But still cannot upload each image one-ny-one.


Solution

  • In your javascript code there are 2 issues:

    1. As @Thanh Dao mentions skip file reading all together.
    2. The Ajax call should also contain the following configuration as well:
          async: false,
          cache: false,
          contentType: false,
          processData: false,
      
    3. And Input should be in its own FormData object. Just place the img into a dedicated FromData.

    Therefore the end result should be:

            $("#multimedia_upload").on('submit',function(e){
                e.preventDefault();
                console.log("files submited");
                
                
                var images = $("#multimedia_upload input[name='images']")[0].files;
                if(images.length == 0){
                    uploadStatus.images=true;
                    redirect();
                }
    
                uploadStatus.images=false;
                var status = true;
                var uploadedTimes = images.length
    
                Array.from(images).forEach(function(img){
                    var formData = new FormData();
                    formData.append('image',img);
                    $.ajax({
                        method: "post",
                        url: $("#multimedia_upload").attr('action'),
                        // url: "http://etable.local/test.php",
                        processData: false,
                        async: false,
                        cache: false,
                        contentType: false,
                        processData: false,
                        data: formData,
                        success: function(){
                            status = status && true;
                        },
                        fail: function(){
                            status = status && false;
                            alert("Αδυναμία ανεβάσματος εικόνας");
                        },
                        complete: function(){
                            uploadedTimes--;
                            if(uploadedTimes == 0){
                                uploadStatus.images=status;
                                redirect();
                            }
                        }
                    });
                });
            });
    

    In the end you can test the file upload works by replacing the url that JS calls into url that contains this simple script (For easyness just place where$_SERVER['DOCUMENT_ROOT'] points):

    <?php
    
    var_dump($_FILES);
    

    If it shown an output then the Ajax Upload is OK if not you messed up with the Js part that does the ajax call. With that you can bypass any framework and ensure that JS part works fine.