LaravelのファイルストレージでConohaのオブジェクトストレージを使う


Laravelのファイルストレージ、便利ですね。
s3、FTPなど様々なファイルシステムを同じインターフェースで扱うことができます。

元からローカル、Amazon S3rackspaceなどのドライバが使えるようになってますが、
S3は料金体系が難しい、rackspaceはよくわからない、ということで、
今回はConohaのオブジェクトストレージに接続してみました。

作業

ライブラリのインストール

前述のrackspaceが、conohaと同じopenstackという規格でできているので、
conohaでもこのライブラリを使います。
用意されているとはいえライブラリの追加インストールが必要みたいなのでcomposerでインストール。
参考:https://readouble.com/laravel/5.4/ja/filesystem.html#driver-prerequisites

composer require league/flysystem-rackspace

ServiceProviderの登録

そのまま使ってもうまく接続できませんので、認証部分だけオリジナルで作成します。
以下のServiceProviderを新規作成します。

app/Providers/ConohaServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use League\Flysystem\Filesystem;
use League\Flysystem\Rackspace\RackspaceAdapter;
use OpenCloud\OpenStack;

class ConohaServiceProvider extends ServiceProvider
{
    /**
     * サービスの初期処理登録後に実行
     *
     * @return void
     */
    public function boot()
    {
        $filesystem = $this->app->make('filesystem');
        $filesystem->extend('conoha', function($app, $config) {
            $client = new OpenStack($config['auth_url'], [
                'username' => $config['username'],
                'password' => $config['password'],
                'tenantName' => $config['tenant_name'],
            ]);
            $client->authenticate();
            $service = $client->objectStoreService('Object Storage Service', $config['region']);
            $container = $service->getContainer($config['container']);

            return new Filesystem(new RackspaceAdapter($container));
        });
    }

    /**
     * コンテナで結合の登録
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

ServiceProviderを作成したら、config/app.phpに登録します。

config/app.php
   'providers' => [
        // ...

        \App\Providers\ConohaServiceProvider::class, // ←追加
    ],

configの登録

認証情報などをconfig/filesystem.php.envに追加します。

config/filesystem.php
   'disks' => [
        // ...

        'conoha' => [
            'driver'        => 'conoha',
            'auth_url'      => env('OS_AUTH_URL', ''),
            'username'      => env('OS_USERNAME', ''),
            'password'      => env('OS_PASSWORD', ''),
            'tenant_name'   => env('OS_TENANT_NAME', ''),
            'container'     => env('OS_CONTAINER', ''),
            'region'        => env('OS_REGION', ''),
        ],
    ],
.env
OS_AUTH_URL=
OS_USERNAME=
OS_PASSWORD=
OS_TENANT_NAME=
OS_CONTAINER=
OS_REGION=

各設定値の意味は以下のとおりです。
※ConohaのAPIに関しては公式ドキュメントが参考になります。
事前に、cyberduckなりでコンテナを作っておくと良いです。
https://www.conoha.jp/guide/objectstoragecyberduck.php

名前 説明
OS_AUTH_URL Conohaのコントロールパネル→API→エンドポイント→Identity ServiceのURL
OS_USERNAME APIユーザー名
OS_PASSWORD APIユーザーパスワード
OS_TENANT_NAME Conohaのコントロールパネル→API→テナント情報→テナント名
OS_CONTAINER 作成したコンテナ名
OS_REGION リージョン名(エンドポイントの「tyo1」.conoha.ioの部分。東京ならtyo1)

使う

ここまでやれば、他のドライバと同じように使えます。
Laravelのファイルストレージについては公式ドキュメントが参考になります。
https://readouble.com/laravel/5.4/ja/filesystem.html

たとえばPOSTされたファイルをアップロードするなら以下のようになります。

$path = $request->file('avatar')->store('avatars', 'conoha');

ServiceProvider解説

app/Providers/ConohaServiceProvider.php
        $filesystem = $this->app->make('filesystem');
        $filesystem->extend('conoha', function($app, $config) {

filesystemのドライバに新しくconohaを追加します。extendメソッドの第1引数がドライバ名です。
functionの引数$configには、config/filesystem.phpで定義したusernameなどが入ってます。

app/Providers/ConohaServiceProvider.php
            $client = new OpenStack($config['auth_url'], [
                'username' => $config['username'],
                'password' => $config['password'],
                'tenantName' => $config['tenant_name'],
            ]);

OpenCloud\OpenStackのインスタンスを生成します。

認証情報はconfigで設定した値を渡しているだけです。
※rackspaceのドライバではこの部分がrackspace専用の実装になっており、
そのまま使うとconohaの認証と合わずにエラーになってしまってました。

app/Providers/ConohaServiceProvider.php
            $client->authenticate();

認証を行います。
※ここで認証しないと、このあとのobjectStoreServiceのところで、カテゴリが見つからない的なエラーになります。

app/Providers/ConohaServiceProvider.php
            $service = $client->objectStoreService('Object Storage Service', $config['region']);
            $container = $service->getContainer($config['container']);

オブジェクトストレージにアクセスするサービスを取得し、設定ファイルで指定したコンテナの情報を取り出します。

app/Providers/ConohaServiceProvider.php
            return new Filesystem(new RackspaceAdapter($container));

最後に、RackspaceAdapter$containerを渡し、Filesystemを生成して返します。
認証部分以外に関しては、rackspaceがそのまま使えるみたいですね。

(追記)WebMode時のURLを取得したい場合

ConohaのオブジェクトストレージをWebModeに設定しており、そのURLを取得したい場合、
上記の方法だとurl()メソッドが「対応してない」とエラーになってしまうことがわかったので、
対応方法を追記します。

なお、WebModeの詳しい説明はこちらをご参照ください。
https://www.conoha.jp/guide/objectstoragesdk.php

configに設定追加

WebMode時のURLのベースパスを登録します。

.env
OS_WEB_URL=[WebMode時のURLベース]
app/filesystems.php
        'conoha' => [
            // ...
            'web_url'       => env('OS_WEB_URL', ''), // ←追加
            // ...
        ],

ConohaAdapterを新たに作成

rackspaceのアダプタを継承してConoha用のアダプタを登録します。
なお、作成する場所は以下じゃなくても大丈夫だと思います。

app/Services/Filesystem/ConohaAdapter.php
<?php

namespace App\Services\Filesystem;

use League\Flysystem\Rackspace\RackspaceAdapter;

class ConohaAdapter extends RackspaceAdapter
{
    /**
     * WEB公開用のURLを取得
     * @param $path
     * @return string
     */
    public function getUrl($path)
    {
        return config('filesystems.disks.conoha.web_url') . DIRECTORY_SEPARATOR . $path;
    }
}

ConohaServiceProviderでインスタンス化するアダプタをConohaAdapterに変更

app/Providers/ConohaServiceProvider.php
            return new Filesystem(new ConohaAdapter($container));

RackspaceAdapterを継承しているので他の機能はそのまま使えます。


これで、url($path)メソッドでWebMode時のURLが取得できます。