PHP Online

Lập Trình PHP Nâng Cao

Hướng dẫn Upload File bằng AJAX kết hợp với Progress Bar

Khi nghe đến tiêu đề thì chắc hẳn các bạn không lạ lẫm gì với kỹ thuật AJAX trong Javascript rồi. Nếu như trước đây, các bạn từng biết cách sử dụng kỹ thuật AJAX trong việc gửi comment, load trang, thêm giỏ hàng..v...v...Và bây giờ các bạn sẽ được làm quen với Kỹ thuật AJAX với Upload và cách các bạn có thể Upload một lúc nhiều File cũng bằng chính kỹ thuật này.

 
Chắc các bạn cũng đang rất hứng khởi với nó đúng không? Để bắt tay ngay và luôn:
 
Điều đầu tiên, chúng ta sẽ phải tạo ra một file index.php, không nhất thiết là php vì file này hoàn toàn chúng ta không sử dụng PHP gì trong đó, nếu như bạn có nhu cầu, nội dung file như thế này:
 
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>Mini Upload Tool</title>
	<link rel="stylesheet" href="css/bootstrap.min.css">
	<style type="text/css">
		.progress {
			position: relative;
		}

		.progress-text {
			position: absolute;
			width: 100%;
			height: 100%;
			text-align: right;
			padding-right: 5px;
			color: #333;
		}
	</style>
</head>
<body>
	<img src="images/progressbar.gif" style="display:none" />
	<div class="container">
		<h1>Mini Upload Tool</h1>
		<form role="form" action="#" method="post" enctype="multipart/form-data" onsubmit="return doUpload();">
		  <div class="form-group">
		    <label for="myfile">File Upload</label>
		    <input type="file" class="form-control" name="myfile" id="myfile" multiple>
		  </div>	  
		  <input type="submit" class="btn btn-default" value="Upload" />
		  <input type="button" class="btn btn-default" value="Cancle" onclick="cancleUpload();"/>
		</form>
		<hr>
			<div id="progress-group">
				<div class="progress">
			      <div class="progress-bar" style="width: 60%;">
			        Tên file ở đây
			      </div>
			      <div class="progress-text">
			      	Tiến trình ở đây
			      </div>
			    </div>
			    <div class="progress">
			      <div class="progress-bar" style="width: 40%;">
			        Tên file ở đây
			      </div>
			      <div class="progress-text">
			      	Tiến trình ở đây
			      </div>
			    </div>
			</div>
	</div>
	
    
	<script type="text/javascript" src="js/function.js"></script>
</body>
</html>

 

Trong đó, các cấu trúc mà tôi đã tạo sẵn đã bao gồm thư viện Bootstrap vào trong đó. Bạn có thể tải Bootstrap tại http://getbootstrap.com và chép file bootstrap.min.css vào thư mục như cấu trúc của tôi bên trên.

Trong file này, tôi cũng đã customize CSS một số thứ và đã demo ngay khi các bạn mở file này lên.

Các bạn nên lưu ý những thứ sau trong file của tôi:


1. File Input sẽ có id là "myfile"


2. Để Upload nhiều file cùng lúc các bạn không quên đến thuộc tính Multiple trong File Input nhé.


3. Form có sự kiện onsubmit gửi tới hàm doUpload()


4. Button Cancle sẽ có sự kiện onclick gửi tới hàm cancleUpload()


5. Source JS tôi trỏ đến file function.js


6. Vùng div#progress-group do tôi tạo ra để khi chúng ta Upload sẽ tạo ra thêm các vùng chứa các thanh tiến trình tại đây.


7. Cuối cùng là thẻ img tôi chèn ở đầu body, giúp cho việc chúng ta sử dụng AJAX được trơn tru hơn, bằng cách load file hình này vào trước để trình duyệt cache.

 

Rồi trong file function.js của tôi sẽ như thế này:

//Biến toàn cục
var http_arr = new Array();

function doUpload() {
	document.getElementById('progress-group').innerHTML = ''; //Reset lại Progress-group
	var files = document.getElementById('myfile').files; 
	for (i=0;i<files.length;i++) {
		uploadFile(files[i], i);
	}
	return false;
}

