Categories
PHP

AJAX Multiple Files Upload

In this tutorial, we’ll create an AJAX form that can upload and validate multiple files.

AJAX stands for Asynchronous Javascript And XML. Although X stands for XML, AJAX can use any data format to communicate with the web server. The main purpose of AJAX is to send (submit) or receive data from the server without having to reload the current page.

To understand how AJAX works read AJAX and Javascript tutorial.

Video: Uploading and validating files with AJAX

HTML Form

First, we create an HTML form and specify the id attribute, we use this id to access the form through Javascript to retrieve the form data. Then we add all the necessary form fields including the file upload field, we associate a span tag with each form field to show errors sent by the server for that field, we also specify the unique id attribute value for each span tag to identify it:

  1. Create an HTML Form
  2. Set id attribute and assign a unique value i.e <form id="example">
  3. Add all the necessary form fields
  4. Add a span tag next to each form field to display form errors sent by the server. i.e. <span id="nameError"></span>, PHP use the id value to send the error for a specific field
<html>
 <head>
  <link rel="stylesheet" href="form.css" media="all" />
  <script src="form.js"></script> 
 </head>
 <body>
<h1>AJAX Multiple File Uploads Form</h1>
<form id="exampleForm">
 <label for="name">Username:</label><br>
 <input type="text" name="name" value=""><br>
 <span id="nameError"></span><br>

 <label for="email">Email:</label><br>
 <input type="text" name="email" value=""><br>
 <span id="emailError"></span><br>

 <label for="uploads">Upload Images:</label><br>
 <input type="file" name="uploads[]" multiple><br>
 <span id="uploadsError"></span><br>
 
 <input type="submit" name="submit" value="Save">
</form>
 </body>
</html>

CSS

We used the span tag to display form errors. You can use the CSS to style the entire form as per your needs, but we just style the span tag to show the text (errors) in red color.

/* form.css */
form span {color:red}

JavaScript

The following AJAX code can be use with any HTML form, it submits the entire form by using the Javascript’s FormData interface.

Note: Visit the https://developer.mozilla.org/docs/Web/Guide/AJAX/Getting_Started to learn the AJAX basics.

// form.js
window.onload = (event) => {
 var form = document.querySelector("#exampleForm");
 form.addEventListener("submit", (e) => {
  e.preventDefault();
  var xhr = new XMLHttpRequest();
  xhr.open("POST", "ajax.php", true);
  xhr.send(new FormData(form)); // Send form data to server

  xhr.onreadystatechange = () => { // Receive response from server
   if (xhr.readyState != 4 || xhr.status != 200)
    return;
    var els = form.querySelectorAll("span");
    for (var el in els)
     els[el].innerHTML = '';
  // Server sent the response in JSON format
   var res = JSON.parse(xhr.responseText);
   if (res.error == false) {
    alert ('Form submitted successfully');
    form.reset();
   }
   else {
    for (var id in res) {
     var el = document.getElementById(id);
     el.innerHTML = res[id]+"<br>";
    }
   }
  }
 });
};

PHP

The PHP code validates the form field and uploaded files for size, extension and type. The $errors array stores the errors in key value pairs, the key name is identical to the id of the span tag associated with that form field.

After completing the validation process PHP sends the response to the user in the JSON format by using the json_encode function.

