Hướng dẫn upload file to s3 với laravel storage

  • January 7, 2021
  • 3420
Amazon S3 (Simple Storage Service) là một dịch vụ tuyệt vời để lưu trữ tệp tin sử dụng công nghệ điện toán đám mây. Bài viết này, mình xin giới thiệu với các bạn cách sử dụng AWS S3 để lưu trữ file trong các dự án sử dụng Laravel

Cài đặt thư viện

Theo document của laravel thì trước khi sử dụng S3 driver cần cài đặt packge league/flysystem-aws-s3-v3 ~1.0 thông qua composer


composer require league/flysystem-aws-s3-v3

Cấu hình file .env


AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=
AWS_BUCKET=

Sử dụng laravel storage với phiên bản laravel từ 5.7 trở lên

Viết một MediaTrait để xử lý việc upload file lên s3


<?php

namespace App\Traits;

use App\Helpers\Common;
use App\Helpers\Constants;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
use Exception;

trait MediaTrait
{
    /**
     * Upload file role private.
     *
     * @param object $file
     * @param string $path
     * @param boolean $isRename
     *
     * @return boolean|string
     */
    public function uploadImage(object $file, string $path, bool $isRename = true)
    {
        try {
            $fileName = $this->getFileName($file, $isRename);
            $key = $this->getUploadKey($path, $fileName);
            Storage::disk('s3')->put($key, file_get_contents($file));

            return $fileName;
        } catch (Exception $e) {
            Log::error('[ERROR_S3_UPLOAD_IMAGE] =>' . $e->getMessage());

            return false;
        }
    }

    /**
     * Get file name.
     *
     * @param object $file
     * @param boolean $isRename
     *
     * @return string
     */
    public function getFileName(object $file, bool $isRename = true): string
    {
        $fileName = $file->getClientOriginalName();
        // Check file upload by blob
        if ($fileName === Constants::FILE_BLOB) {
            return Common::encryptFileName(
                Common::generateUuid(),
                Constants::DEFAULT_EXT_FILE_BLOB
            );
        }
        if ($isRename) {
            $fileName = Common::encryptFileName(
                Common::generateUuid(),
                $file->getClientOriginalExtension()
            );
        }

        return $fileName;
    }

    /**
     * Gennerate presigned url has expried time.
     *
     * @param string $name
     * @param string $path
     *
     * @return null|string
     */
    public function getUrl(string $name, string $path)
    {
        try {
            return Storage::disk('s3')->temporaryUrl(
                $this->getUploadKey($path, $name),
                Carbon::now()->addMinutes(config('filesystems.disks.s3.time_presigned_url'))
            );
        } catch (Exception $e) {
            Log::error('ERROR_S3_GET_URL:' . $e->getMessage());

            return null;
        }
    }

    /**
     * Delete image.
     *
     * @param string $name
     * @param string $path
     *
     * @return boolean
     */
    public function deleteImage(string $name, string $path): bool
    {
        try {
            $key = $this->getUploadKey($path, $name);

            return Storage::disk('s3')->delete($key);
        } catch (Exception $e) {
            Log::error('[ERROR_S3_DELETE_IMAGE] =>' . $e->getMessage());

            return false;
        }
    }

    /**
     * Get upload key to s3.
     *
     * @param string $path path.
     * @param string $name name.
     *
     * @return string
     */
    public function getUploadKey(string $path, string $name): string
    {
        return sprintf('%s/%s', $path, $name);
    }

    /**
     * Create s3 pre-signed url.
     *
     * @param string $name
     * @param string $path
     * @return null|string
     */
    public function getPutObjectUrl(string $name, string $path): string
    {
        $filePath = $this->getUploadKey($path, $name);
        $adapter = Storage::disk('s3')->getAdapter();
        $client = $adapter->getClient();
        $bucket = $adapter->getBucket();
        $cmd = $client->getCommand('PutObject', [
            'Bucket' => $bucket,
            'Key' => $adapter->getPathPrefix() . $filePath
        ]);
        $request = $client->createPresignedRequest($cmd, '+5 minutes');

        return (string)$request->getUri();
    }
}

khi dùng để upload file ở contrller chỉ việc user MediaTrait vào là có thể dùng được ngay, không phải viết lại constuctor như cách 2 sử dụng ở các phiên bản cũ.

Chú ý nếu đùng minio thì cần thêm config trong file config/filesystems.php 


use_path_style_endpoint => true

Hướng dẫn test config s3 laravel

Sử dụng tinker để test thử xem có upload được file lên s3 hay không


// truy cập vào tinker
php artisan tinker

// Use storage
use Illuminate\Support\Facades\Storage;

// Upload file to s3
Storage::disk('s3')->put($s3Path, $content);
vd: Storage::disk('s3')->put('test.txt', 'hello');

// Get all file trên s3
Storage::disk('s3')->allFiles();

// Tạo 1 url tạm để download, xem file từ s3
Storage::disk('s3')->temporaryUrl($s3Path, now()->addMinutes(20));

Nếu bạn sử dụng phiên bản laravel cũ nhỏ hơn 5.7 thì đọc bài viết link bên dưới này nhé

Hướng dẫn lưu trữ file trên S3 với laravel