Đây là bài viết Phần 3 nằm trong series: Laravel File Upload
Trong 2 phần trước, mình đã chia sẻ cách tạo form file upload cơ bản và cách kiểm tra (valdiation) file upload trong Laravel. Tuy nhiên, form upload hiện tại đang bị giới hạn chỉ chọn được 1 file duy nhất.
Bài viết [Phần 3] hôm nay sẽ hướng dẫn cách upload cùng lúc nhiều file cùng cách xác thực và xử lý các file được upload.
Mục Lục
I. Chỉnh sửa lại form upload
Chỉnh sửa lại phần form trong upload.blade.php
, thay đổi các thông số của tag input: name=file
thành name=files[]
, id=file
thành id=files
, bổ sung thêm thông số multiple
. Cập nhật luôn thông số của tag label: for=file
thành for=files
<form action="{{ route("upload.store") }}" method="POST" enctype="multipart/form-data" class="space-y-4">
@csrf
<div>
<label for="files" class="block text-sm font-medium text-gray-700 mb-1">Choose file</label>
<input type="file" name="files[]" id="files" multiple
class="block w-full text-sm text-gray-500
file:mr-4 file:py-2 file:px-4
file:rounded-full file:border-0
file:text-sm file:font-semibold
file:bg-blue-50 file:text-blue-700
hover:file:bg-blue-100" />
</div>
<button type="submit"
class="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Upload
</button>
</form>
Code language: HTML, XML (xml)
II. Cập nhật Validation Rule trong Controller
Cập nhật phần validation trong UploadController.php
cho phù hợp với đối tượng mới files
: là một array (tiếng Việt hình như gọi là mảng?) gồm thông tin của nhiều file khác nhau.
$request->validate([
'files' => 'required|array', // Tên input là 'files[]' trong HTML
'files.*' => 'required|image|mimes:jpg,jpeg,png|max:2048', // max = 2MB mỗi file
]);
Code language: PHP (php)
III. Xử lý file upload trong Controller
Chỉnh sửa lại code trong UploadController để phù hợp với thiết lập mới: upload nhiều file cùng lúc
// Tạo biến mới để lưu đường dẫn và tên file gốc
$storedFilePaths = []; // Array lưu đường dẫn các file đã lưu thành công
$originalFilenames = []; // Array lưu tên gốc của các file
$uploadedFiles = $request->file('files'); // Lấy array các đối tượng file đã upload
$numberOfFiles = count($uploadedFiles); // Đếm số lượng file đã upload
// Lặp qua từng file trong array $uploadedFiles
foreach ($uploadedFiles as $file) {
// Lấy tên file gốc từ client
$originalFilename = $file->getClientOriginalName();
$originalFilenames[] = $originalFilename; // Thêm tên gốc vào array
// Chuẩn bị các phần của tên file
$filenameWithoutExtension = pathinfo($originalFilename, PATHINFO_FILENAME); // Lấy tên file không có phần mở rộng
$extension = $file->getClientOriginalExtension(); // Lấy phần mở rộng
$directory = 'uploads'; // Thư mục lưu file trên disk
$disk = 'public'; // Disk public sẽ sử dụng (được định nghĩa trong config/filesystems.php)
// Xác định tên file duy nhất
$finalFilename = $originalFilename; // Bắt đầu với tên gốc
$counter = 1;
// Kiểm tra xem file đã tồn tại chưa
while (Storage::disk($disk)->exists($directory . '/' . $finalFilename)) {
// Nếu tồn tại, tạo tên mới với hậu tố 1,2,3,...
$finalFilename = $filenameWithoutExtension . '-' . $counter . '.' . $extension;
$counter++;
}
// Lưu file bằng storeAs với tên file mới
$storedFilePath = $file->storeAs($directory, $finalFilename, $disk); // Trả về đường dẫn tương đối: 'uploads/ten_file_cuoi_cung.jpg'
$storedFilePaths[] = $storedFilePath; // Thêm đường dẫn file đã lưu vào array $storedFilePaths
}
// Chuyển hướng về trang trước đó
return back()->with('success', 'You have successfully uploaded ' . $numberOfFiles . ' files')
// Gửi kèm array các đường dẫn file đã lưu vào session flash data với key 'stored_paths'
->with('stored_paths', $storedFilePaths)
// Gửi kèm array các tên file gốc vào session flash data với key 'original_filenames'
->with('original_filenames', $originalFilenames);
Code language: PHP (php)
IV. Hiển thị các files đã upload
Chỉnh sửa lại phần hiển thị file đã upload trong upload.blade.php
@if (session("stored_paths") && is_array(session("stored_paths")))
<div class="mt-4">
<p>Uploaded Files:</p>
{{-- Lặp qua array các đường dẫn file đã lưu. $index là chỉ số, $path là đường dẫn --}}
@foreach (session("stored_paths") as $index => $path)
<div class="border p-4 mt-2">
<p class="text-sm text-gray-600">Original Filename:
{{ session("original_filenames")[$index] }}
</p>
<p class="text-sm text-gray-600">Stored Path: {{ $path }}</p>
<img src="{{ $path }}" alt="Uploaded Image {{ $index + 1 }}"
class="mt-2 rounded max-w-full h-auto border">
</div>
@endforeach
</div>
@endif
Code language: Bash (bash)
Kiểm tra thành quả. Mọi thứ hoạt động đúng như ý muốn 🎉

V. Lời kết
Trong [Phần 3] này, mình đã chia sẻ:
- Cập nhật form upload để có thể upload cùng lúc nhiều file
- Chỉnh sửa lại validation rule khi upload nhiều file
- Cách xử lý file upload khi upload nhiều file
- Hiển thị các files đã upload ra front end.
🔗 Mã nguồn
Tham khảo mã nguồn sử dụng trong [Phần 3] ở đây: https://github.com/10h30/laravel-file-upload-series/tree/part-3-multiple-file-upload
🔜 Phần 4: Hiển thị & xoá file
Sau khi đã hỗ trợ upload nhiều file, bước tiếp theo mình cần làm quản lý các file đã upload:
- Hiển thị danh sách file đã được lưu
- Cho phép xoá file không còn sử dụng
- Lưu thông tin file vào database để dễ tra cứu và mở rộng
Trong [Phần 4], chúng ta sẽ xây dựng chức năng hiển thị và xoá file, đồng thời liên kết việc upload với database bằng một model Upload
.
Hẹn gặp bạn ở [Phần 4] sẽ được ra lò vào tối Chủ nhật – 11/05/2025!
Bạn đang xem loạt bài viết: Laravel File Upload
- Phần 1: File Upload trong Laravel – [Phần 1] Tạo form, xử lý file, lưu trữ file
- Phần 2: File Upload trong Laravel – [Phần 2] Kiểm tra và bảo vệ file upload form
- Phần 3: File Upload trong Laravel – [Phần 3] Upload cùng lúc nhiều file
Nếu bạn cần hỗ trợ kỹ thuật miễn phí, vui lòng gửi câu hỏi trực tiếp ở phần Thảo luận bên dưới, mình sẽ trả lời trong thời gian sớm nhất.
Bạn cần hỗ trợ kỹ thuật chuyên sâu?
Khám phá các gói dịch vụ giúp bạn tối ưu công việc và vận hành hệ thống hiệu quả hơn. Từ chăm sóc website đến hỗ trợ kỹ thuật, mọi thứ đều linh hoạt và phù hợp với nhu cầu của bạn.