PHP Code Example

DropzoneJS: How to upload files in PHP via AJAX – Drag and drop features

DropzoneJS upload image in PHP

In this tutorial, we will learn how to upload multiple images with drag and drop features by using jQuery and PHP. You will learn to create OOP features of PHP.

DropzoneJS, Are you looking for a jQuery plugin to upload images and files with a progress bar? Are you looking for a library that provides a facility to upload files with a progress bar? Are you looking for a lightweight library that provides drag and drops features. If your answer is “Yes” then you must have to read this tutorial. This tutorial is best for you.

I am going to share a library that provides the facility to upload files with a progress bar. Here, I am talking about the DropzoneJS library. Let’s first see what is DropzoneJS?

What is DropzoneJS?

According to their official site definition “DropzoneJS is an open-source library that provides drag and drops file uploads with image previews.“.

This is a JavaScript library that provides features to upload files by drag and drop features with a progress bar and it also provides the facility to upload multiple images at the same time. The best part of this library is this is not dependent on any other library like jQuery. Let’s see features of this library:

  • It provides facility to upload multiple images at the same time.
  • It also provides facility to select multiple images at a time but uploading one by one. (This one is best features of this library).
  • It doesn’t depend on another library like jQuery that means it works independently in any project and any browsers.
  • It provides validation features to validate files before sending request to server.
  • It shows progress bar when uploading files.
  • It shows preview of images and other supported files.
  • It is very lightweight library because it doesn’t have any dependency.

There are so many features of this library. Some features we have mentioned here. Now, we will learn how to upload files using the DropzoneJS library in PHP Via AJAX? In this tutorial, I am not storing the image path in the database. Here, I am storing images in folders only. If you want to store in database then you can simply store it on database by writing your database connectivity code and insertion code.

Upload files using Drag and Drops features in PHP via Ajax

Now, we will see each steps and code to upload files by DropzoneJS in PHP. If you are beginner then definitely this tutorial will help you and for professional also.

In this tutorial, we will learn to upload image by using Ajax that means without refresh the browser we will upload multiple image and will show multiple images. We will apply validation also in this file.

First Step:

Download the DropzoneJS library from their official site or download from GitHub. If none of these options worked for you then download from my server. Download the DropzoneJS library from my server.

Second Step:
  • Create your project folder under htdocs (If you are using XAMPP) and www (if you are using WAMP).
  • Here, I am going to give the project folder name is ptp_content_bucket
  • Inside this folder, I will create different folders according to different work. See the below image
Folder structure of Project
Folder structure
  • Let’s see each folder role in this project
    • api: This folder is used to write PHP code. In this folder, we will write API to upload, get and delete files.
    • assets: In this folder, we will store all CSS and JS library and code.
    • config: In this folder, we will store all configurations files like constant files etc.
    • helpers: In this folder, we will store helpers that helps in performing different operation by a simple function call.
    • uploads: This folder will contain all uploaded files.
    • file_upload.html: This file contain HTML code.
Drag and drop files
View of DropzoneJS showing in the browser
Third Step: Code writing
  • First, copy your DropzoneJS library and paste into assets/js folder.
  • Create CSS and JS folder inside assets folder to write your CSS and JS code.

file_upload.html

<!DOCTYPE html>
<html>

<head>
    <title>File Upload</title>
    <link rel="stylesheet" href="assets/dropzone-5.7.0/dist/min/dropzone.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css">
    <link rel="stylesheet" href="assets/css/style.css">
</head>

<body>
    <div class="srs_cdn_file_upload">
        <form method="post" enctype="multipart/form-data" id="dropzoneFrom" class="dropzone">
		</form>
    </div>

    <div class="file-listings">
        <div class="srs_cdn_file_list" data-files=""></div>
    </div>

    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="assets/dropzone-5.7.0/dist/min/dropzone.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js"></script>
    <script src="assets/js/common.js"></script>
    <script src="assets/js/file_upload.js"></script>
    <script src="assets/js/file_delete.js"></script>
</body>

</html>

Explanation: In the above HTML code, I have linked three CSS one is for DropzoneJS, second one is for toaster to display message in stylish form and third one is my custom CSS stylesheet.

I have also added six JS files for jQuery, DropzoneJS, toaster, common, file upload and file get.

And inside body tag I have added a form tag which has a class attribute that value must be dropzone. If you will change the value of class attribute then DropzoneJS functionality will not work properly.

Second div is for listing all uploaded files on the webpage.

helpers/common_helper.php

<?php

require_once '../config/constant.php';


/**
 * function helps to check requested method is correct or not
 * @param  string $method [method type like POST, GET, PUT]
 * @return json or boolean
 */
function allowedRequestMethod($method = 'POST'){

	if($_SERVER['REQUEST_METHOD'] !== $method){
		$response = [
			'message' => 'Only ' . $method . ' requests are allowed.',
			'code' => 400,
			'error' => true
		];
		echo json_encode($response);die();
	}
	return true;
}



/**
 * function helps to send json response data and exit
 * @param  string or array  $message [message]
 * @param  boolean $error   [error or not]
 * @param  integer $code    [success = 200 and so on]
 * @return json
 */
