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:

Trong đó:
css/style.csssẽ viết giao diện cho toàn bộ layout của chức năng.js/jquery.form.jslà 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.jslà 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.jslà 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.phplà file chứa layout thao tác của chức năng.upload.phplà 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>
div.box-uploadlà khung của chức năng.form#formUploadlà 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.progresslà thanh tiến trình (mặc định là 0%).#img_filelà 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-imgsẽ chứa những hình ảnh xem trước.button.btn-resetlà nút reset lại form upload.button.btn-submitlà 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;}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
$.inArraytrong 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);
}
?>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!