function uploadFile(file, index) {
	var http = new XMLHttpRequest();
	http_arr.push(http);
	/** Khởi tạo vùng tiến trình **/
	//Div.Progress-group
	var ProgressGroup = document.getElementById('progress-group');
	//Div.Progress
	var Progress = document.createElement('div');
	Progress.className = 'progress';
	//Div.Progress-bar
	var ProgressBar = document.createElement('div');
	ProgressBar.className = 'progress-bar';
	//Div.Progress-text
	var ProgressText = document.createElement('div');
	ProgressText.className = 'progress-text';	
	//Thêm Div.Progress-bar và Div.Progress-text vào Div.Progress
	Progress.appendChild(ProgressBar);
	Progress.appendChild(ProgressText);
	//Thêm Div.Progress và Div.Progress-bar vào Div.Progress-group	
	ProgressGroup.appendChild(Progress);


	//Biến hỗ trợ tính toán tốc độ
	var oldLoaded = 0;
	var oldTime = 0;
	//Sự kiện bắt tiến trình
	http.upload.addEventListener('progress', function(event) {	
		if (oldTime == 0) { //Set thời gian trước đó nếu như bằng không.
			oldTime = event.timeStamp;
		}	
		//Khởi tạo các biến cần thiết
		var fileName = file.name; //Tên file
		var fileLoaded = event.loaded; //Đã load được bao nhiêu
		var fileTotal = event.total; //Tổng cộng dung lượng cần load
		var fileProgress = parseInt((fileLoaded/fileTotal)*100) || 0; //Tiến trình xử lý
		var speed = speedRate(oldTime, event.timeStamp, oldLoaded, event.loaded);
		//Sử dụng biến
		ProgressBar.innerHTML = fileName + ' đang được upload...';
		ProgressBar.style.width = fileProgress + '%';
		ProgressText.innerHTML = fileProgress + '% Upload Speed: '+speed+'KB/s';
		//Chờ dữ liệu trả về
		if (fileProgress == 100) {
			ProgressBar.style.background = 'url("images/progressbar.gif")';
		}
		oldTime = event.timeStamp; //Set thời gian sau khi thực hiện xử lý
		oldLoaded = event.loaded; //Set dữ liệu đã nhận được
	}, false);
	

	//Bắt đầu Upload
	var data = new FormData();
	data.append('filename', file.name);
	data.append('myfile', file);
	http.open('POST', 'upload.php', true);
	http.send(data);


	//Nhận dữ liệu trả về
	http.onreadystatechange = function(event) {
		//Kiểm tra điều kiện
		if (http.readyState == 4 && http.status == 200) {
			ProgressBar.style.background = ''; //Bỏ hình ảnh xử lý
			try { //Bẫy lỗi JSON
				var server = JSON.parse(http.responseText);
				if (server.status) {
					ProgressBar.className += ' progress-bar-success'; //Thêm class Success
					ProgressBar.innerHTML = server.message; //Thông báo				
				} else {
					ProgressBar.className += ' progress-bar-danger'; //Thêm class Danger
					ProgressBar.innerHTML = server.message; //Thông báo
				}
			} catch (e) {
				ProgressBar.className += ' progress-bar-danger'; //Thêm class Danger
				ProgressBar.innerHTML = 'Có lỗi xảy ra'; //Thông báo
			}
		}
		http.removeEventListener('progress'); //Bỏ bắt sự kiện
	}
}

function cancleUpload() {
	for (i=0;i<http_arr.length;i++) {
		http_arr[i].removeEventListener('progress');
		http_arr[i].abort();
	}
	var ProgressBar = document.getElementsByClassName('progress-bar');
	for (i=0;i<ProgressBar.length;i++) {
		ProgressBar[i].className = 'progress progress-bar progress-bar-danger';
	}	
}


function speedRate(oldTime, newTime, oldLoaded, newLoaded) {
		var timeProcess = newTime - oldTime; //Độ trễ giữa 2 lần gọi sự kiện
		if (timeProcess != 0) {
			var currentLoadedPerMilisecond = (newLoaded - oldLoaded)/timeProcess; // Số byte chuyển được 1 Mili giây
			return parseInt((currentLoadedPerMilisecond * 1000)/1024); //Trả về giá trị tốc độ KB/s
		} else {
			return parseInt(newLoaded/1024); //Trả về giá trị tốc độ KB/s
		}
}

Các bạn nên lưu ý các vấn đề như sau:


1. Javascript phân biệt hoa thường (lỗi này gặp rất nhiều)


