Skip to content

Instantly share code, notes, and snippets.

@crynobone
Last active June 10, 2022 11:46
Show Gist options
  • Save crynobone/c5f89034d58598d6c60730e97af60333 to your computer and use it in GitHub Desktop.
Save crynobone/c5f89034d58598d6c60730e97af60333 to your computer and use it in GitHub Desktop.
Using Minio for Laravel Vapor.
FILESYSTEM_DRIVER=minio
FILESYSTEM_CLOUD=minio
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=local
AWS_ENDPOINT=http://127.0.0.1:9000
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->app->singleton(
\Laravel\Vapor\Contracts\SignedStorageUrlController::class,
\App\Http\Controllers\SignedStorageUrlController::class
);
Gate::define('uploadFiles', function ($user) {
return true;
});
}
}
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application. Just store away!
|
*/
'default' => env('FILESYSTEM_DRIVER', 'local'),
/*
|--------------------------------------------------------------------------
| Default Cloud Filesystem Disk
|--------------------------------------------------------------------------
|
| Many applications store files both locally and in the cloud. For this
| reason, you may specify a default "cloud" driver here. This driver
| will be bound as the Cloud disk implementation in the container.
|
*/
'cloud' => env('FILESYSTEM_CLOUD', 's3'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have
| been setup for each driver as an example of the required options.
|
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
'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'),
],
'minio' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'endpoint' => env('AWS_ENDPOINT'),
'url' => env('AWS_URL'),
'use_path_style_endpoint' => true,
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
<?php
namespace App\Http\Controllers;
use Aws\S3\S3Client;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Laravel\Vapor\Contracts\SignedStorageUrlController as SignedStorageUrlControllerContract;
class SignedStorageUrlController extends \Illuminate\Routing\Controller implements SignedStorageUrlControllerContract
{
/**
* Create a new signed URL.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
Gate::authorize('uploadFiles', [
$request->user(),
$bucket = $request->input('bucket') ?: config('filesystems.disks.minio.bucket'),
]);
$client = $this->storageClient();
$uuid = (string) Str::uuid();
$signedRequest = $client->createPresignedRequest(
$this->createCommand($request, $client, $bucket, $key = ('tmp/'.$uuid)),
'+10 minutes'
);
return response()->json([
'uuid' => $uuid,
'bucket' => $bucket,
'key' => $key,
'url' => (string) $signedRequest->getUri(),
'headers' => $this->headers($request, $signedRequest),
], 201);
}
/**
* Create a command for the PUT operation.
*
* @param \Illuminate\Http\Request $request
* @param \Aws\S3\S3Client $client
* @param string $bucket
* @param string $key
* @return \Aws\Command
*/
protected function createCommand(Request $request, S3Client $client, $bucket, $key)
{
return $client->getCommand('putObject', array_filter([
'Bucket' => $bucket,
'Key' => $key,
]));
}
/**
* Get the headers that should be used when making the signed request.
*
* @param \Illuminate\Http\Request $request
* @param \GuzzleHttp\Psr7\Request
* @return array
*/
protected function headers(Request $request, $signedRequest)
{
return array_merge(
$signedRequest->getHeaders(),
[
'Content-Type' => $request->input('content_type') ?: 'application/octet-stream',
]
);
}
/**
* Get the S3 storage client instance.
*
* @return \Aws\S3\S3Client
*/
protected function storageClient()
{
$config = [
'region' => config('filesystems.disks.minio.region'),
'version' => 'latest',
'use_path_style_endpoint' => true,
'url' => config('filesystems.disks.minio.endpoint'),
'endpoint' => config('filesystems.disks.minio.endpoint'),
'credentials' => [
'key' => config('filesystems.disks.minio.key'),
'secret' => config('filesystems.disks.minio.secret'),
],
];
return S3Client::factory($config);
}
}
@crynobone
Copy link
Author

crynobone commented Oct 29, 2020

It's actually quite simple to setup minio for Laravel Vapor storage when running it locally. But you probably needs to read through Vapor documentation before using this:

  • Setup laravel/vapor-core
  • Setup laravel-vapor npm for file uploading (using under Laravel Nova doesn't require this).
  • Setup Gate policy for uploadFiles based on Vapor documentation (as shown in AppServiceProvider.php sample code).
  • Setup minio, personally I use tightenco/takeout to set minio but it should be rather straightforward using other approach.

Now, what's important is to have an alternative SignedStorageUrlController since minio has minor different compared to how s3 prepares pre-signed request. Finally it's just a matter for overriding the default route and configurations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment