LoginSignup
0
0

Laravel 10でS3互換Oracle Cloud Storageを使う方法

Posted at

S3互換のクラウドストレージは多くありますが、Laravel 10でOracleのS3互換ストレージを利用する記事が少なく、また参考にした記事の多くはLaravelのバージョンが古かったため、情報共有と備忘録を兼ねてこの記事を書きました

前提

Laravelプロジェクトを既に立ち上げているものとします

Oracle Cloud Infrastructure側の設定

Oracle Cloudは他クラウドに比べると情報が少ないので、クラウド操作部分も少し丁寧に書きます

エンドポイントはhttps://{バケット名前空間}.compat.objectstorage.{リージョン}.oraclecloud.comになるため、まずはそれぞれの情報を取得します

リージョンの確認

ここから自分の利用リージョンに対応する文字列を探してください

例えば日本リージョンは大阪がap-osaka-1、東京がap-tokyo-1です
後でこの値はAWS_DEFAULT_REGIONとして利用します

バケットの作成、バケット名前空間の確認

左上のハンバーガーメニューから、ストレージ>バケットを選択

コンパートメントを指定して、バケット名をつけて作成

作成したバケットの詳細のネームスペースがバケット名前空間になるので、覚えておきましょう
後でこの値はAWS_ENDPOINTの一部として利用します

また、付けたバケット名はAWS_BUCKETとして後で利用します

image.png

権限を分けたアカウントを作成(Optional)

権限のスコープは必要最小にすべきです、必ず設定しましょう

ただし、テストなので管理者アカウントのままでも構わないという人は、#顧客認証キーの発行 まで読み飛ばしてください
また本筋と関係ないのでそこまで詳しく紹介しません

作成方法

グループを作成

アイデンティティとセキュリティ>ドメイン>グループ
仮の名前としてLaravel managerとして作成します

ユーザを追加

アイデンティティとセキュリティ>ドメイン>ユーザー
作成時、先に作ったグループに所属させます

ポリシを追加

アイデンティティとセキュリティ>ポリシー

ポリシーでは一行ごとに以下のような構文で権限を割り当てます
Allow group [group_name] to [verb] [resource-type] in compartment [compartment_name] where [condition]

バケットの読み取りとオブジェクト作成と取得の権限をLaravel managerに与える例

Allow group 'Default'/'Laravel manager' to read buckets in tenancy
Allow group 'Default'/'Laravel manager' to manage objects in tenancy where any {request.permission='OBJECT_CREATE', request.permission='OBJECT_INSPECT'}

適当に作ったのでテナンシに対して有効になっちゃってます
自分に合ったポリシを作成してください

顧客認証キーの発行

ログインしているアカウントで発行する場合

右上のアカウント画像から、

ユーザープロファイル>顧客秘密キー

で秘密キーの生成を行います

作成した別のアカウントで発行する場合

ハンバーガーメニューから、

アイデンティティとセキュリティ>ドメイン>ユーザ>作成したアカウント>顧客秘密キー

で秘密キーの生成を行います
ドメインは多分Defaultになってるはず

顧客秘密キーの生成

アクセスキーシークレットの取得

以前はS3互換APIキーと呼ばれていたようです

適当な識別用の名前を付けて生成すると、アクセスキーのシークレットが表示されます
一度閉じると二度と表示されないので、必ずメモしましょう(画像のトークンは無効化済みです)
この値はAWS_SECRET_ACCESS_KEYとして利用します

image.png

アクセスキーの取得

その後顧客秘密キーの一覧に登録されているので、アクセスキーをコピーします
この値はAWS_ACCESS_KEY_IDとして利用します

image.png

Laravelの設定

S3パッケージをインストール

$ composer require league/flysystem-aws-s3-v3
$ composer install

ファイルの追加

追加・変更するファイル一覧

/
|- app
|  |- Http
|  |  \- Controllers
|  |     \- UploadController.php
|  \- Providers
|     \- OciObjectStorageServiceProvider.php
|- config
|  |- app.php
|  \- filesystems.php
|- routes
|  \- web.php
|- resources
|  \- views
|     \- upload.blade.php
\- .env

.env

コード内容

FILESYSTEM_DISKlocal->ociに変更

AWS_*には上で設定した情報を追記

.env
FILESYSTEM_DISK=oci
# ...
AWS_ACCESS_KEY_ID="<key-id>"
AWS_SECRET_ACCESS_KEY="<key-secret>"
AWS_DEFAULT_REGION="<cloud-region>"
AWS_BUCKET="<bucket-name>"
AWS_ENDPOINT="https://<bucket-namespace>.compat.objectstorage.${AWS_BUCKET}.oraclecloud.com"
AWS_USE_PATH_STYLE_ENDPOINT=true

app/Providers/OciObjectStorageServiceProvider.php

OCI登録するサービスプロバイダを作成

コード内容
app/Providers/OciObjectStorageServiceProvider.php
<?php

namespace App\Providers;

use Aws\S3\S3Client;
use Illuminate\Support\ServiceProvider;
use Illuminate\Filesystem\AwsS3V3Adapter;
use Illuminate\Support\Arr;
use Storage;

use League\Flysystem\AwsS3V3\AwsS3V3Adapter as S3Adapter;
use \League\Flysystem\Filesystem as Flysystem;

class OciObjectStorageServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap services.
     */

    public function boot()
        {
            if (config('filesystems.default') != 'oci') {
                return;
            }
            Storage::extend('s3', function($app, $config) {

                // illuminateのAwsS3V3AdapterでOCIのbucket名をパスのprefixに使うための設定
                $config['directory_separator'] = '/';
                $config['prefix'] = $config['prefix'] ?? null;
                if($config['use_path_style_endpoint']) {
                    $config['prefix'] = $config['bucket']. $config['prefix'];
                }
                
                $client = new S3Client([
                    'credentials' => [
                        'key'    => $config['key'],
                        'secret' => $config['secret'],
                    ],
                    'region' => $config['region'],
                    'version' => '2006-03-01',
                    'bucket_endpoint' => true,
                    'use_path_style_endpoint' => true,
                    'endpoint' => $config['endpoint'],
                ]);
                
                // S3クライアント
                $s3_adapter = new S3Adapter($client, $config['bucket'], $config['prefix']);

                // \Illuminate\Filesystem\FilesystemManager.php createflysystemのパクリ
                $flysystem_adapter = new Flysystem($s3_adapter, Arr::only($config, [
                    'directory_visibility',
                    'disable_asserts',
                    'temporary_url',
                    'url',
                    'visibility',
                ]));

                // IlluminateのAwsS3V3Adapter
                $adapter = new AwsS3V3Adapter($flysystem_adapter, $s3_adapter, $config, $client);
                
                return $adapter;
            });
        }
}

app\Http\Controllers\UploadController.php

コードはこちらのサイトを参考に一部を変更して使用しています

https://www.geekfeed.co.jp/geekblog/laravel_s3

コード内容
app\Http\Controllers\UploadController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\UploadedFile;
use Storage;

use Illuminate\Support\Facades\Log;
use Illuminate\Http\Request;

class UploadController extends Controller
{
    //
    public function index()
    {
        return view('upload');
    }

    public function store(Request $request){
        // $request->file('file')->store(''); // storage/appに保存
    
        // アップロードされたファイルを変数に格納
        $upload_file = $request->file('file');
 
        // ファイルがアップロードされた場合
        if(!empty($upload_file)) {
 
            // アップロード先S3フォルダ名 
            $dir = 'test';
    
            // バケット内の指定フォルダへアップロード ※putFileはLaravel側でファイル名の一意のIDを自動的に生成してくれます。
            $s3_upload = Storage::disk('s3')->putFile('/'.$dir, $upload_file);
    
            // ※オプション(ファイルダウンロード、削除時に使用するS3でのファイル保存名、アップロード先のパスを取得します。)
            // アップロードファイルurlを取得
            $s3_url = Storage::disk('s3')->url($s3_upload);
            
            // s3_urlからS3でのファイル保存名取得
            $s3_upload_file_name = explode("/", $s3_url)[4];
    
            // アップロード先パスを取得 ※ファイルダウンロード、削除で使用します。
            $s3_path = $dir.'/'.$s3_upload_file_name;

            return $s3_url;
        }

    }
}

config/app.php

作成したサービスプロバイダを登録

コード内容
config/app.php
<?php
return [
    # ...
    'providers' => ServiceProvider::defaultProviders()->merge([
        # ...
        App\Providers\OciObjectStorageServiceProvider::class,
        # ...
    ])->toArray(),
    # ...

config/filesystem.php

ここはデフォルトのままですが、一応

config/filesystem.php
<?php
return [
    # ...
    'disks' => [
        # ...
        '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'),
            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
            'throw' => false,
        ],
    ],
    # ...

resources/views/upload.blade.php

アップロードテスト用のページ

コード内容
resources/views/upload.blade.php
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <form method="POST" action="{{ route('upload') }}" enctype="multipart/form-data">
      {{ csrf_field() }}

      <input type="file" id="file" name="file" class="form-control" />

      <button type="submit">アップロード</button>
    </form>
  </body>
</html>

routes/web.php

コード内容
routes/web.php
# 追記
Route::resource('upload', App\Http\Controllers\UploadController::class)->name('index', 'upload');

これで設定は完了です

テスト

http://localhost/uploadにアクセスしてテストします
簡易アップロードformがあるので適当なファイルを送信します
image.png
送信に成功すると保存先のURLを表示します

image.png
バケットの詳細からアップロードされたのが確認出来たら成功です

image.png

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0