function jsonResponse($message = '', $error = false, $code = 200){
	echo json_encode([
		'message' => $message,
		'code' => $code,
		'error' => $error
	]);
	die();
}

Explanation: In common helper, I have included constant file to use all defined constant and created two methods one for check input method and second for send response in JSON format. I have created this file to use these functions at every place. We don’t have to write repeated code in the file. This is the best way to become an experienced developer.

config/constant.php

<?php

define('BASE_URL', 'http://localhost/ptp_content_bucket/');
define('FILE_UPLOAD_PATH', '../uploads/');

Now create three different files under assets/js

common.js

/**
 * function helps to show dynamic toster
 * @param  {string} message [message text]
 * @param  {String} type    [type of message success, error, warning]
 * @return
 */
function showTosterMessage(message, type ='success'){

	toastr[type](message)

	toastr.options = {
	  "closeButton": true,
	  "debug": false,
	  "newestOnTop": true,
	  "progressBar": true,
	  "positionClass": "toast-top-right",
	  "preventDuplicates": true,
	  "onclick": null,
	  "showDuration": "300",
	  "hideDuration": "1000",
	  "timeOut": "5000",
	  "extendedTimeOut": "1000",
	  "showEasing": "swing",
	  "hideEasing": "linear",
	  "showMethod": "fadeIn",
	  "hideMethod": "fadeOut"
	}
}

/**
 * function helps to maintain ajax response dynamically
 * @param  object or string response
 * @return 
 */
function maintainAjaxResponse(response){

	response = JSON.parse(response);
	if(response.code == 200 && response.error == false){

		if(!Array.isArray(response.message) && typeof response.message === 'string'){
			showTosterMessage(response.message);return;
		}

		$.each(response.message, function( index, value ) {
		  	showTosterMessage(value );
		});
		return;
	}

	if(!Array.isArray(response.message) && typeof response.message === 'string'){
		showTosterMessage(response.message, 'error');return;
	}

	$.each(response.message, function( index, value ) {
	  	showTosterMessage(value , 'error');
	});
}

Explanation: Common JavaScript file has been created to write all repeated JavaScript code at one place. In this file, I have created two functions. First function is showTosterMessage() that will show message dynamically provided by PHP server and second function is to maintain response.

file_delete.js

$(document).ready(function(){
	listAllImages();
});

function listAllImages(){
	$.ajax({
		url: 'api/get_all_files.php',
		method: 'POST',
		success: function(response){
			$('.file-listings').html(response);
		}
	});
}

/**
 * delete
 */
$(document).on('click', '.close-button', function(){

	if(!confirm('Do you want to remove?')){
		return;
	}

	$.ajax({
		url: 'api/delete_file.php',
		method: 'POST',
		data: {file_path : $(this).parent('div.srs_cdn_file_list').attr('data-files')},
		success: function(response){
			maintainAjaxResponse(response);
			listAllImages();
		}
	});
});

Explanation: In the above file, I have created a function listAllImages() that will get all uploaded files from server and it will display on the web browser and second one is AJAX call to delete a file by clicking on close button.

file_upload.js

Dropzone.autoDiscover = false;

$(document).ready(function(){
	var myDropzone = new Dropzone("#dropzoneFrom", 
	{ 
		dictDefaultMessage: "Drop files here or click to upload.",
		url: "api/File_Upload.php",
		paramName: 'file',
		maxFilesize : 10, //10 MB
		acceptedFiles : 'image/*,.mp4',
		success: function(response){
			var xhrRes = response.xhr;

			if (xhrRes.readyState == 4 && xhrRes.status == 200) {
				
				maintainAjaxResponse(xhrRes.responseText);
				listAllImages();
			}
		}
	});
});

Explanation: In the above files, I have added first line “Dropzone.autoDiscover = false;” that will remove auto features of DropzoneJS to handle according to our requirement. If I will set this true then this will work according to DropzoneJS functionality that means this will not call our Ajax function that’s why I have set this to false to send Ajax request according to our custom use.

You can read about more configuration of Dropzone.

assets/css/style.css


.dropzone{
	width: 50%;
    margin-left: 20%;
    border: 4px dashed blue;
    background: aliceblue;
}
.file-listings{
	margin-top: 10px;
}
.srs_cdn_file_list{
	width: 175px;
	display: inline-block;
	border: 2px solid black;
	margin: 10px;
}
.srs_cdn_file_list img{
	min-width: 175px;
	min-height: 100%;
}

.srs_cdn_file_list .close-button {
    position: relative;
    left: 162px;
    top: -191px;
    z-index: 1;
    background: #ca0606;
    color: #fff;
    width: 22px;
    height: 22px;
    line-height: 22px;
    border-radius: 50%;
    padding: 5px;
}
.srs_cdn_file_list .close-button:hover{
	cursor: pointer;
}

Now, we will create three different file in api folder for different operations:

api/File_Upload.php

<?php

require_once '../helpers/common_helper.php';

