06/04/2021, 14:48

Multi upload file với Progress bar trong PHP - Bài tập Javascript

Xin chào tất cả các bạn, hôm nay mình xin hướng dẫn các bạn cách xây dựng chức năng upload nhiều ảnh cùng một lúc xem trước, kết hợp thanh tiến trình (progress bar) với ngôn ngữ PHP và Ajax. Đây là một chức năng khá cần thiết cho các dự án như mạng xã hội, forum, trang chia sẻ ảnh, ... Để ...

Xin chào tất cả các bạn, hôm nay mình xin hướng dẫn các bạn cách xây dựng chức năng upload nhiều ảnh cùng một lúc xem trước, kết hợp thanh tiến trình (progress bar) với ngôn ngữ PHP và Ajax. Đây là một chức năng khá cần thiết cho các dự án như mạng xã hội, forum, trang chia sẻ ảnh, ... Để có thể viết được chức năng này, mình yêu cầu các bạn phải biết cách upload file lên server với PHP đã, nếu bạn nào chưa tìm hiểu về vấn đề này, có thể học ngay trên blog. Bây giò chúng ta bắt đầu thôi!

1. Ý tưởng và cấu trúc thư mục 

Đầu tiên để mình nói sơ qua về ý tưởng cho chức năng này. Chúng ta sẽ upload ảnh thông qua Ajax, xử lý đuôi ảnh, chạy thanh tiến trình, những lỗi này nọ rồi mình mới gửi dữ liệu qua PHP để hoàn tất quá trình upload. Mình thấy có một số trường hợp gửi qua PHP rồi mới xử lý thì thấy không hay cho lắm, vì chẳng lẽ bắt người ta chờ một hồi cho thanh tiến trình chạy xong rồi mới thông báo lỗi thì có phần hơn khó chịu, đặc biệt là upload video.

Đây là toàn bộ cấu trúc co chức năng này:

cau truc thu muc upload nhieu anh xem truoc va progress bar voi php ajax jpg

Trong đó:

  • css/style.css sẽ viết giao diện cho toàn bộ layout của chức năng.
  • js/jquery.form.js là thư viện jQuery Form, các bạn có thể download tại source code bài viết hoặc download tại đây.
  • js/jquery.js là thư viện jQuery, các bạn có thể download tại source code bài viết hoặc download tại đây.
  • js/main.js là file sẽ xử lý ảnh, cũng như thực hiện xem trước và chạy thanh tiến trình trước khi gửi đến file PHP.
  • index.php là file chứa layout thao tác của chức năng.
  • upload.php là file sẽ nhận dữ liệu được gửi từ js/main.js để hoàn tất quá trình upload.

2. Xây dựng layout

Viết HTML

Các bạn mở file index.php rồi dán nội dung này vào:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Upload nhiều ảnh xem trước và thanh tiến trình</title>
	<link rel="stylesheet" href="css/style.css">
</head>
<body>
	<div class="box-upload">
		<h2>Upload hình ảnh</h2>
		<form action="upload.php" method="POST" enctype="multipart/form-data" id="formUpload" onsubmit="return false;">
			<div class="progress">
				<div class="progress-bar">0%</div>
			</div>
			<input type="file" name="img_file[]" multiple="true" onchange="previewImg(event);" id="img_file" accept="image/*">
			<div class="box-preview-img"></div>
			<button type="reset" class="btn-reset">Làm mới</button>
			<button type="submit" class="btn-submit">Upload</button>
			<div class="output"></div>
		</form>
	</div>
	<script src="js/jquery.js"></script>
	<script src="js/jquery.form.js"></script>
	<script src="js/main.js"></script>
</body>
</html>
Trong đó:

  • div.box-upload là khung của chức năng.
  • form#formUpload là form upload. Trong đó:
    • enctype="multipart/form-data" đây là thuộc tính để form có thể upload file được.
    • onsubmit="return false;" là sự kiện không load trang khi submit.
  • div.progress là thanh tiến trình (mặc định là 0%).
  • #img_file là nút để chọn hình ảnh. Trong đó:
    • name="img_file[]" là mảng để có thể chứa nhiều file.
    • multipart="true" để cho phép chọn được nhiều file.
    • onchange="previewImg(event);" là sự kiện để chạy hàm xem trước khi chọn hoặc thay đổi file (Hàm này mình sẽ viết ở bước Viết Ajax xử lý).
    • accept="image/*" chỉ cho phép chọn những file là ảnh.
  • div.box-preview-img sẽ chứa những hình ảnh xem trước.
  • button.btn-reset là nút reset lại form upload.
  • button.btn-submit là nút bắt đầu upload.

Viết CSS

Mở file css/style.css là patse đoạn code này:

/* Reset CSS */
* {padding: 0; margin: 0;}
body {font-family: 'Helvetica Neue', Arial, Helvetica,'Nimbus Sans L', sans-serif, 'Calibri'; font-size: 14px; color: #444; background-color: #ecf0f5;}
h1, h2, h3, h4, h5, h6 {font-weight: normal;}
.clearfix {clear: both;}
button {display: inline-block; margin-top: 10px; margin-right: 5px; padding: 7px; font-size: 14px; border-radius: 4px;}
button:hover {cursor: pointer; opacity: 0.8;}

/* Box upload */
.box-upload {width: 500px; margin: 20px auto; border: 1px solid #e5e5e5; background-color: #fff; padding: 10px;}
.box-upload h2 {text-align: center; margin-bottom: 20px;}
.progress {padding: 2px; border: 1px solid #e5e5e5; border-radius: 4px; margin-bottom: 10px; display: none;}
.progress-bar {background-color: #428bca; color: #fff; text-align: center; border-radius: 4px; padding: 2px 0; width: 0;}
input[type=file] {display: block; font-size: 14px;}
.box-preview-img {margin-top: 10px; display: none;}
.box-preview-img p {font-weight: bold;}
.box-preview-img img {width: 50px; height: 50px; border: 1px solid #e5e5e5; margin-right: 5px; margin-top: 5px;}
button.btn-reset {background-color: #fff; border: 1px solid #ccc; color: #444;}
button.btn-submit {background-color: #428bca; border: 1px solid #428bca; color: #fff;}
.output {display: none; background-color: #d9534f; color: #fff; padding: 7px; border-radius: 4px; margin-top: 10px;}
.success {background-color: #5cb85c;}
Đây chỉ là giao diện đơn giản thôi, bạn nào muốn thì có thể thay thế bằng giao diện khác cũng được.

2. Viết Ajax xử lý

Trong phần này mình sẽ chia ra làm ba mục nhỏ

Xem hình ảnh trước khi upload

Các bạn mở file js/main.js lên rồi chèn đoạn code này:

// Xem hình ảnh trước khi upload
function previewImg(event) {
	// Gán giá trị các file vào biến files
    var files = document.getElementById('img_file').files; 

    // Show khung chứa ảnh xem trước
    $('#formUpload .box-preview-img').show();

    // Thêm chữ "Xem trước" vào khung
    $('#formUpload .box-preview-img').html('<p>Xem trước</p>');

    // Dùng vòng lặp for để thêm các thẻ img vào khung chứa ảnh xem trước
    for (i = 0; i < files.length; i++)
    {
    	// Thêm thẻ img theo i
        $('#formUpload .box-preview-img').append('<img src="" id="' + i +'">');

        // Thêm src vào mỗi thẻ img theo id = i
        $('#formUpload .box-preview-img img:eq('+i+')').attr('src', URL.createObjectURL(event.target.files[i]));
    }   
}

Nút reset form upload

Nút này thì cũng đơn giản thôi, các bạn copy đoạn code này rồi chèn tiếp vào phía dưới nhé:

// Nút reset form upload
$('#formUpload .btn-reset').on('click', function() {
	// Làm trống khung chứa hình ảnh xem trước
	$('#formUpload .box-preview-img').html('');

	// Hide khung chứa hình ảnh xem trước
	$('#formUpload .box-preview-img').hide();

	// Hide khung hiển thị kết quả
	$('#formUpload .output').hide();
});

Xử lý file và upload

Như mình đã nói ở phần ý tưởng, mình sẽ viết xử lý fle ở đây rồi mới tiến hành upload. Đây là phần quan trọng của bài, các bạn chú ý theo dõi từng bước, các bạn copy đoạn code này rồi dán tiếp vào bên dưới rồi mình sẽ giải thích kỹ hơn:

// Xử lý ảnh và upload
$('#formUpload .btn-submit').on('click', function() {
	// Gán giá trị của nút chọn tệp vào var img_file
	$img_file = $('#formUpload #img_file').val();

	// Cắt đuôi của file để kiểm tra
	$type_img_file = $('#formUpload #img_file').val().split('.').pop().toLowerCase();

	// Nếu không có ảnh nào
	if ($img_file == '')
	{
		// Show khung kết quả
		$('#formUpload .output').show();

		// Thông báo lỗi
		$('#formUpload .output').html('Vui lòng chọn ít nhất một file ảnh.');
	}
	// Ngược lại nếu file ảnh không hợp lệ với các đuôi bên dưới
	else if ($.inArray($type_img_file, ['png', 'jpeg', 'jpg', 'gif']) == -1)
	{
		// Show khung kết quả
		$('#formUpload .output').show();

		// Thông báo lỗi
		$('#formUpload .output').html('File ảnh không hợp lệ với các đuôi .png, .jpeg, .jpg, .gif.');
	}
	// Ngược lại
	else
	{
		// Tiến hành upload 
		$('#formUpload').ajaxSubmit({ 
			// Trước khi upload
	        beforeSubmit: function() {
	            target:   '#formUpload .output',

	            // Ẩn khung kết quả
	            $('#formUpload .output').hide();

	            // Show thanh tiến trình
	            $("#formUpload .progress").show();

	            // Đặt mặc định độ dài thanh tiến trình là 0
	            $("#formUpload .progress-bar").width('0');
	        },

	        // Trong quá trình upload
	        uploadProgress: function(event, position, total, percentComplete){ 
	        	// Kéo dãn độ dài thanh tiến trình theo % tiến độ upload
	            $("#formUpload .progress-bar").css('width', percentComplete + '%');

	            // Hiển thị con số % trên thanh tiến trình
	            $("#formUpload .progress-bar").html(percentComplete + '%');
	        },
	        // Sau khi upload xong
	        success: function() {    
	        	// Show khung kết quả 
	        	$('#formUpload .output').show();

	        	// Thêm class success vào khung kết quả
	        	$('#formUpload .output').addClass('success');

	        	// Thông báo thành công
	        	$('#formUpload .output').html('Upload ảnh thành công.');
	        },
	        // Nếu xảy ra lỗi
	        error : function() {
	        	// Show khung kết quả
	            $('#formUpload .output').show();

	            // Thông báo lỗi
	            $('#formUpload .output').html('Không thể upload ảnh vào lúc này, hãy thử lại sau.');
	        }
	    }); 
	    return false; 
	}
});

Giải thích:

  • Ở phần cắt đuôi file có có sử dùng một số hàm như:
    • split() dùng để chuyển một chuỗi sang mảng với tham số truyền vào là ký tự ngăn cách giữa các phần tử (ở đây mình dùng dấu .).
    • pop() dùng để lấy đuôi phía sau của file phần tử cuối cùng trong mảng (tức là đuôi ảnh).
    • toLowerCase() dùng để chuyển kí tự sang chữ thường.
  • Ở phần kiểm tra định dạng ảnh mình có sử dụng $.inArray trong jQuery để kiểm tra, nó cũng như hàm .indexOf() trong Javascript để kiểm tra sự tồn tại của giá trị trong mảng, nếu không tồn tại nó sẽ trả về -1.

3. Viết PHP lưu file ảnh

Đây là bước cuối cùng của chức năng này, bước này thì cũng khá đơn giản đối với những bạn đã biết cách upload file lên server bằng PHP đơn giản. Nhưng trong chức năng này vì upload nhiều file cùng một lúc nên mình phải dùng vòng lặp for để có thể lưu cùng lúc nhiều ảnh được. Bây giờ các bạn copy đoạn code sau và paste vào file upload.php:

<?php

// Sử dụng vòng lặp for để lưu từng file trong mảng
foreach($_FILES['img_file']['name'] as $name => $value)
{
	$name_img = stripslashes($_FILES['img_file']['name'][$name]);
	$source_img = $_FILES['img_file']['tmp_name'][$name];
	$path_img = "upload/" . $name_img;
	move_uploaded_file($source_img, $path_img);
}

?>
Ok! Chúng ta đã xây dựng xong chức năng này rồi đấy, các bạn có thể chạy thử để xem thành quả của mình đạt được trong bài này. Ngoài ra để lưu vào trong CSDL thì các bạn đặt lệnh SQL trong vòng lặp luôn nhé!

4. Lời kết

Đây là một chức năng khá hay và hữu ích cho các dự án về site xã hội. Hi vọng qua bài này sẽ giúp ích và giải đáp được thắc mắc cho các bạn muốn tìm hiểu về mục này. Cảm ơn các bạn đã theo dõi, chúc các bạn thành công! 

Tạ Quốc Bảo

23 chủ đề

7270 bài viết

Cùng chủ đề
0