How to Multiple File Upload in PHP Using Ajax

Multiple file upload in PHP using ajax script is relatively easy to implement. Here is the simplest method to upload multiple files using ajax by just creating four files. Also, we have mentioned multiple file upload in PHP using ajax demo code with proper explanation.

Direct file upload using the form is quite old fashioned. Ajax provides a better user experience during file uploading because ajax works in the background and doesn’t refresh it.

Note: If you are new to PHP, Please read our PHP file upload post first to understand the process of PHP file uploading. Otherwise please continue.

Multiple File Upload in PHP Using Ajax Demo Code

Here, we have created a few simple steps to implement multiple file upload in PHP using Ajax. Please follow the steps to understand the complete multiple file upload in PHP.

Step 1: Create index.html

Create an index.html file to your working path in your local machine (XAMPP/WAMP). This index.html file contains the form to upload files using ajax to PHP server/localhost.

<!DOCTYPE html>
<html>
    <head>
        <title>php-ajax File Uploader</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div id="upfo">
            <input type="file" multiple="" id="file" onchange="upf()">
            <div class="upstacon">
                <h5 class="upstate" id="status"></h5>
    	    </div>
    	</div>
        <script src="script.js"></script>
    </body>
</html>

Step 2: Create style.css

This file includes a style-sheet for the multiple PHP file upload progress-bars.

.cssProgress {
  width: 100%;
}
.cssProgress .progress1,
.cssProgress .progress2,
.cssProgress .progress3 {
  position: relative;
  overflow: hidden;
  width: 100%;
}
.cssProgress .cssProgress-bar {
  display: block;
  float: left;
  width: 0%;
  height: 100%;
  background: #3798d9;
  box-shadow: inset 0px -1px 2px rgba(0, 0, 0, 0.1);
  -webkit-transition: width 0.8s ease-in-out;
          transition: width 0.8s ease-in-out;
}
.cssProgress .cssProgress-label {
  position: absolute;
  overflow: hidden;
  left: 0px;
  right: 0px;
  color: rgba(0, 0, 0, 0.6);
  font-size: 0.7em;
  text-align: center;
  text-shadow: 0px 1px rgba(0, 0, 0, 0.3);
  font-weight: 800;}
.cssProgress .cssProgress-info {
  background-color: #9575cd !important;
}
.cssProgress .cssProgress-danger {
  background-color: #ef5350 !important;
}
.cssProgress .cssProgress-success {
  background-color: #66bb6a !important;
}
.cssProgress .cssProgress-warning {
  background-color: #ffb74d !important;
}
.cssProgress .cssProgress-right {
  float: right !important;
}
.cssProgress .cssProgress-label-left {
  margin-left: 10px;
  text-align: left !important;
}
.cssProgress .cssProgress-label-right {
  margin-right: 10px;
  text-align: right !important;
}
.cssProgress .cssProgress-label2 {
  display: block;
  margin: 2px 0;
  padding: 0 8px;
  font-size: 0.8em;
}
.cssProgress .cssProgress-label2.cssProgress-label2-right {
  text-align: right;
}
.cssProgress .cssProgress-label2.cssProgress-label2-center {
  text-align: center;
}
.cssProgress .cssProgress-stripes,
.cssProgress .cssProgress-active,
.cssProgress .cssProgress-active-right {
  background-image: -webkit-linear-gradient(135deg, rgba(255, 255, 255, 0.125) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.125) 50%, rgba(255, 255, 255, 0.125) 75%, transparent 75%, transparent);
  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.125) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.125) 50%, rgba(255, 255, 255, 0.125) 75%, transparent 75%, transparent);
  background-size: 35px 35px;
}
.cssProgress .cssProgress-active {
  -webkit-animation: cssProgressActive 2s linear infinite;
  -ms-animation: cssProgressActive 2s linear infinite;
  animation: cssProgressActive 2s linear infinite;
}
.cssProgress .cssProgress-active-right {
  -webkit-animation: cssProgressActiveRight 2s linear infinite;
  -ms-animation: cssProgressActiveRight 2s linear infinite;
  animation: cssProgressActiveRight 2s linear infinite;
}
@-webkit-keyframes cssProgressActive {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 35px 35px;
  }
}
@-ms-keyframes cssProgressActive {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 35px 35px;
  }
}
@keyframes cssProgressActive {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 35px 35px;
  }
}
@-webkit-keyframes cssProgressActiveRight {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: -35px -35px;
  }
}
@-ms-keyframes cssProgressActiveRight {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: -35px -35px;
  }
}
@keyframes cssProgressActiveRight {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: -35px -35px;
  }
}
/* -----------------------------------------------------
  Progress Bar 1
-------------------------------------------------------- */
.progress1 {
  background-color: #EEE;
  box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.2);
}
.progress1 .cssProgress-bar {
  height: 18px;
}
.progress1 .cssProgress-label {
  line-height: 18px;
}