2. Biết cách sử dụng JSON và cách bẫy lỗi JSON


3. Sử dụng sự kiện event trả về trong addEventListener, các bạn cũng nên lưu ý đối số cuối cùng trong addEventListener nhé, bạn có thể tham khảo tại đây :

http://www.w3schools.com/js/tryit.asp?filename=tryjs_addeventlistener_usecapture

4. Cuối cùng, tôi nghĩ là khi đến với bài viết này, các bạn cũng đã hiểu qua về Javascript và AJAX cũng ít nhiều rồi. Nếu chưa nắm rõ bạn có thể tham khảo lại bài hướng dẫn của thầy Kenny về khái niệm ajax: Kỹ thuật lập trình ajax kết hợp PHP 


Tiếp tục, chúng ta sẽ đến với phần Server-side và ở đây chính là PHP. Các bạn hãy tạo ra file upload.php :

<?php
//Các Mimes quản lý định dạng file
$mimes = array(
	'image/jpeg', 'image/png', 'image/gif'
);
sleep(2);
if (isset($_FILES['myfile'])) {
	$fileName = $_FILES['myfile']['name'];
	$fileType = $_FILES['myfile']['type'];
	$fileError = $_FILES['myfile']['error'];
	$fileStatus = array(
		'status' => 0,
		'message' => ''	
	);
	if ($fileError== 1) { //Lỗi vượt dung lượng
		$fileStatus['message'] = 'Dung lượng quá giới hạn cho phép';
	} elseif (!in_array($fileType, $mimes)) { //Kiểm tra định dạng file
		$fileStatus['message'] = 'Không cho phép định dạng này';
	} else { //Không có lỗi nào
		move_uploaded_file($_FILES['myfile']['tmp_name'], 'uploads/'.$fileName);
		$fileStatus['status'] = 1;
		$fileStatus['message'] = "Bạn đã upload $fileName thành công";
	}	
	echo json_encode($fileStatus);
	exit();
}

Với file PHP này thật sự không quá khó với dân lập trình không chuyên và thật sự rất dễ với PHP Dev. Tôi nghĩ là trong file này tôi cũng không có giải thích gì nhiều biến $_FILES. Nó chỉ sử dụng cách trả về bằng JSON bằng cách encode Array mà tôi đã tạo bên trên về đối tượng JSON:


Status : Tình trạng Upload thành công hay chưa?


Message: Thông báo từ phía server gửi về.

 

Và các bạn lưu ý hơn đó chính là $_FILES['myfile'], như ở trong file function.js, chúng ta đã tạo ra FormData và các khóa Key trong $_FILES được tạo ra từ đó, chứ không phải từ Form mà tôi đã tạo ở index.php và tôi cũng đã cố tình tạo dư ra một khóa "filename" để các bạn có thể tự khám phá khi sử dụng FormData trong Javascript. Chứ nếu mà các bạn chỉ Copy và Paste thì chắc chắn sẽ không chú ý đến chi tiết này vì bên file upload.php tôi có xài cái key filename mà tôi đã tạo ra đâu nào

 

Sau khi hoàn tất các quá trình trên, còn chờ gì mà không tận hưởng thành quả của chúng ta nào.

Hướng dẫn Upload File bằng AJAX kết hợp với Progress Bar

 

Nếu xem qua mà bạn vẫn chưa hiểu, bạn có thể xem phiên bản video để nắm vấn đề rõ hơn nhé:

 

 

Lưu ý: Để xem các video rõ hơn, bạn có thể chọn chế độ HD và mở full màn hình. Chúc các bạn học tốt.

 

Tải toàn bộ mã nguồn của bài hướng dẫn tại đây.


(Ân Vũ)
23958
Bạn vẫn chưa hiểu rõ vấn đề ?. Bạn vẫn còn nhiều điều thắc mắc ?. Bạn gặp lỗi khi thực hành mã lệnh trên ?. Hãy tham gia diễn đàn QHOnline.Info để nhận được sự giúp đỡ từ phía cộng đồng nhanh nhất. Đồng thời tải những tài liệu giá trị tại diễn đàn. Việc đăng ký là hoàn toàn miễn phí, hãy đăng ký ngay để chúng tôi giúp đỡ bạn nhé.

Ghi rõ nguồn từ website QHOnline.Info - Khi bạn phát hành lại thông tin từ website này

Ý kiến cho bài viết này.