Đây là bài viết Phần 7 nằm trong series: Laravel File Upload
Trong phần trước, mình đã chia sẻ cách upload file lên Amazon S3 hoặc MinIO và chia sẻ file tạm thời bằng Temporary URL – đảm bảo bảo mật và kiểm soát quyền truy cập.
Tuy nhiên, với các file ảnh, hiển thị ảnh gốc (full-size) trong giao diện admin hay danh sách upload là không tối ưu:
- Ảnh có thể quá lớn, làm tăng thời gian tải trang
- Giao diện sẽ bị vỡ bố cục nếu không kiểm soát kích thước
👉 Vì vậy, trong phần này, bạn sẽ học cách tạo thumbnail (ảnh thu nhỏ) ngay sau khi upload ảnh, sử dụng thư viện Intervention Image – giúp hệ thống gọn nhẹ và chuyên nghiệp hơn.
Mục Lục
I. Intervention Image là gì?
Intervention Image là một thư viện PHP phổ biến giúp xử lý ảnh dễ dàng: resize, crop, thêm watermark, và nhiều chức năng khác. Laravel hỗ trợ thư viện này rất tốt thông qua Facade Image
.
Trong bài này, mình sẽ dùng Intervetion Image để tạo ảnh thu nhỏ (thumbnail) – một tính năng thường thấy trong hệ thống quản lý ảnh hoặc file upload.
II. Cài đặt Intervention Image
Mình sẽ sử dụng phiên bản Intervention Image v3 – phiên bản mới nhất.
1. Yêu cầu hệ thống
Yêu cầu hệ thống để sử dụng Intervention Image
- PHP >= 8.1
- Mbstring PHP Extension
- Image Processing PHP Extension
Mặc định khi cài Herd, PHP sẽ là bản mới nhất 8.4, hỗ trợ sẵn Mbstring PHP Extenstion và Image Process PHP Extention (Imagick).
Có thể kiểm tra PHP có Mbstring PHP Extension và Imagick chưa bằng lệnh sau
php -m | grep 'mbstring\|imagick'
Code language: Nginx (nginx)
Nếu thấy trả về kết quả như bên dưới nghĩa là hệ thống đã sẵn sàng để cài đặt Intervetion Image
imagick
mbstring
Code language: Nginx (nginx)
2. Cài đặt Intervention Image
Cài đặt bằng composer
composer require intervention/image
Code language: JavaScript (javascript)
III. Tạo thumbnail khi upload ảnh
1. Cấu hình driver xử lý ảnh
Để có thể sử dụng Intervention Image, trước tiên cần phải import class ImageManager
và chọn driver (Gd hoặc Imagick). Xem chi tiết hướng dẫn: https://image.intervention.io/v3/basics/configuration-drivers
use Intervention\Image\Drivers\Imagick\Driver;
use Intervention\Image\ImageManager;
$manager = new ImageManager(Driver::class);
Code language: PHP (php)
2. Tạo thumbnail khi upload ảnh
Mình bổ sung đoạn code sau vào hàm store
trong UploadController để tạo file thumnail có kích thước 100px x 100px
// Tạo thumbnail bằng Intervention Image
$thumbnail = $manager->read($file->getRealPath())
->resize(100, 100);
// Đường dẫn tương đối của file thumbnail: 'uploads/thumbnail-ten_file_cuoi_cung.jpg'
$thumbnailStoragePath = $directory . '/thumbnail-' . $finalFilename;
// Lưu thumbnail vào disk
Storage::disk($disk)->put($thumbnailStoragePath, $thumbnail->encode());
Code language: PHP (php)
Upload thử 1 file, trên MinIO giờ sẽ tự động có thêm file thumbnail-xxx

3. Hiển thị thumbnail
Để hiển thị thumbnail của file ảnh vừa upload, mình sẽ cập nhật lại $urlFilePath
như sau, thay thế $storedFilePath
(path của file gốc) bằng $thumbnailStoragePath
(path của file thumbnail)
// Trả về Temporary URL của file
$urlFilePath = Storage::disk($disk)->temporaryUrl($thumbnailStoragePath, now()->addMinutes(5));
Code language: PHP (php)
Ảnh thumbnail 100 x 100 px giờ đã hiện ra ở phần thông báo Sucess!

