Hey Friend! Let's Build a Cool File Uploader
Uploading multiple files with a progress bar? Sounds cool, right?
we’re building exactly that! create a Multiple File Uploading system using HTML, CSS, JavaScript (jQuery), and PHP. You’ll be able to drag & drop files, see a progress bar, and even cancel or delete uploads if needed. Let’s do this step by step!
Features We’re Adding:
- Drag & drop file upload
- Real-time progress bar
- Show file details (name, size, status)
- Cancel or delete uploaded files
- Server-side handling with PHP and MySQL
What You Need:
- Basic knowledge of HTML, CSS, JavaScript, and PHP
- A local server (XAMPP, WAMP, or MAMP)
- A database (if you want to store uploads)
Step 1: Setting Up the HTML
Let’s start with the structure of our page. We need a drag & drop area and a list to show uploaded files.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload with Progress</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="file-uploader">
<div class="upload-container">
<h6 class="pb-2 mb-0 title-txt">Multiple File Uploads</h6>
</div>
<div class="ms-4 file-inr">
<p id="status-bar" class="status-bar py-3">Files Uploaded: 0 / Completed: 0</p>
<div id="file-drop-area" class="file-container ms-4">
<p>Click or Drag & Drop files here</p>
</div>
<input type="file" id="file-input" multiple hidden>
<div id="file-list" class="file-list ms-4"></div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
Explanation:
The `file-container` is a drop area for dragging files.
`file-input` is hidden but triggered when the user clicks the container.
`file-list` displays uploaded files and progress.
Wow.! perfectly we create html file upload html code and Now ,we need to give a nice look for the html code with css.
Style.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
padding: 15px;
justify-content: center;
min-height: 100vh;
background: #faf9fe;
}
.file-uploader{
width: 500px;
background: #fff;
border-radius: 5px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.file-inr{padding-bottom:3rem;}
.file-uploader .upload-container {
padding: 20px;
background: #EEF1FB;
align-items: center;
border-radius: 5px 5px 0 0;
justify-content: space-between;
}
.upload-container .title-txt{
font-size: 1.2rem;
font-weight: 700;
text-transform: uppercase;
}
.file-container {
width: 400px;
border: 2px dashed #007bff;
background-color: white;
padding: 20px;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
border-radius: 10px;
transition: 0.3s;
cursor: pointer;
}
.file-container p {
margin: 0;
font-size: 18px;
color: #333;
}
.file-container.drag-over {
border-color: #28a745;
background-color: #f1f8f4;
}
.file-list {
margin-top: 20px;
width: 400px;
}
.file-item {
display: flex;
align-items: center;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.1);
margin-bottom: 10px;
position: relative;
}
.file-icon {
width: 40px;
height: 40px;
background-color: #6c5ce7;
color: white;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
font-size: 14px;
margin-right: 10px;
text-transform: uppercase;
}
.file-info {
flex-grow: 1;
}
.file-name {
font-size: 14px;
font-weight: bold;
color: #333;
}
.file-size {
font-size: 12px;
color: #666;
}
.progress-container {
width: 100%;
height: 4px;
background: #ddd;
border-radius: 2px;
margin-top: 5px;
position: relative;
}
.progress-bar {
height: 4px;
background: #6c5ce7;
width: 0%;
border-radius: 2px;
}
.delete-btn, .cancel-btn {
cursor: pointer;
color: #333;
font-weight: bold;
margin-left: 10px;
}
.delete-btn {
color: #333;
cursor: pointer;
display: none; /* Initially hidden */
}
.status-bar {
margin-top: 15px;
font-size: 16px;
font-weight: bold;
color: #333;
text-align:center;
}
Step 2: JavaScript to Handle File Upload
Now, let’s make this thing actually work! Copy and paste this into a script.js file.
$(document).ready(function () {
let fileDropArea = $("#file-drop-area");
let fileInput = $("#file-input");
let fileList = $("#file-list");
let statusBar = $("#status-bar");
let totalFiles = 0;
let completedFiles = 0;
fileDropArea.on("click", function () {
fileInput.click();
});
fileInput.on("change", function (e) {
let files = e.target.files;
handleFiles(files);
});
fileDropArea.on("dragover", function (e) {
e.preventDefault();
fileDropArea.addClass("drag-over");
});
fileDropArea.on("dragleave", function () {
fileDropArea.removeClass("drag-over");
});
fileDropArea.on("drop", function (e) {
e.preventDefault();
fileDropArea.removeClass("drag-over");
let files = e.originalEvent.dataTransfer.files;
handleFiles(files);
});
function handleFiles(files) {
totalFiles += files.length;
updateStatus();
for (let file of files) {
uploadFile(file);
}
}
function uploadFile(file) {
let formData = new FormData();
formData.append("file", file);
let fileExt = file.name.split('.').pop().toUpperCase();
let fileItem = $(`
<div class="file-item">
<div class="file-icon">${fileExt}</div>
<div class="file-info">
<div class="file-name">${file.name}</div>
<div class="file-size">${(file.size / 1024).toFixed(2)} KB • Uploading...</div>
<div class="progress-container">
<div class="progress-bar"></div>
</div>
</div>
<span class="cancel-btn">X</span>
<span class="delete-btn"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5M8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5m3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0"/>
</svg></span>
</div>
`);
fileList.append(fileItem);
let progressBar = fileItem.find(".progress-bar");
let fileSizeText = fileItem.find(".file-size");
let cancelBtn = fileItem.find(".cancel-btn");
let deleteBtn = fileItem.find(".delete-btn");
let xhr = new XMLHttpRequest();
xhr.open("POST", "upload.php", true);
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
let percent = (e.loaded / e.total) * 100;
progressBar.css("width", percent + "%");
fileSizeText.text(`${(e.loaded / 1024).toFixed(2)} KB / ${(file.size / 1024).toFixed(2)} KB • Uploading...`);
}
};
xhr.onload = function () {
if (xhr.status == 200) {
let response = JSON.parse(xhr.responseText);
if (response.status === "success") {
progressBar.css("background", "#28a745");
fileSizeText.text(`${(file.size / 1024).toFixed(2)} KB / ${(file.size / 1024).toFixed(2)} KB • Completed`);
completedFiles++;
updateStatus();
cancelBtn.hide();
deleteBtn.show();
deleteBtn.on("click", function () {
deleteFile(response.file_path, fileItem);
});
} else {
progressBar.css("background", "red");
fileSizeText.text("Upload Failed");
}
}
};
cancelBtn.on("click", function () {
xhr.abort();
fileItem.remove();
totalFiles--;
updateStatus();
});
xhr.send(formData);
}
function deleteFile(filePath, fileItem) {
$.ajax({
url: "upload.php",
type: "POST",
data: { delete: true, file_path: filePath },
success: function (response) {
let res = JSON.parse(response);
if (res.status === "success") {
fileItem.remove();
totalFiles--;
completedFiles--;
updateStatus();
}
}
});
}
function updateStatus() {
statusBar.text(`Files Uploaded: ${totalFiles} / Completed: ${completedFiles}`);
}
});
Step 3: PHP Backend to Handle Uploads
Now, let’s handle the uploaded files on the server with upload.php
<?php
// Database connection using PDO (Update with your database credentials)
$host = 'localhost';
$dbname = 'file_uploads';
$username = 'root'; // Change this if needed
$password = ''; // Change this if needed
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die(json_encode(["status" => "error", "message" => "Database connection failed."]));
}
// Create upload directory if it doesn't exist
$uploadDir = "uploads/";
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
// Handle file upload
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_FILES['file'])) {
$file = $_FILES['file'];
$fileName = basename($file['name']);
$fileSize = $file['size'];
$fileTmp = $file['tmp_name'];
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'docx', 'txt', 'zip', 'mp4'];
$maxSize = 10 * 1024 * 1024; // 10MB max file size
if (!in_array($fileExt, $allowedExtensions)) {
echo json_encode(["status" => "error", "message" => "Invalid file type."]);
exit;
}
if ($fileSize > $maxSize) {
echo json_encode(["status" => "error", "message" => "File size exceeds the 10MB limit."]);
exit;
}
// Generate unique file name
$uniqueName = uniqid() . "." . $fileExt;
$filePath = $uploadDir . $uniqueName;
// Move file to server
if (move_uploaded_file($fileTmp, $filePath)) {
// Insert into database
$stmt = $pdo->prepare("INSERT INTO uploads (file_name, file_size, file_type, file_path, uploaded_at) VALUES (?, ?, ?, ?, NOW())");
$stmt->execute([$fileName, $fileSize, $fileExt, $filePath]);
echo json_encode(["status" => "success", "message" => "File uploaded successfully.", "file_name" => $fileName, "file_path" => $filePath]);
} else {
echo json_encode(["status" => "error", "message" => "Failed to move uploaded file."]);
}
exit;
}
// Handle file deletion
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['delete']) && isset($_POST['file_path'])) {
$filePath = $_POST['file_path'];
// Check if file exists
if (file_exists($filePath)) {
unlink($filePath); // Delete file from server
// Delete from database
$stmt = $pdo->prepare("DELETE FROM uploads WHERE file_path = ?");
$stmt->execute([$filePath]);
echo json_encode(["status" => "success", "message" => "File deleted successfully."]);
} else {
echo json_encode(["status" => "error", "message" => "File not found."]);
}
exit;
}
echo json_encode(["status" => "error", "message" => "Invalid request."]);
?>
Here MySQL Database Table code:
CREATE TABLE `uploaded_files` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`file_name` varchar(255) NOT NULL,
`uploaded_at` timestamp NOT NULL DEFAULT current_timestamp()
)
Done!
Boom!
You just built a Multiple File Uploading System with a Progress Bar using HTML, CSS, JavaScript, and PHP. The script allows users to drag and drop files, see upload progress, and delete uploaded files. Now you can enhance it by:
Adding a database to store uploads
Showing file preview for images
Restricting file types and sizes
Hope you had fun building this!