Skip to content
Thuan Bui's Blog
Go back

File Upload trong Laravel - [Phần 3] Upload cùng lúc nhiều file

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.

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>

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.

Terminal window
$request->validate([
'files' => 'required|array', // Tên input 'files[]' trong HTML
'files.*' => 'required|image|mimes:jpg,jpeg,png|max:2048', // max = 2MB mỗi file
]);

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);

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

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ẻ:

🔗 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:

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.

https://thuanbui.me/file-upload-laravel-phan-4/


Share this post on:

Previous Post
Các bước cần làm sau khi clone dự án laravel từ github về máy
Next Post
File Upload trong Laravel - [Phần 2] Kiểm tra và bảo vệ file upload form