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.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>
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;}
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); } ?>
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!