Khái niệm
Kiểm tra dung lượng file trước khi upload lên server để tiết kiệm bandwidth và cải thiện UX. Sử dụng File API (input.files[0].size).
Ví dụ hoàn chỉnh
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Validate File Size</title>
<style>
body { font-family: 'Segoe UI', sans-serif; padding: 20px; max-width: 600px; margin: 0 auto; }
.result { font-size: 16px; font-weight: 500; margin: 15px 0; padding: 15px; border-radius: 4px; white-space: pre-wrap; }
.success { color: #2e7d32; background: #e8f5e9; }
.error { color: #c62828; background: #ffebee; }
.info { color: #1565c0; background: #e3f2fd; }
input[type="file"] { display: block; margin: 15px 0; padding: 10px; }
.file-info { font-family: monospace; font-size: 14px; }
</style>
</head>
<body>
<h1>Validate File Size khi Upload</h1>
<input type="file" id="fileInput" onchange="validateFile()" accept="image/*,.pdf,.doc,.docx">
<div class="result info" id="result">Chọn file để kiểm tra kích thước...</div>
<script>
const fileInput = document.getElementById('fileInput');
const resEle = document.getElementById('result');
const MAX_SIZE_MB = 4; // 4MB
const MAX_SIZE_BYTES = MAX_SIZE_MB * 1024 * 1024;
function validateFile() {
const file = fileInput.files[0];
if (!file) {
resEle.textContent = 'Chưa chọn file';
resEle.className = 'result info';
return;
}
const sizeMB = (file.size / (1024 * 1024)).toFixed(2);
if (file.size > MAX_SIZE_BYTES) {
resEle.innerHTML = `❌ File quá lớn!
Tên: ${file.name}
Kích thước: ${sizeMB} MB
Giới hạn: ${MAX_SIZE_MB} MB`;
resEle.className = 'result error';
} else {
resEle.innerHTML = `✅ File hợp lệ
Tên: ${file.name}
Kích thước: ${sizeMB} MB
Loại: ${file.type || 'Unknown'}`;
resEle.className = 'result success';
}
}
</script>
</body>
</html>
Kết quả
Chọn file > 4MB: Hiển thị lỗi đỏ.
Chọn file ≤ 4MB: Hiển thị thành công xanh.
Mở rộng: Validate nhiều file, loại file, preview
function validateFiles(input, options = {}) {
const {
maxSizeMB = 10,
allowedTypes = ['image/', 'application/pdf'],
maxFiles = 5
} = options;
const files = Array.from(input.files);
const errors = [];
const validFiles = [];
if (files.length > maxFiles) {
errors.push(`Chỉ cho phép tối đa ${maxFiles} file`);
}
files.forEach(file => {
// Check size
if (file.size > maxSizeMB * 1024 * 1024) {
errors.push(`${file.name}: ${(file.size/1024/1024).toFixed(1)}MB > ${maxSizeMB}MB`);
return;
}
// Check type
const isAllowed = allowedTypes.some(type => file.type.startsWith(type));
if (!isAllowed && allowedTypes.length > 0) {
errors.push(`${file.name}: Loại file không được phép (${file.type})`);
return;
}
validFiles.push(file);
});
return { validFiles, errors };
}
// Usage
fileInput.addEventListener('change', (e) => {
const { validFiles, errors } = validateFiles(e.target, {
maxSizeMB: 5,
allowedTypes: ['image/', 'application/pdf'],
maxFiles: 3
});
if (errors.length) {
showErrors(errors);
}
// Preview valid images
validFiles.forEach(file => previewImage(file));
});
Server-side Validation (BẮT BUỘC)
⚠️ Client-side validation chỉ để UX, KHÔNG bao giờ tin cậy cho bảo mật. Luôn validate lại trên server:
- Kiểm tra Content-Length header
- Stream parsing với giới hạn size (multer: limits.fileSize)
- Kiểm tra MIME type thực tế (magic bytes), không tin extension
- Quét virus/malware
HTML5 Validation Attributes
<input type="file"
accept="image/*,.pdf"
multiple
max-file-size="4194304"
>
{{-- max-file-size không phải standard, cần JS --}}