/* -----------------------------------------------------
   Progress Bar 2
-------------------------------------------------------- */
.progress2 {
  background-color: #EEE;
  border-radius: 9px;
  box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.2);
}
.progress2 .cssProgress-bar {
  height: 18px;
  border-radius: 9px;
}
.progress2 .cssProgress-label {
  line-height: 18px;
}

/* -----------------------------------------------------
   Progress Bar 3
-------------------------------------------------------- */
.progress3 {
  width: auto !important;
  padding: 4px;
  background-color: rgba(0, 0, 0, 0.1);
  box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.2);
  border-radius: 3px;
}
.progress3 .cssProgress-bar {
  height: 16px;
  border-radius: 3px;
}
.progress3 .cssProgress-label {
  line-height: 16px;
}

/* -----------------------------------------------------
  Progress Bar 4
-------------------------------------------------------- */
.progress4 {
  position: relative;
  width: 100%;
  background-color: #EEE;
}
.progress4.cssProgress-bg {
  background-color: #bbdefb !important;
}
.progress4.cssProgress-bg-info {
  background-color: #d1c4e9 !important;
}
.progress4.cssProgress-bg-danger {
  background-color: #ffcdd2 !important;
}
.progress4.cssProgress-bg-success {
  background-color: #c8e6c9 !important;
}
.progress4.cssProgress-bg-warning {
  background-color: #ffecb3 !important;
}
.progress4 .cssProgress-bar {
  display: block;
  float: none;
  width: 0%;
  height: 4px;
  background: #3798d9;
}
.progress4 .cssProgress-bar.cssProgress-lg {
  height: 6px;
}
.progress4 .cssProgress-bar.cssProgress-2x {
  height: 8px;
}
.progress4 .cssProgress-bar.cssProgress-3x {
  height: 10px;
}
.progress4 .cssProgress-bar.cssProgress-4x {
  height: 12px;
}
.progress4 .cssProgress-bar.cssProgress-5x {
  height: 14px;
}
.progress4 .cssProgress-bar.cssProgress-glow {
  box-shadow: 5px 0px 15px 0px #3798D9;
}
.progress4 .cssProgress-bar.cssProgress-glow.cssProgress-info {
  box-shadow: 5px 0px 15px 0px #9575cd;
}
.progress4 .cssProgress-bar.cssProgress-glow.cssProgress-danger {
  box-shadow: 5px 0px 15px 0px #ef5350;
}
.progress4 .cssProgress-bar.cssProgress-glow.cssProgress-success {
  box-shadow: 5px 0px 15px 0px #66bb6a;
}
.progress4 .cssProgress-bar.cssProgress-glow.cssProgress-warning {
  box-shadow: 5px 0px 15px 0px #ffb74d;
}
.progress4 .cssProgress-bar.cssProgress-glow-active {
  -webkit-animation: cssProgressGlowActive1 3s linear infinite;
  -ms-animation: cssProgressGlowActive1 3s linear infinite;
  animation: cssProgressGlowActive1 3s linear infinite;
}
.progress4 .cssProgress-bar.cssProgress-glow-active.cssProgress-info {
  -webkit-animation: cssProgressGlowActive2 3s linear infinite;
  -ms-animation: cssProgressGlowActive2 3s linear infinite;
  animation: cssProgressGlowActive2 3s linear infinite;
}
.progress4 .cssProgress-bar.cssProgress-glow-active.cssProgress-danger {
  -webkit-animation: cssProgressGlowActive3 3s linear infinite;
  -ms-animation: cssProgressGlowActive3 3s linear infinite;
  animation: cssProgressGlowActive3 3s linear infinite;
}
.progress4 .cssProgress-bar.cssProgress-glow-active.cssProgress-success {
  -webkit-animation: cssProgressGlowActive4 3s linear infinite;
  -ms-animation: cssProgressGlowActive4 3s linear infinite;
  animation: cssProgressGlowActive4 3s linear infinite;
}
.progress4 .cssProgress-bar.cssProgress-glow-active.cssProgress-warning {
  -webkit-animation: cssProgressGlowActive5 3s linear infinite;
  -ms-animation: cssProgressGlowActive5 3s linear infinite;
  animation: cssProgressGlowActive5 3s linear infinite;
}
@-webkit-keyframes cssProgressGlowActive1 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #3798D9;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #3798D9;
  }
}
@-ms-keyframes cssProgressGlowActive1 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #3798D9;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #3798D9;
  }
}
@keyframes cssProgressGlowActive1 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #3798D9;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #3798D9;
  }
}
@-webkit-keyframes cssProgressGlowActive2 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #9575cd;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #9575cd;
  }
}
@-ms-keyframes cssProgressGlowActive2 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #9575cd;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #9575cd;
  }
}
@keyframes cssProgressGlowActive2 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #9575cd;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #9575cd;
  }
}
@-webkit-keyframes cssProgressGlowActive3 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #ef5350;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #ef5350;
  }
}
@-ms-keyframes cssProgressGlowActive3 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #ef5350;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #ef5350;
  }
}
@keyframes cssProgressGlowActive3 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #ef5350;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #ef5350;
  }
}
@-webkit-keyframes cssProgressGlowActive4 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #66bb6a;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #66bb6a;
  }
}
@-ms-keyframes cssProgressGlowActive4 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #66bb6a;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #66bb6a;
  }
}
@keyframes cssProgressGlowActive4 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #66bb6a;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #66bb6a;
  }
}
@-webkit-keyframes cssProgressGlowActive5 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #ffb74d;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #ffb74d;
  }
}
@-ms-keyframes cssProgressGlowActive5 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #ffb74d;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #ffb74d;
  }
}
@keyframes cssProgressGlowActive5 {
  0%, 100% {
    box-shadow: 5px 0px 15px 0px #ffb74d;
  }
  45% {
    box-shadow: 1px 0px 4px 0px #ffb74d;
  }
}


.upstacon{
    margin-top: 5px;
}

.upstate{
    margin: 0px;
}
.upstate2{
    margin: 0px;
    height: 18px;
    overflow: hidden;
}
.upproclocon{
    text-align: center;
    display: none;
    float: right;
    width: 40px;
    height: 24px;
    margin: 0px;
    cursor: pointer;
    position: relative;
    top: -24px;
    color: #ff4600;
    border: 1px dashed #ff4600;
    background-color: #ffc063;
}
.upproclosym{
    margin: 1px;
    font-size: 20px;
}

Step 3: Create script.js

This javascript file holds the Ajax function to handle multiple file upload in the queue. Also, it will generate a dynamic progress bar for each uploading file.

var i=j=0,k;
var file;
var ups;
var fq = [];
var fcq = [];
var que = [];

function _(el){
    return document.getElementById(el);
}

//following function sends files in queue
function upf(){
	if(j-i == 0){
		j = j + _("file").files.length;
		k = 0;
		filesend();
	}
}

//following function makes the request to the reuest_handler.php file
function filesend(){
	var rem = j-i;
	_("status").innerHTML = rem + "file(s) remaining in uploading queue.";
	if(i<j){
		file = _("file").files[k];

		fq[i] = file.name;
		fcq[i] = 0;
		formdata = new FormData();
		formdata.append("file",file);
		if (navigator.appName == "Microsoft Internet Explorer") {
			ups = new ActiveXObject("Microsoft.XMLHTTP");
		}else {
			ups = new XMLHttpRequest();
		}

		crupsta();
		eventhand();
		ups.open("POST","request_handler.php");
		ups.send(formdata);
	}

}


//following function add event listeners for request sent by above Ajax function
function eventhand(){
	ups.upload.addEventListener("progress",pH,false);
	ups.addEventListener("load",cH,false);
	ups.addEventListener("error",eH,false);
	ups.addEventListener("abort",aH,false);

}

//following functions generates dynamic progress-bars in index.html
function crupsta(){
	var scon = document.createElement("div");
	var pbarocon = document.createElement("div");
	var pbaricon = document.createElement("div");
	var pbar = document.createElement("div");
	var pbart = document.createElement("span");

	var pccon = document.createElement("div");
	var pclo = document.createElement("i");

	var pte1 = document.createElement("h5");
	var pte2 = document.createElement("p");
	scon.appendChild(pbarocon);
	pbarocon.appendChild(pbaricon);
	pbaricon.appendChild(pbar);
	pbar.appendChild(pbart);
	scon.appendChild(pccon);
	pccon.appendChild(pclo);
	scon.appendChild(pte2);
	scon.appendChild(pte1);
	var upfcon = document.getElementById("upfo");
	upfcon.appendChild(scon);

	scon.className = "upstacon";

	pbarocon.className = "cssProgress";
	pbaricon.className = "progress3";
	pbar.className = "cssProgress-bar cssProgress-warning cssProgress-stripes";
	pbart.className = "cssProgress-label";
	pccon.className = "upproclocon";
	pclo.className = "upproclosym fas fa-times";
	pte1.className = "upstate";
	pte2.className = "upstate2";

	var cliatt = document.createAttribute("onclick");
	cliatt.value = "proclo(this)";
	pccon.setAttributeNode(cliatt);

	pbar.style.width = "0%";

	pccon.id = "upfclo"+i;
	pbar.id = "pbar"+i;
	pte1.id = "status"+i;
	pte2.id = "lnt"+i;
	pbart.id = "per"+i;
}

function pH(e){
		if(i >= 0){
			if(que[i] === undefined && fq[i] == file.name){
				que[i]= e.total;
			}
		}

		if(e.lengthComputable && (que[i] == e.total)){
				var lnt = "lnt"+i;
				var per = "per"+i;
				var pbar = "pbar"+i;
				var sta = "status"+i;
				var load = e.loaded/1048576;
				var totl = e.total/1048576;
				loadr = load.toFixed(2);
				totlr = totl.toFixed(2);
				var percent = (e.loaded/e.total)*100;

				_(lnt).innerHTML = fq[i];
				_(per).innerHTML = Math.round(percent)+" %";
				_(pbar).style.width = percent+"%";
				_(sta).innerHTML = loadr + " MB of " + totlr + " MB uploded";
		}
}

function cH(event){
		if((_("pbar"+i).style.width == "100%") && (fcq[i]!== 1)){
			fcq[i] = 1;
			_("status"+i).innerHTML = event.target.responseText;
			_("lnt"+i).style.display = "none";
			_("upfclo"+i).style.display = "block";
			_("pbar"+i).setAttribute("style","background-color: #66bb6a !important; width: 100%;");
			k++;
			i++;
			filesend();
		}
}

function eH(event){
	fcq[i] = 1;
	_("status"+i).innerHTML = "upload failed";
	_("lnt"+i).style.display = "none";
	_("upfclo"+i).style.display = "block";
	_("pbar"+i).setAttribute("style","background-color: #66bb6a !important; width: 100%;");
	k++;
	i++;
	fref();
	filesend();
}

function aH(event){
	fcq[i] = 1;
	_("status"+i).innerHTML = "upload aborted";
	_("lnt"+i).style.display = "none";
	_("upfclo"+i).style.display = "block";
	_("pbar"+i).setAttribute("style","background-color: #66bb6a !important; width: 100%;");
	k++;
	i++;
	filesend();
}

function proclo(clob){
	var parob = _("upfo");
	var clobj = clob.parentNode;
	parob.removeChild(clobj);
}

Step 4: Create request_handler.php

This PHP file handles the Ajax request sent by the script.js file.

Fundamentally this file moves the uploaded file from the temporary folder of the current execution file request_handler.php working directory. This PHP file also checks for duplicate file names and automatically renames the latest one with a number sequence.

<?php

if($_SERVER["REQUEST_METHOD"] == "POST" && !empty($_FILES["file"])){

    $fn = $_FILES["file"]["name"]; //file name
    $ftyp = $_FILES["file"]["type"]; //file type
    $ftl = $_FILES["file"]["tmp_name"]; //path of temporary file
    $ft = $_FILES["file"]["size"]; //file size
    $fem = $_FILES["file"]["error"]; //errors if any
    $i = 1;  
    

//check if file successfully uploaded or not in the temporary folder.
    if(!$ftl){
    	echo "ERROR: please browse for file before uploadind";
    	exit();
    }


//check for duplicate file names and renames the latest file in sequence if duplicates found.

    if(file_exists($fn)){
    	$fext = substr($fn,strrpos($fn,"."),strlen($fn));
    	$fntmp1 = substr($fn,0,strrpos($fn,"."));
    	do{
    		$fntmp2 = $fntmp1.(" copy($i)").$fext;
    		$i++;
    	}while(file_exists($fntmp2));
    	$fn = $fntmp2;
    }


//moves uploaded the file to the current directory of the request_handler.php file from the temporary directory of the server.

    if(move_uploaded_file($ftl,$fn)){
        if(file_exists($fn) == 1){
		    echo "$fn uploaded successfully.";
        }else{
            echo "Unknown Error";
        }
    }else{
    	echo "Function Failed.";
    }

}else{
    echo "Incorrect Parameter";
}
?>

Read Also: How to Set Onclick Function in PHP

Conclusion

Now you can effortlessly do multiple file upload in PHP using Ajax. Also, the user can see the rate of file upload in realtime.

I hope you found this article helpful πŸ™‚

Leave a Reply

Your email address will not be published. Required fields are marked *

Read previous post:
PHP form handling
PHP Form Handling

A Form is a document containing blank fields that the user can fill the data or user can select the...

Close