Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Validate kích thước file khi upload bằng JavaScript

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 --}}