Created
September 26, 2024 03:06
-
-
Save kohki-shikata/55072289d3c287e872ecaae2868898a6 to your computer and use it in GitHub Desktop.
ファイルの操作を行うLaravelのTrait
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Traits; | |
use Illuminate\Support\Facades\Storage; | |
use Illuminate\Http\UploadedFile; | |
use Illuminate\Support\Str; | |
use Illuminate\Support\Facades\Validator; | |
use Intervention\Image\Facades\Image; // Intervention Imageパッケージを使用 | |
trait FileStorageTrait | |
{ | |
protected $maxFileSize = 4 * 1024 * 1024; // 最大4MB | |
protected $maxFiles = 30; // 最大30件 | |
protected $minImageSize = 200; // 短辺の最小サイズ(200px) | |
/** | |
* アップロードされたファイルを指定のディスクに保存します。 | |
* | |
* @param UploadedFile[] $files | |
* @param string $directory | |
* @return array 保存したファイルのキー | |
*/ | |
public function uploadFiles(array $files, string $directory = ''): array | |
{ | |
// スロットリングの実装 | |
$this->throttleRequests(); | |
// バリデーション | |
$this->validateFiles($files); | |
$savedPaths = []; | |
foreach ($files as $file) { | |
// 画像のサイズを確認 | |
if (!$this->isImageSizeValid($file->getPathname(), $this->minImageSize)) { | |
return ['error' => '画像が小さすぎます。']; | |
} | |
// ファイルの保存 | |
$path = $this->uploadFile($file, $directory); | |
$savedPaths[] = $path; | |
} | |
return $savedPaths; | |
} | |
/** | |
* アップロードされたファイルを指定のディスクに保存します。 | |
* | |
* @param UploadedFile $file | |
* @param string $directory | |
* @return string 保存したファイルのキー | |
*/ | |
public function uploadFile(UploadedFile $file, string $directory = ''): string | |
{ | |
$disk = Storage::disk('s3'); // ここで使用するディスクを指定 | |
$filename = $this->generateUniqueFileName($file); | |
$path = $directory ? "{$directory}/{$filename}" : $filename; | |
$disk->put($path, file_get_contents($file)); | |
return $path; | |
} | |
/** | |
* バリデーション | |
* | |
* @param UploadedFile[] $files | |
* @return void | |
*/ | |
protected function validateFiles(array $files): void | |
{ | |
$validator = Validator::make(['files' => $files], [ | |
'files.*' => 'required|file|mimes:jpeg,png|max:' . ($this->maxFileSize / 1024), // KB単位 | |
]); | |
if ($validator->fails()) { | |
throw new \Exception('バリデーションエラー: ' . json_encode($validator->errors()), 400); | |
} | |
if (count($files) > $this->maxFiles) { | |
throw new \Exception('最大' . $this->maxFiles . '件までのアップロードが可能です。', 400); | |
} | |
} | |
/** | |
* アップロードされた画像のサイズを確認します。 | |
* | |
* @param string $filePath | |
* @param int $minSize | |
* @return bool | |
*/ | |
protected function isImageSizeValid($filePath, $minSize): bool | |
{ | |
$image = Image::make($filePath); | |
return min($image->width(), $image->height()) >= $minSize; | |
} | |
/** | |
* ファイルを指定のキーで取得します。 | |
* | |
* @param string $path | |
* @return string|null ファイルの内容 | |
*/ | |
public function getFile(string $path): ?string | |
{ | |
$disk = Storage::disk('s3'); | |
return $disk->exists($path) ? $disk->get($path) : null; | |
} | |
/** | |
* ファイルを指定のキーで削除します。 | |
* | |
* @param string $path | |
* @return bool 削除に成功したかどうか | |
*/ | |
public function deleteFile(string $path): bool | |
{ | |
$disk = Storage::disk('s3'); | |
return $disk->exists($path) ? $disk->delete($path) : false; | |
} | |
/** | |
* ファイルを指定のキーで更新します。 | |
* | |
* @param UploadedFile $file | |
* @param string $path | |
* @return bool 更新に成功したかどうか | |
*/ | |
public function updateFile(UploadedFile $file, string $path): bool | |
{ | |
return $this->deleteFile($path) && $this->uploadFile($file, dirname($path)); | |
} | |
/** | |
* 一意のファイル名を生成します。 | |
* | |
* @param UploadedFile $file | |
* @return string 一意のファイル名 | |
*/ | |
protected function generateUniqueFileName(UploadedFile $file): string | |
{ | |
return Str::uuid()->toString() . '.' . $file->extension(); | |
} | |
/** | |
* スロットリングの処理を実装 | |
* | |
* @return void | |
*/ | |
protected function throttleRequests(): void | |
{ | |
// スロットリングの具体的な実装を追加 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment