Storage S3 trong Laravel

Storage S3 là gì?

Hello, xin chào mọi người. Lâu rồi mới viết bài lại nên còn nhiều bỡ ngỡ, có gì sai sót mong mọi người bỏ qua. Dạo này mình đang tìm hiểu về laravel 1 chút nên hôm nay mình sẽ viết 1 bài nhẹ nhàng về cách sử dụng Storage S3 trong laravel.

Storage S3
Storage S3

1. Storage S3 trong Laravel

Trong Laravel, chắc hẳn ai làm về nó cũng biết thư viện Storage của Laravel hỗ trợ trữ file trên server bằng filesystem hệ thống, SFTP và Amazon S3. Do vậy, chúng ta cũng không nói đâu xa, mà chính là thư viện Storage của Laravel 8.

2. Configuration FileSystem.

Trong /config/filesystems.php, chúng ta có thể nhìn thấy các thiết lập của FileSystem.

  • Tại đây chúng ta có thể thiết lập giá trị default hoặc set từ biến môi trường FILESYSTEM_DRIVER tên loại disk mà chúng ta có thể sử dụng (và đã khai báo ở mục disks.
  • Cũng có thể thiết lập giá trị cho cloud là s3 để sau này có thể sử dụng Storage::disk('cloud') để truy xuất tới S3 (hoặc các Cloud Filesystem Disk khác)
  • Trong mục disks là tất cả các loại driver chúng ta sẽ sử dụng trong project. Tuy nhiên mình sẽ tập trung vào S3 thôi (thực ra trong project mặc định mình tạo thì chỉ có thêm local).
‘s3’ => [
‘driver’ => ‘s3’,
‘key’ => env(‘AWS_ACCESS_KEY_ID’),
‘secret’ => env(‘AWS_SECRET_ACCESS_KEY’),
‘region’ => env(‘AWS_DEFAULT_REGION’),
‘bucket’ => env(‘AWS_BUCKET’),
‘url’ => env(‘AWS_URL’),
‘endpoint’ => env(‘AWS_ENDPOINT’),
‘cache’ => […]
]

Tại đây chúng ta nhìn thấy có 1 số mục chúng ta cần phải khai báo trong env, đó là AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_DEFAULT_REGIONAWS_BUCKET.

Mọi người có thể sử dụng IAM User để test lúc develop dưới local cho trường hợp này. Tuy nhiên mình đang muốn nhấn mạnh 1 chút về môi trường production nên mình sẽ có một khuyến cáo là không nên sử dụng IAM user, mà sử dụng IAM role cho EC2 instances trên hệ thống cloud. Do đó thì chỉ nên khai báo AWS_DEFAULT_REGION và AWS_BUCKET thôi.

Note: Vì phần cache mình chưa sử dụng tới nên tạm thời không nói nhiều về phần này .

3. Tiến hành giao tiếp xử lý với S3.

Để bắt đầu xử lý, chúng ta có thể sử dụng 1 Facade quen thuộc tên gọi là StorageStorage cung cấp rất nhiều những abstract static method giúp chúng ta xử lý dễ dàng các object mà không cần phải quan tâm đến chuyện nó đang lưu trữ tại đâu. Nếu cần lưu trữ cụ thể tại đâu đó, luôn có thể dùng thế này ::disk('s3').

Storage::put(); // Sử dụng FileSystem mặc định
Storage::disk(‘s3’)->put(); // Sử dụng FileSystem s3

Một số method điển hình cho Storage:

$content = Storage::get(‘file.jpg’); // Lấy file về để xử lý.
Storage::disk(‘s3’)->exists(‘file.jpg’); // Kiểm tra file có tồn tại trên disk hay không
Storage::disk(‘s3’)->missing(‘file.jpg’); //Kiểm tra xem file có bị thiếu trên disk hay không (trong trường hợp S3 có auto cycle move nó đi đâu đó rồi).
Storage::download(‘file.jpg’); // Buộc người dùng download file
$url = Storage::url(‘file.jpg’); // Lấy url của 1 file

Tuy nhiên phần này, có lẽ mọi người có thể tra cứu được (hoặc dựa vào tên của nó để có thể làm việc nên mình cũng không nhắc tới nhiều nữa).

Ở đây nói 1 chút về 1 tính năng đặc biệt trong S3 gọi là Presigned URL. Trong Storage S3, có 1 tính năng là 1 file không ở chế độ public, chúng ta có thể public tạm thời trong 1 khoảng thời gian nhất định chẳng hạn 1-5 phút cho người dùng có thể nhìn thấy / download các asset của trang và hạn chế bị đánh cắp asset (người khác mang asset lên site khác). Để làm được điều đó, chúng ta sử dụng như sau:

$url = Storage::temporaryUrl(
$filePath,
now()->addMinutes(5),
);

Như này chúng ta đang hiểu là, cái $url nhận được sẽ có tác dụng trong 5 phút. của $filePath mà chúng ta đã lưu.

Storage S3 1

Để lưu trữ $filePath thì trước đó, chúng ta đã phải put lên server như sau (Lưu ý: cách này không sử dụng Presign URL để phía client đẩy trực tiếp lên Storage. Theo quan điểm cá nhân của mình thì nó hơi rủi ro, do không check gì cả, và có khả năng bị ghi đè file trên Storage mà không biết và hiện cũng chưa biết cách xử lý sao cho đẹp đoạn đó, nên tốt nhất chúng ta làm kiểu cơ bản, đưa lên Server trước rồi đưa lên S3 sau):

$result = Storage::putFileAs(‘image’, $file, Str::uuid(). substr($file->getClientOriginalName(), -100), [
‘Tagging’ => “env=prod&type=img”,
‘ACL’ => ‘private’,
]);
  • Tại tham số đầu tiên, chúng ta có bucket-name.
  • Tại tham số thứ 2, chúng ta có file (đây là biến được lấy ra bằng $request->file())
  • Tại tham số thứ 3, chúng ta có tên file. Để tránh bị trùng tene, chúng ta gắn thêm uuid vào trước. Đồng thời để tránh tên file bị “cắt” trong quá trình lưu vào DB, thì chúng ta có thể cắt trước.
  • Tại mục Tagging, hãy đánh rõ đây là file cho môi trường nào (nếu sử dụng nhiều môi trường cùng 1 bucket) và 1 số tag tùy ý mà sau này có thể tìm lại được.
  • Tại mục ACL, xác định rõ loại quyền có thể truy cập. Tại đây chúng ta đang sử dụng Presign URL nên có thể không cần sử dụng quyền truy cập ACL public hay public-read.

Ok, hôm nay tới đây thôi. Trong Storage còn rất nhiều những hàm được merge với nhau chung tên đối với cả S3 và Local Storage.