/**
 * ============================================================================
 *@className : File_Upload
 *@author  : <sumit kumar gupta>
 *@date : 05-January-2020
 *@purpose : To upload file in folder and return uploaded file in message
 *=============================================================================
 */
class File_Upload
{
	private $fileUpload;
	private $message;
	private $error;

	/**
	 * upload file from this API
	 * @return json
	 */
	public function uploadFile(){

		$this->error = false;
		allowedRequestMethod();

		$this->fileUpload = $_FILES;
		$this->fileValidation();

		if($this->error === true){
			jsonResponse($this->message, true, 400);
		}

		if (!is_dir(FILE_UPLOAD_PATH)) {
		   mkdir(FILE_UPLOAD_PATH, 0777, true);
		}
		
    	$fileName = $_FILES['file']['name'];
    	$fileTmpName  = $_FILES['file']['tmp_name'];
    	$newFileName = rand() . time() . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
		$uploadPath = FILE_UPLOAD_PATH .'/'. basename($newFileName);
		$didUpload = move_uploaded_file($fileTmpName, $uploadPath);

        if ($didUpload) {
        	jsonResponse("The file " . basename($newFileName) . " has been uploaded.");
        }
       	jsonResponse("An error occurred. Please contact the administrator.", true, 400);
	}

	/**
	 * function helps to validate uploaded file
	 * @return empty or error message
	 */
	private function fileValidation(){

		if(!isset($this->fileUpload['file'])){
			$this->error = true;
			$this->message = 'The file field is required';
			return;
		}

		$fileName = $this->fileUpload['file']['name'];
		$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
		
		$validFileExtension = ['jpg', 'png','jpeg','gif','mp4'];

		if(!in_array($ext, $validFileExtension)){
			$this->error = true;
			$this->message['file_ext'] = 'Please upload a valid file. Only jpg, png, jpeg, gif and mp4 files are allowed.';
		}

		$fileSize = $this->fileUpload['file']['size'];
		
		if($fileSize > 10000000){
			$this->error = true;
			$this->message['file_size'] = 'Maximum allowed file size is 10 MB.';
		}
		return;
	}
}

$obj = new File_Upload();
$obj->uploadFile();

api/Get_All_Files.php

<?php

require_once '../helpers/common_helper.php';

$result = array();
$folder_name = BASE_URL . 'uploads/';
$files = scandir('../uploads');

$output = '';

if(false !== $files)
{
	foreach($files as $file)
	{
		if('.' !=  $file && '..' != $file)
		{
			$output .= '
			<div class="srs_cdn_file_list" data-files="../uploads/' . $file . '">
				<img src="'.$folder_name.$file.'" class="img-thumbnail" width="175" height="175" style="height:175px;" />
				<span class="close-button"> X</span>
			</div>
			';
		}
	}
}
$output .= '';
echo $output;

api/Delete_File.php

<?php

require_once '../helpers/common_helper.php';

/**
 * ============================================================================
 *@className : Delete_File
 *@author  : <sumit kumar gupta>
 *@date : 05-January-2020
 *@purpose : To delete file from folder and return message
 *=============================================================================
 */
class Delete_File
{
	private $message;
	private $error;
	private $successMessage;
	private $errorMessage;

	/**
	 * delete file from this API
	 * @return json
	 */
	public function deleteFile(){

		$this->error = false;
		allowedRequestMethod();

		$this->inputValidations();
		if($this->error === true){
			jsonResponse($this->message, true, 400);
		}

		$filePath = $_POST['file_path'];

		$filePathArray = explode(',', $filePath);

		if(empty($filePathArray)){
			jsonResponse('Please provide file path.', true, 400);
		}

		foreach ($filePathArray as $file) {

			$fileName = trim($file);
			if(file_exists($fileName)){
				unlink($fileName);
				$this->successMessage[] = 'File ' . $fileName . ' deleted successfully.';
			}else{
				$this->errorMessage[] = 'The file ' . $fileName . ' does not exist.';
			}
		}

		if(empty($this->successMessage) && !empty($this->errorMessage)){
			jsonResponse($this->errorMessage, true, 400);
		}else if(!empty($this->successMessage) && empty($this->errorMessage)){
			jsonResponse($this->successMessage);
		}else{
			jsonResponse($this->successMessage);
		}
	}

	/**
	 * input field validation
	 * @return json or empty
	 */
	private function inputValidations(){

		if(!isset($_POST['file_path'])){
			$this->error = true;
			$this->message = 'The file path field is required.';
			return;
		}

		if(!is_string($_POST['file_path'])){
			$this->error = true;
			$this->message = 'The file path field must be string.';
			return;
		}
	}

}

$obj = new Delete_File();
$obj->deleteFile();

To understand this complete tutorial watch my YouTube video.

Complete Code on Github: https://github.com/guptatreepoint/ptp_content_bucket

Conclusion and Final Words

According to my point of view, 70% of readers would not understand the complete tutorial but if you try to understand the coding standard, you can write best coding according to different companies coding standards.

Try to remove repeated code from your project because it makes your project fast and easily readable to other developers. When other developer can easily understand code then this is best for both.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.