PHP Multiple File Uploader Using Ajax

Multiple file upload in PHP using ajax script is easy to implement. Here is the simplest method to upload multiple files using ajax by just creating 4 files.

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

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

Steps to implement the PHP-Ajax file uploader.

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 a file.

<!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 progress-bar to make it looks good.

.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 upload multiple files in the queue.

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

Basically this PHP file handles the Ajax request sent by 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";
}
?>

Conclusion

Now you can upload unlimited files using ajax. In addition, user can see the rate of file upload in realtime.

Leave a Reply

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