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

Upload file HTML5 với AJAX và jQuery

HTML5 File API kết hợp FormData và XMLHttpRequest (hoặc fetch) cho phép upload file qua AJAX mà không cần reload trang. jQuery đơn giản hóa quá trình này.

Cách hiện đại: FormData + fetch (Khuyên dùng, không cần jQuery)

<input type="file" id="fileInput" multiple>
<button onclick="uploadFiles()">Upload</button>
<div id="progress"></div>

<script>
async function uploadFiles() {
  var input = document.getElementById('fileInput');
  var files = input.files;
  
  if (!files.length) return alert('Chọn file trước!');
  
  var formData = new FormData();
  for (var i = 0; i < files.length; i++) {
    formData.append('files[]', files[i]); // Key 'files[]' cho PHP nhận mảng
  }
  
  try {
    var response = await fetch('/upload.php', {
      method: 'POST',
      body: formData
      // Không set Content-Type - browser tự set multipart/form-data với boundary
    });
    
    var result = await response.json();
    console.log('Kết quả:', result);
    alert('Upload thành công!');
  } catch (err) {
    console.error('Lỗi upload:', err);
    alert('Upload thất bại!');
  }
}
</script>

Cách dùng jQuery AJAX (Legacy)

$('#fileInput').on('change', function() {
  var formData = new FormData();
  var files = this.files;
  
  for (var i = 0; i < files.length; i++) {
    formData.append('files[]', files[i]);
  }
  
  $.ajax({
    url: '/upload.php',
    type: 'POST',
    data: formData,
    processData: false,  // Quan trọng: không chuyển data thành query string
    contentType: false,  // Quan trọng: để browser tự set Content-Type multipart
    xhr: function() {
      var xhr = new window.XMLHttpRequest();
      // Theo dõi tiến độ upload
      xhr.upload.addEventListener('progress', function(e) {
        if (e.lengthComputable) {
          var percent = Math.round((e.loaded / e.total) * 100);
          $('#progress').text('Đang upload: ' + percent + '%');
        }
      });
      return xhr;
    },
    success: function(response) {
      console.log(response);
      $('#progress').text('Hoàn tất!');
    },
    error: function(xhr, status, error) {
      console.error(error);
      $('#progress').text('Lỗi upload');
    }
  });
});

Server-side (PHP ví dụ)

<?php
// upload.php
$uploadDir = __DIR__ . '/uploads/';
if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);

$results = [];
foreach ($_FILES['files']['tmp_name'] as $key => $tmpName) {
  $name = basename($_FILES['files']['name'][$key]);
  $size = $_FILES['files']['size'][$key];
  $error = $_FILES['files']['error'][$key];
  
  if ($error !== UPLOAD_ERR_OK) {
    $results[] = ['file' => $name, 'error' => 'Upload error: ' . $error];
    continue;
  }
  
  // Validate: kích thước, loại file, v.v.
  if ($size > 10 * 1024 * 1024) { // 10MB
    $results[] = ['file' => $name, 'error' => 'File quá lớn'];
    continue;
  }
  
  $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
  $allowed = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx'];
  if (!in_array($ext, $allowed)) {
    $results[] = ['file' => $name, 'error' => 'Loại file không cho phép'];
    continue;
  }
  
  // Tên file an toàn: timestamp + random
  $newName = time() . '_' . bin2hex(random_bytes(8)) . '.' . $ext;
  $dest = $uploadDir . $newName;
  
  if (move_uploaded_file($tmpName, $dest)) {
    $results[] = ['file' => $name, 'saved_as' => $newName, 'url' => '/uploads/' . $newName];
  } else {
    $results[] = ['file' => $name, 'error' => 'Không thể lưu file'];
  }
}

header('Content-Type: application/json');
echo json_encode(['success' => true, 'files' => $results]);
?>

Đọc file trước khi upload (Preview)

function previewFile(file) {
  if (file.type.startsWith('image/')) {
    var reader = new FileReader();
    reader.onload = function(e) {
      var img = document.createElement('img');
      img.src = e.target.result;
      img.style.maxWidth = '200px';
      document.getElementById('preview').appendChild(img);
    };
    reader.readAsDataURL(file);
  }
}

Lưu ý quan trọng

  • processData: false và contentType: false là bắt buộc khi dùng jQuery + FormData.
  • Luôn validate phía server: loại file, kích thước, tên file, quét virus.
  • Giới hạn upload PHP: upload_max_filesize, post_max_size trong php.ini.
  • CSRF protection cho form upload.