This tutorial we going to implement Multiple image upload without page refresh. we use base 64 to convert into image and store. upload multiple image and store all image in single submit button click.
Here are the steps for Upload Multiple image.
- Create index.php file
- Add Progress bar on submit button click
- Create JS file for image upload and progress bar
- Store image in server
Let’s start with creating form and we use bootstrap as design.
Create index.php file
<!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" crossorigin="anonymous"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" crossorigin="anonymous"> <link rel="stylesheet" href="./css/style.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="./js/add_post.js"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-12"> <div class="panel panel-card "> <div class="panel-body"> <h2>How to upload Multiple image without page refresh using PHP,jQuery and AJAX</h2> <form method="post" id="add_form"> <div class="form-group"> <span class="btn btn-success fileinput-button"> <span>Select Attachment</span> <input type="file" name="files[]" id="files" multiple accept="image/jpeg, image/png, image/gif,"><br /> </span> <output id="Filelist"> <ul class="thumb-Images" id="imgList"> </ul> </output> </div> <div class="progress"> <div class="progress-bar"></div> </div> <div id="uploadStatus"></div> <div id="optimize_img"></div> <div class="widget-content padding"> <input type="button" name="save_post" id="add_post" class="btn btn-primary md-trigger" value="Save"></button> </div> </form> </div> </div> </div> </div> </div> </body> </html>
Create form where user can upload multiple image file on single click as we can use multiple attributes for this and if you want single upload won’t need to add multiple and array as name.
add_post.js file
document.addEventListener("DOMContentLoaded", init, false); //To save an array of attachments var AttachmentArray = []; //counter for attachment array var arrCounter = 0; //to make sure the error message for number of files will be shown only one time. var filesCounterAlertStatus = false; //un ordered list to keep attachments thumbnails var ul = document.createElement("ul"); ul.className = "thumb-Images"; ul.id = "imgList"; function init() { //add javascript handlers for the file upload event document .querySelector("#files") .addEventListener("change", handleFileSelect, false); } //the handler for file upload event function handleFileSelect(e) { //to make sure the user select file/files if (!e.target.files) return; //To obtaine a File reference var files = e.target.files; // Loop through the FileList and then to render image files as thumbnails. for (var i = 0, f; (f = files[i]); i++) { //instantiate a FileReader object to read its contents into memory var fileReader = new FileReader(); // Closure to capture the file information and apply validation. fileReader.onload = (function(readerEvt) { return function(e) { //Apply the validation rules for attachments upload ApplyFileValidationRules(readerEvt); //Render attachments thumbnails. RenderThumbnail(e, readerEvt); //Fill the array of attachment FillAttachmentArray(e, readerEvt); }; })(f); // Read in the image file as a data URL. // readAsDataURL: The result property will contain the file/blob's data encoded as a data URL. fileReader.readAsDataURL(f); } document .getElementById("files") .addEventListener("change", handleFileSelect, false); } //To remove attachment once user click on x button jQuery(function($) { $("div").on("click", ".img-wrap .close", function() { var id = $(this) .closest(".img-wrap") .find("img") .data("id"); //to remove the deleted item from array var elementPos = AttachmentArray.map(function(x) { return x.FileName; }).indexOf(id); if (elementPos !== -1) { AttachmentArray.splice(elementPos, 1); } //to remove image tag $(this) .parent() .find("img") .not() .remove(); //to remove div tag that contain the image $(this) .parent() .find("div") .not() .remove(); //to remove div tag that contain caption name $(this) .parent() .parent() .find("div") .not() .remove(); //to remove li tag var lis = document.querySelectorAll("#imgList li"); for (var i = 0; (li = lis[i]); i++) { if (li.innerHTML == "") { li.parentNode.removeChild(li); } } }); }); //Apply the validation rules for attachments upload function ApplyFileValidationRules(readerEvt) { //To check file type according to upload conditions if (CheckFileType(readerEvt.type) == false) { alert( "The file (" + readerEvt.name + ") does not match the upload conditions, You can only upload jpg/png/gif files" ); e.preventDefault(); return; } //To check file Size according to upload conditions if (CheckFileSize(readerEvt.size) == false) { alert( "The file (" + readerEvt.name + ") does not match the upload conditions, The maximum file size for uploads should not exceed 300 KB" ); e.preventDefault(); return; } //To check files count according to upload conditions if (CheckFilesCount(AttachmentArray) == false) { if (!filesCounterAlertStatus) { filesCounterAlertStatus = true; alert( "You have added more than 10 files. According to upload conditions you can upload 10 files maximum" ); } e.preventDefault(); return; } } //To check file type according to upload conditions function CheckFileType(fileType) { if (fileType == "image/jpeg") { return true; } else if (fileType == "image/png") { return true; } else if (fileType == "image/gif") { return true; } else if (fileType == "image/jpg") { return true; } else { return false; } return true; } //To check file Size according to upload conditions function CheckFileSize(fileSize) { if (fileSize < 3000000) { return true; } else { return false; } return true; } //To check files count according to upload conditions function CheckFilesCount(AttachmentArray) { //Since AttachmentArray.length return the next available index in the array, //I have used the loop to get the real length var len = 0; for (var i = 0; i < AttachmentArray.length; i++) { if (AttachmentArray[i] !== undefined) { len++; } } //To check the length does not exceed 10 files maximum if (len > 9) { return false; } else { return true; } } //Render attachments thumbnails. function RenderThumbnail(e, readerEvt) { var li = document.createElement("li"); ul.appendChild(li); li.innerHTML = [ ' <div class="img-wrap"> <span class="close">×</span>' + '<img class="thumb" src="', e.target.result, '" title="', escape(readerEvt.name), '" data-id="', readerEvt.name, '"/>' + " </div> " ].join(""); var div = document.createElement("div"); div.className = "FileNameCaptionStyle"; li.appendChild(div); div.innerHTML = [readerEvt.name].join(""); document.getElementById("Filelist").insertBefore(ul, null); } //Fill the array of attachment function FillAttachmentArray(e, readerEvt) { AttachmentArray[arrCounter] = { AttachmentType: 1, ObjectType: 1, FileName: readerEvt.name, FileDescription: "Attachment", NoteText: "", MimeType: readerEvt.type, Content: e.target.result.split("base64,")[1], FileSizeInBytes: readerEvt.size }; arrCounter = arrCounter + 1; } $(document).on('click','#add_post',function(e) { e.preventDefault(); //validation of form var valid=1; var form = $('#add_form')[0]; var formData = new FormData(form); var paramJSON = JSON.stringify(AttachmentArray); var main_image=$("#main_image").val(); formData.append('main_image', main_image); formData.append('file', paramJSON); formData.append('action', 'add'); $.ajax({ xhr: function() { var xhr = new window.XMLHttpRequest(); xhr.upload.addEventListener("progress", function(evt) { if (evt.lengthComputable) { var percentComplete = ((evt.loaded / evt.total) * 100); $(".progress-bar").width(percentComplete + '%'); $(".progress-bar").html(percentComplete+'%'); } }, false); return xhr; }, type: 'POST', url: 'upload.php', dataType:"json", data: formData, contentType: false, cache: false, processData:false, beforeSend: function(){ $(".progress-bar").width('0%'); $('#uploadStatus').html('<img src="images/loading.gif"/>'); $("#add_post").attr("disabled", true); }, error:function(){ $('#uploadStatus').html(' <p style="color:#EA4335;">File upload failed, please try again.</p> '); $("#add_post").attr("disabled", false); $('#optimize_img').html(''); }, success: function(resp){ if(resp.success ==1){ $('#add_form')[0].reset(); $('#uploadStatus').html(' <p style="color:#28A74B;">Added successfully!</p> '); $("#add_post").attr("disabled", false); $('#optimize_img').html(''); }else if(resp.success ==0){ $('#uploadStatus').html(' <p style="color:#EA4335;">'+resp.error+'</p> '); $("#add_post").attr("disabled", false); $('#optimize_img').html(''); } } }); });
All JS logic we implement add_post.js file. it provide all image to display preview with delete option as well. Render file thumbnails, image size validation and maximum image upload limit. We use ajax call to send image data in upload.php. var formData = new FormData(form); that can handle all form data.
Create style.css
.btn { display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: normal; line-height: 1.42857143; text-align: center; white-space: nowrap; vertical-align: middle; cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-image: none; border: 1px solid transparent; border-radius: 4px; } /*Also */ .btn-success { border: 1px solid #c5dbec; background: #d0e5f5; font-weight: bold; color: #2e6e9e; } .fileinput-button { position: relative; overflow: hidden; } .fileinput-button input { position: absolute; top: 0; right: 0; margin: 0; opacity: 0; -ms-filter: "alpha(opacity=0)"; font-size: 200px; direction: ltr; cursor: pointer; } .thumb { height: 80px; width: 100px; border: 1px solid #000; border-radius: 10px; } .thumb-Images{padding-left: 0px;} ul.thumb-Images li { width: 120px; float: left; display: inline-block; vertical-align: top; height: 120px; } .img-wrap { position: relative; display: inline-block; font-size: 0; margin: 10px; } .img-wrap .close { position: absolute; top: 2px; right: 2px; z-index: 100; background-color: #d0e5f5; padding: 5px 2px 2px; color: #000; font-weight: bolder; cursor: pointer; opacity: 0.5; font-size: 23px; line-height: 10px; border-radius: 50%; } .img-wrap:hover .close { opacity: 1; background-color: #ff0000; } .FileNameCaptionStyle { font-size: 12px; } .progress { display: -ms-flexbox; display: flex; height: 20px; overflow: hidden; font-size: .75rem; background-color: #e9ecef; border-radius: .25rem; margin-top: 10px; box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); } .progress-bar { display: flex; flex-direction: column; justify-content: center; overflow: hidden; color: #fff; text-align: center; white-space: nowrap; background-color: #28a745; transition: width .6s ease; font-size: 16px; text-align: center; } ul#imgList { margin: 0px; } ul.thumb-Images li.active{ background:red; }
Add some design for progress bar, delete icon and file display to looks awesome.
Create uploads folder in working directory and create upload.php file in to store all image in uploads folder.
Create upload.php file
File data are pass inside upload.php. We are using base64_encode function so at the end receiver site we are decode it . file_put_contents can write file inside directory.
<?php $target_dir = "./uploads/"; // Upload directory $data = json_decode($_POST["file"]); if($_POST['action']=='add'){ for($i=0; $i<count($data); $i++){ if(!empty($data[$i]->FileName)) { $image_base64 = base64_decode($data[$i]->Content); $temp = explode(".", $data[$i]->FileName); $file_name_cl=time(); $newfilename =$file_name_cl.'.'. end($temp); $file = $target_dir . $newfilename; file_put_contents($file, $image_base64); } } $response = array('error'=>'','success'=>1); echo json_encode($response); }
Final Output
Conclusion
upload multiple image tutorial implementations helps to add this on your project just require to change CSS. you can take all JS, PHP from here.