Tuy nhiên, danh sách Previously Uploaded Files vẫn hiển thị ảnh gốc do trong DB chưa có thông tin của các file thumbnail được tạo ra.
IV. Lưu đường dẫn thumbnail vào database
Hiện tại, chúng ta chỉ đang lưu đường dẫn của file gốc (filename
) vào table uploads
. Nếu muốn hiển thị thumbnail dễ dàng, cần phải thêm một cột thumbnail
vào table này.
1. Tạo migration file
php artisan make:migration add_thumbnail_to_uploads_table --table=uploads
Code language: Nginx (nginx)
Chỉnh sửa file migration
public function up(): void
{
Schema::table('uploads', function (Blueprint $table) {
$table->string('thumbnail')->nullable();
});
}
Code language: CSS (css)
Chạy migration để áp dụng những thay đổi cho database
php artisan migrate
Code language: Nginx (nginx)
2. Cập nhật model Upload
Trong app/Models/Upload.php
, thêm thumbnail
vào $fillable
:
protected $fillable = [
'filename',
'original_filename',
'thumbnail',
];
Code language: PHP (php)
3. Lưu thumbnail path vào database
Trong hàm store()
, cập nhật phần tạo bản ghi như sau:
// Tạo bản ghi mới trong table uploads của database
Upload::create([
'filename' => $storedFilePath,
'original_filename' => $originalFilename,
'thumbnail' => $thumbnailStoragePath,'
]);
Code language: PHP (php)
Đồng thời cập nhật lại hàm destroy
để hệ thống xóa luôn file thumbnail mỗi khi bấm nút Delete
if (Storage::disk($disk)->exists($upload->thumbnail)) {
Storage::disk($disk)->delete($upload->thumbnail);
}
Code language: PHP (php)
4. Chỉnh sửa blade để hiển thị ảnh thumbnail
Trong app/Models/Upload.php
, tạo thêm hàm getThumbnailUrlAttribute
để có thể truy xuất URL của thumbnail thông qua thuộc tính thumbnail_url
// Tạo URL tạm thời mới mỗi khi thuộc tính 'thumbnail_url' được truy cập
public function getThumbnailUrlAttribute(): string
{
$disk = 'minio'; // Ensure this matches the disk used for storing thumbnails
if ($this->thumbnail) {
// Generate temporary URL for the thumbnail path
return Storage::disk($disk)->temporaryUrl($this->thumbnail, now()->addMinutes(5));
}
return ''; // Hoặc xử lý một cách thích hợp nếu tên tệp là null
}
Code language: PHP (php)
Cập nhật lại upload.blade.php
để hiển thị file thumbnail
@if (count($uploads) > 0)
<div class="container mx-auto mt-10 p-10 bg-white rounded-lg shadow-md max-w-md">
<h2 class="text-xl font-semibold mb-4 text-gray-700">Previously Uploaded Files:</h2>
@foreach ($uploads as $upload)
<ul>
<li class="flex items-center justify-between mb-4">
<a class="flex items-center gap-4 py-2" href="{{ $upload->url }}" target="_blank">
<img src="{{ $upload->thumbnail_url }}" alt="{{ $upload->original_filename }}" width="50" height="50">
<span class="text-sm text-gray-700 hover:text-blue-600">{{ $upload->original_filename }}</span>
</a>
<form action="{{ route("upload.destroy", $upload->id) }}" method="POST"
style="display:inline;"
onsubmit="return confirm('Are you sure you want to delete this file?');">
@csrf
@method("DELETE")
<button type="submit"
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">Delete</button>
</form>
</li>
</ul>
@endforeach
</div>
@endif
Code language: HTML, XML (xml)
Thử nghiệm lại, tất cả đã hoạt động đúng như mong muốn.
Table uploads giờ đã có thêm 1 cột lưu đường dẫn của thumbnail.

App đã hiển thị thumbnail của các file đã upload. Khi bấm vào thumbnail, nó sẽ hiện ra file ảnh gốc.

V. Tính năng mở rộng của Intervention Image
Ngoài việc tạo thumbnail, thư viện Intervention Image còn cung cấp nhiều tính năng xử lý ảnh khác cực kỳ hữu ích cho ứng dụng thực tế
1. Resize theo kích thước mong muốn
$image->resize(800, 600); // Resize thành 800x600
Code language: PHP (php)
resize()
sẽ bóp ảnh nhỏ lại đúng theo kích thước mong muốn, làm sai tỉ lệ (ratio) của ảnh. Nếu muốn thu nhỏ ảnh mà vẫn giữ nguyên tỉ lệ, cần phải dùng scale()
2. Scale giữ nguyên tỉ lệ ảnh
$image->scale(height: 300) // Giảm kích thước về chiều cao 300px
Code language: PHP (php)
3. Cắt ảnh
$image->crop(300, 300, 10, 10); // Cắt ảnh 300x300 từ góc trái (10,10)
Code language: PHP (php)
4. Thêm hiệu ứng ảnh
Ví dụ: làm mờ (blur), tăng độ sáng (brightness), độ tương phản (contrast)
$image->blur(5); // Làm mờ ảnh
$image->brightness(-20); // Làm ảnh tối hơn
$image->contrast(15); // Tăng tương phản
Code language: PHP (php)
5. Thêm watermark / text
Có thể ghi chữ lên ảnh hoặc chèn watermark:
$image->text('© ThuanBui.me', 10, 10, function ($font) {
$font->size(24);
$font->color('#ffffff');
});
Code language: PHP (php)
VI. Lời kết
Trong phần 7 này, mình đã chia sẻ về cách tạo ảnh thumbnail với Intervention Image
- Sử dụng Intervention Image để tạo ảnh thu nhỏ
- Giảm tải giao diện, tiết kiệm băng thông
- Tuỳ chọn lưu thumbnail vào cơ sở dữ liệu
Việc tạo ảnh thu nhỏ giúp hệ thống của bạn chạy nhanh hơn, gọn nhẹ hơn và tiết kiệm chi phí hơn khi hiển thị ảnh hàng loạt.
🔗 Mã nguồn
Tham khảo mã nguồn sử dụng trong [Phần 7] ở đây: https://github.com/10h30/laravel-file-upload-series/tree/part-7-thumbnail-intervention
🔜 Phần 8: Quản lý ảnh nâng cao với Spatie Media Library
Hiện tại, chúng ta đang xử lý upload, resize, lưu đường dẫn thủ công. Trong phần tiếp theo, mình sẽ chia sẻ về Spatie Media Library – một package mạnh mẽ cho việc quản lý file & ảnh trong Laravel.
- Gắn file trực tiếp vào model
- Tự động tạo và quản lý conversion (thumbnail, preview, v.v)
- Tích hợp sẵn upload, delete, responsive images…
Hẹn gặp lại bạn trong phần 8 sẽ được ra lò vào ngày Thứ Hai, 19/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
- Phần 4: File Upload trong Laravel – [Phần 4] Hiển thị và xoá các file đã upload
- Phần 5: File Upload trong Laravel – [Phần 5] Upload file lên Amazon S3
- Phần 6: File Upload trong Laravel – [Phần 6] Temporary URL và Upload lên MinIO (self-hosted S3)
- Phần 7: File Upload trong Laravel – [Phần 7] Tạo thumbnail (ảnh thu nhỏ) với Intervention Image
- Phần 8: File Upload trong Laravel – [Phần 8] Quản lý ảnh nâng cao với Spatie Media Library
- Phần 9: File Upload trong Laravel – [Phần 9] Nâng cấp giao diện upload file với FilePond
- Phần 10: File Upload trong Laravel – [Phần 10] Upload file tự động với Livewire 3