Đây là bài viết Phần 6 nằm trong series: Laravel File Upload

Trong 5 phần đầu tiên của series Laravel File Upload, chúng ta đã lần lượt xây dựng tính năng upload file trong Laravel từ cơ bản đến nâng cao:

  1. Tìm hiểu cách upload file cơ bản
  2. Áp dụng validation và bảo mật
  3. Hỗ trợ upload nhiều file
  4. Lưu thông tin file vào database, hiển thị và xóa file
  5. Upload lên Amazon S3

Trong [Phần 6] này, chúng ta sẽ tìm hiểu thêm về

  • Cách tạo Temporary URL để chia sẻ file an toàn trong thời gian ngắn.
  • Khi nào nên dùng public hay private bucket.
  • Và cách kết nối Laravel với MinIO, một dịch vụ lưu trữ tương thích S3 có thể tự cài đặt trên server riêng.

I. Tạo Temporary URL cho file trên S3

Trong phần trước, mình hướng dẫn cách cấu hình S3 Bucket ở chế độ public và sử dụng hàm getUrlAttribute khai báo trong model Upload.php để truy xuất Public URL của file

 public function getUrlAttribute(): string
    {
        // Đảm bảo 's3' là tên disk chính xác được sử dụng để lưu trữ các file này.
        $disk = 's3';
        if ($this->filename) {
            return Storage::disk($disk)->url($this->filename);
        }
        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)

1. Rủi ro khi dùng Public URL

Tuy nhiên, sử dụng Public URL sẽ gặp một số rủi ro:

  • Ai có link cũng có thể truy cập và tải file.
  • Không thể giới hạn thời gian hoặc số lần truy cập.
  • Không phù hợp với file riêng tư: hồ sơ người dùng, tài liệu cá nhân, video nội bộ,…

Ví dụ thực tế:

Bạn upload một file PDF tài liệu khách hàng lên S3 và lấy link công khai để gửi cho họ. Sau đó:

  • Link bị chia sẻ lại lên mạng hoặc diễn đàn
  • Hoặc tệ hơn, ai đó nhúng (hotlink) file đó vào website riêng của họ (ví dụ ảnh hoặc video)

Kết quả:

  • Website của người khác hiển thị file từ S3 bucket của bạn
  • AWS vẫn tính phí băng thông – bạn phải trả tiền cho người ta xài miễn phí

Điều này không chỉ làm lộ thông tin mà còn khiến bạn tốn chi phí rất cao nếu bị lạm dụng.

2. Temporary URL là giải pháp an toàn & linh hoạt

Để tránh các rủi ro trên, Laravel cho phép tạo Temporary URL (đường dẫn tạm thời) – chỉ hoạt động trong một khoảng thời gian nhất định.

Rất phù hợp cho:

  • Tài liệu nội bộ
  • Link chia sẻ giới hạn thời gian
  • Tải file trong email xác nhận, OTP, hóa đơn,…

3. Cách tạo Temporary URL trong Laravel

Laravel hỗ trợ sẵn method temporaryUrl() nếu bạn dùng S3 (hoặc các dịch vụ tương thích). Mình sẽ cập nhật lại hàm getUrlAttribute trong Model Upload.php như sau

public function getUrlAttribute(): string
    {
        // Đảm bảo 's3' là tên disk chính xác được sử dụng để lưu trữ các file này.
        $disk = 's3';
        if ($this->filename) {
            // Thao tác này tạo ra một URL tạm thời mới mỗi khi thuộc tính 'url' được truy cập.
            // URL sẽ có hiệu lực trong 5 phút kể từ thời điểm nó được tạo.
            return Storage::disk($disk)->temporaryUrl($this->filename, 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)

→ Link chỉ có hiệu lực 5 phút, sau đó sẽ tự động vô hiệu hóa.

Đồng thời, minh sẽ vào Amazon S3, xóa policy của bucket upload để nó về lại chế độ private.

Ngoài ra, cần phải sửa trong file UploadController.php, dòng

            $urlFilePath = Storage::disk($disk)->url($storedFilePath); // Trả về URL public của file
Code language: PHP (php)

thành

            $urlFilePath = Storage::disk($disk)->temporaryUrl($storedFilePath, now()->addMinutes(5)); // Trả về Temporary URL của file
Code language: PHP (php)

Truy cập lại vào http://upload.test/upload, các file ảnh giờ sẽ có URL tương tư như sau

https://laravel-file-upload-series.s3.ap-southeast-1.amazonaws.com/uploads/Coolify%208.png?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2LIPZ55FX65JVYU4%2F20250509%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=20250509T031623Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Signature=a05326647621f098eafd35ee559e12b3102362752b3a0702647b170f8f1e5554Code language: JavaScript (javascript)

Sau 5′, thử truy cập lại vào file ảnh này, sẽ bị báo lỗi: This XML file does not appear to have any style information associated with it. The document tree is shown below do URL đã hết hiệu lực.

II. Khi nào dùng Public hay Private bucket?

Để hiển thị file trong Amazon S3, chúng ta có 2 cách

  • Chỉnh bucket qua chế độ công khai (public) và sử dụng Public URL thông qua Storage::disk($disk)->url($storedFilePath);
  • Chỉnh bucket qua chế độ riêng tư (private) và sử dụng Temporary URL thông qua Storage::disk($disk)->temporaryUrl($storedFilePath, now()->addMinutes(5));

Vây khi nào thì nên để bucket ở chế độ công khai (public), và khi nào thì nên giữ riêng tư (private)?

1. Dùng Public Bucket khi:

  • File mang tính công khai: ảnh bài viết blog, ảnh đại diện comment,…
  • Không cần kiểm soát truy cập
  • Muốn dùng CDN để tối ưu tốc độ

2. Dùng Private Bucket khi:

  • File nhạy cảm hoặc giới hạn người xem
  • Muốn dùng Temporary URL hoặc cơ chế xác thực riêng
  • Cần bảo vệ tài nguyên (tránh hotlink, tránh tốn băng thông)

III. Upload lên MinIO – Dịch vụ lưu trữ tương thích S3

Việc sử dụng Amazon S3 giúp bạn lưu trữ file an toàn và dễ dàng tích hợp vào Laravel. Tuy nhiên, chi phí băng thông (bandwidth) có thể trở thành một vấn đề lớn nếu:

  • Ứng dụng có nhiều lượt tải file
  • File dung lượng lớn như video, PDF, ảnh chất lượng cao
  • Người dùng chia sẻ link ngoài ý muốn (hotlink)

Để kiểm soát chi phí tốt hơn mà vẫn giữ nguyên API tương thích với S3, bạn có thể sử dụng MinIO – một dịch vụ S3 self-hosted, mã nguồn mở, có thể cài đặt ngay trên server hoặc VPS cá nhân.

1. Cài đặt Minio

Tham khảo lại bài viết mình đã chia sẻ trước đây để biết cách cài đặt Minio, tạo Bucket và tạo Access Key

2. Cấu hình thông số trong Laravel

Tạo thêm disk mới trong config/filesystems.php:

'minio' => [
    'driver' => 's3',
    'key' => env('MINIO_KEY'),
    'secret' => env('MINIO_SECRET'),
    'region' => 'us-east-1',
    'bucket' => env('MINIO_BUCKET'),
    'endpoint' => env('MINIO_ENDPOINT'),
    'use_path_style_endpoint' => true,
],Code language: PHP (php)

Bổ sung thông số của MINIO vào .env

MINIO_KEY=VFfxxxxxxxxr9Am
MINIO_SECRET=EEHetgd5xxxxxxxxxxWMr
MINIO_BUCKET=laravel-file-upload
MINIO_ENDPOINT=https://minio.thuanbui.me
MINIO_USE_SSL=trueCode language: JavaScript (javascript)

3. Upload file lên Minio

Trong file Controller UploadController.php và model Upload.php cần thay đổi tất cả các phần khai báo $disk = 's3' thành $disk = 'minio' để hệ thống chuyển sang sử dụng disk minio.

Các file sau khi upload giờ sẽ được lưu trữ trên Minio thay vì Amazon S3.

TemporaryURL vẫn sẽ hoạt động khi lưu trữ file trên Minio storage.

Các tính năng khác như hiển thị danh sách file, xóa file đều hoạt động bình thường. Khi bấm Delete, file sẽ bị xóa khỏi thư mục lưu trữ trên S3.

IV. Lời kết

Trong [Phần 6] này, mình đã chia sẻ thêm một số kiến thức nâng cao liên quan đến S3:

  • Sử dụng Temporary URL giúp chia sẻ file an toàn, giới hạn thời gian
  • Ưu – nhược điểm của public vs private bucket
  • Cách kết nối Laravel với MinIO, để tự host dịch vụ S3 Storage.

Đây là những kiến thức quan trọng trong việc xây dựng hệ thống quản lý file thực tế – cần bảo mật, vừa tiết kiệm chi phí và linh hoạt khi triển khai.

🔗 Mã nguồn

Tham khảo mã nguồn sử dụng trong [Phần 6] ở đây: https://github.com/10h30/laravel-file-upload-series/tree/part-6-s3-temporary-url-minio

🔜 Phần 7: Tạo ảnh thu nhỏ với Intervention Image

Ở phần 7, chúng ta sẽ tìm hiểu tạo thêm thumbnail cho ảnh upload, sử dụng thư viện Intervention Image. Việc tạo thumbnail giúp giảm tải băng thông, tăng tốc độ hiển thị ảnh trong giao diện người dùng như: danh sách file, gallery ảnh, trang quản trị,… đồng thời giữ cho layout gọn gàng và tối ưu hơn.

Hẹn gặp lại ở [Phần 7] sẽ được ra lò vào tối Thứ Bảy – 17/05/2025!

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.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *


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.