<?php
 // ajax.php
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  $errors   = [];
  $username = $_POST['name'] ?? '';
  $email    = $_POST['email'] ?? '';
  $files    = $_FILES['uploads'] ?? []; // Multiple Files Upload
  
  if (filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
   $errors['emailError'] = 'Invalid email address.'; 
  if (strlen(trim($username)) < 5)
   $errors['nameError'] = 'Minimum 5 characters required';

  //Validating uploaded files
  if (isset($files['name']))
  foreach ($files['name'] as $k => $v) {
   if ($files['error'][$k] == UPLOAD_ERR_OK) {
    //Validate file type, extension, size, etc.
    $ext = pathinfo($files['name'][$k], PATHINFO_EXTENSION);
    $type = mime_content_type($files['tmp_name'][$k]);
    $size = $files['size'][$k];

    if (!in_array($ext, ['jpg','png','gif'])) {
     $errors['uploadsError'] = 'Only jpg, png, and gif files are allowed';
     break;
    }
    if (!in_array($type, ['image/jpeg','image/gif','image/png'])) {
     $errors['uploadsError'] = "The type '$type' is not allowed";
     break;
    }
    if ( $size > 15360 ) {
     $errors['uploadsError'] = 'Maximum 15KB file size is allowed';
     break;
    }
   }
  }
  
  if (empty($errors)){
   echo json_encode(['error'=>false]);
   //Process or save form data
   foreach ($files['name'] as $k => $v) {
    if (is_uploaded_file($files['tmp_name'][$k]))
    move_uploaded_file($files['tmp_name'][$k], 'uploads/'.$files['name'][$k]);
   }
  } else {
   echo json_encode($errors);
  }
 }

Single file ajax (include JS, CSS, and PHP code):

<?php
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  $errors   = [];
  $username = $_POST['name'] ?? '';
  $email    = $_POST['email'] ?? '';
  $files    = $_FILES['uploads'] ?? []; // Multiple Files Upload
  
  if (filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
   $errors['emailError'] = 'Invalid email address.';
  if (strlen(trim($username)) < 5)
   $errors['nameError'] = 'Minimum 5 characters required';

  //Validating uploaded files
  if (isset($files['name']))
  foreach ($files['name'] as $k => $v) {
   if ($files['error'][$k] == UPLOAD_ERR_OK) {
    //Validate file type, extension, size, etc.
    $ext = pathinfo($files['name'][$k], PATHINFO_EXTENSION);
    $type = mime_content_type($files['tmp_name'][$k]);
    $size = $files['size'][$k];

    if (!in_array($ext, ['jpg','png','gif'])) {
     $errors['uploadsError'] = 'Only jpg, png, and gif files are allowed';
     break;
    }
    if (!in_array($type, ['image/jpeg','image/gif','image/png'])) {
     $errors['uploadsError'] = "The type '$type' is not allowed";
     break;
    }
    if ( $size > 15360 ) {
     $errors['uploadsError'] = 'Maximum 15KB file size is allowed';
     break;
    }
   }
  }
  
  if (empty($errors)){
   echo json_encode(['error'=>false]);
   //Process or save form data
   
   foreach ($files['name'] as $k => $v) {
    if (is_uploaded_file($files['tmp_name'][$k]))
     move_uploaded_file($files['tmp_name'][$k], 'uploads/'.$files['name'][$k]);
   }
   
  } else {
   echo json_encode($errors);
  }
 }
 else
  form();

function form() {
?>
<style>
form span {color:red}
h1 {font-size:105%}
</style>
<h1>AJAX Multiple File Uploads Form</h1>
<form id="exampleForm">
 <label for="name">Username:</label><br>
 <input type="text" name="name" value=""><br>
 <span id="nameError"></span><br>

 <label for="email">Email:</label><br>
 <input type="text" name="email" value=""><br>
 <span id="emailError"></span><br>

 <label for="uploads">Upload Images:</label><br>
 <input type="file" name="uploads[]" multiple><br>
 <span id="uploadsError"></span><br>
 
 <input type="submit" name="submit" value="Save">
</form>
<script>
 var form = document.querySelector("#exampleForm");
 form.addEventListener("submit", (e) => {
  e.preventDefault();
  var xhr = new XMLHttpRequest();
  xhr.open("POST", "ajax.php", true);
  xhr.send(new FormData(form)); // Send form data to server

  xhr.onreadystatechange = () => { // Receive response from server
   if (xhr.readyState != 4 || xhr.status != 200)
    return;
    var els = form.querySelectorAll("span");
    for (var el in els)
     els[el].innerHTML = '';
   var res = JSON.parse(xhr.responseText);
   if (res.error == false) {
    alert ('Form submitted successfully');
    form.reset();
   }
   else {
    for (var id in res) {
     var el = document.getElementById(id);
     el.innerHTML = res[id]+"<br>";
    }
   }
  }
 });
</script>
<?php
}

Processing Forms in PHP: