Guia de implementação de upload de arquivo no Laravel | Validação, Storage e suporte a S3
Laravel possui recursos abrangentes relacionados a uploads de arquivos, permitindo implementar validação, abstração de armazenamento e integração com S3 com uma API consistente. Este artigo explica sistematicamente desde o uso de <code>Request::file()</code>, regras de validação, armazenamento através da fachada Storage, até a configuração do driver S3 para implementação de upload de arquivos em nível profissional.
Como usar Request::file() e hasFile()
Para receber arquivos enviados no controlador Laravel, use o método <code>$request->file()</code>. Este método retorna uma instância de <code>Illuminate\Http\UploadedFile</code> (que estende a classe <code>UploadedFile</code> do Symfony).
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class FileUploadController extends Controller
{
public function store(Request $request)
{
// ファイルが送信されているか確認
if (!$request->hasFile('avatar')) {
return response()->json(['error' => 'ファイルが選択されていません。'], 422);
}
// UploadedFile インスタンスを取得
$file = $request->file('avatar');
// アップロードが成功しているか確認
if (!$file->isValid()) {
return response()->json(['error' => 'ファイルのアップロードに失敗しました。'], 422);
}
// ファイル情報の取得
$originalName = $file->getClientOriginalName(); // 元のファイル名
$extension = $file->getClientOriginalExtension(); // 元の拡張子
$mimeType = $file->getMimeType(); // サーバー側で判定したMIMEタイプ
$clientMime = $file->getClientMimeType(); // クライアントが申告したMIMEタイプ(信頼しない)
$size = $file->getSize(); // バイト単位のサイズ
$tmpPath = $file->getRealPath(); // 一時ファイルのパス
// 複数ファイルの場合(input[type="file" multiple])
$files = $request->file('documents');
foreach ($files as $uploadedFile) {
// 各ファイルを処理
}
}
}
Validação de arquivo com <code>$request->validate()</code>
Usando os recursos de validação do Laravel, você pode validar declarativamente o tipo MIME do arquivo, tamanho e dimensões de imagem. Quando a validação falha, uma resposta 422 é retornada automaticamente.
public function store(Request $request)
{
$validated = $request->validate([
// 基本的なファイルバリデーション
'avatar' => [
'required',
'file', // ファイルであること
'mimes:jpg,jpeg,png,gif,webp', // 許可するMIMEタイプ(拡張子指定でMIMEを自動判定)
'max:5120', // KB単位のサイズ上限(5120KB = 5MB)
],
// 画像専用のバリデーションルール
'thumbnail' => [
'required',
'image', // 画像ファイルであること(JPEG/PNG/GIF/WebP/SVG)
'mimes:jpg,jpeg,png,webp',
'max:2048', // 2MBまで
'dimensions:min_width=100,min_height=100,max_width=4096,max_height=4096',
],
// PDFのバリデーション
'document' => [
'required',
'file',
'mimes:pdf',
'max:20480', // 20MBまで
],
// 複数ファイル
'attachments' => 'required|array|max:5',
'attachments.*' => 'file|mimes:jpg,jpeg,png,pdf|max:10240',
]);
// バリデーション済みファイルを処理
$file = $request->file('avatar');
// ...
}
| Regras de validação | Descrição | Exemplo |
|---|---|---|
file |
Deve ser um arquivo enviado | 'file' |
image |
Arquivo de imagem (JPEG/PNG/GIF/WebP/SVG) | 'image' |
mimes |
Permitir tipo MIME da extensão especificada | 'mimes:jpg,png,pdf' |
mimetypes |
Especificar tipo MIME diretamente | 'mimetypes:image/jpeg,image/png' |
max |
Limite de tamanho em unidades de KB | 'max:10240'(10MB) |
min |
Tamanho mínimo em unidades de KB | <code>'min:1'</code> (1KB ou mais) |
dimensions |
Número de pixels verticais e horizontais da imagem | 'dimensions:min_width=100' |
Salvamento com Storage::disk()->put() (disco public / s3)
A fachada <code>Storage</code> do Laravel abstrai o sistema de arquivos, permitindo que você manipule discos locais, discos públicos e armazenamentos em nuvem como S3 com a mesma API.
use Illuminate\Support\Facades\Storage;
public function store(Request $request)
{
$request->validate([
'file' => 'required|file|max:10240',
]);
$file = $request->file('file');
// ===== ローカル保存(storage/app/ 以下)=====
// 自動でユニークなファイル名を生成して保存
$path = $file->store('uploads');
// → storage/app/uploads/xxxx.jpg のような形で保存される
// 第2引数でディスクを指定
$path = $file->store('uploads', 'local');
// ファイル名を指定して保存
$filename = uniqid('file_') . '.' . $file->getClientOriginalExtension();
$path = $file->storeAs('uploads', $filename);
// ===== public ディスク(公開アクセス可能)=====
// storage/app/public/ 以下に保存(公開URL: /storage/... でアクセス可能)
$path = $file->store('avatars', 'public');
// または
$path = Storage::disk('public')->put('avatars', $file);
// 保存パスから公開URLを取得
$url = Storage::disk('public')->url($path);
// → /storage/avatars/xxxx.jpg
// ===== Storage ファサードの各種操作 =====
// ファイルの存在確認
if (Storage::exists('uploads/file.jpg')) { ... }
// ファイルの削除
Storage::delete('uploads/file.jpg');
// ファイルの移動
Storage::move('uploads/temp.jpg', 'uploads/final.jpg');
// ファイルの取得
$contents = Storage::get('uploads/file.txt');
// ファイルのURL取得
$url = Storage::url('uploads/file.jpg');
return response()->json(['path' => $path, 'url' => $url]);
}
Explicação de php artisan storage:link
Para expor o diretório <code>storage/app/public</code> através da Web, você precisa criar um link simbólico chamado <code>public/storage</code>. O comando para criar esse link é <code>php artisan storage:link</code>.
# シンボリックリンクを作成
php artisan storage:link
# 出力例:
# The [public/storage] link has been connected to [storage/app/public].
# 作成されたリンクを確認
ls -la public/storage
# lrwxrwxrwx ... public/storage -> /var/www/storage/app/public
# Docker/本番環境での注意点:
# デプロイ時に毎回実行するか、Dockerfile に含める
# RUN php artisan storage:link
Quando o link simbólico é criado, os arquivos salvos em <code>storage/app/public/avatars/photo.jpg</code> podem ser acessados em <code>https://example.com/storage/avatars/photo.jpg</code>.
Configuração do driver S3 (.env)
Para salvar arquivos no AWS S3, o pacote <code>league/flysystem-aws-s3-v3</code> é necessário (pode estar incluído por padrão no Laravel 9 ou posterior).
composer require league/flysystem-aws-s3-v3
# .env の設定
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=my-app-bucket
AWS_USE_PATH_STYLE_ENDPOINT=false
# CloudFront 経由でURLを取得したい場合
AWS_URL=https://d1234abcd.cloudfront.net
// S3 への保存
$path = $file->store('uploads', 's3');
// S3 への保存(アクセス制御を指定)
$path = Storage::disk('s3')->put('uploads/' . $filename, $file, 'public');
// 署名付きURL(一時的なプライベートファイルへのアクセス)
$url = Storage::disk('s3')->temporaryUrl(
$path,
now()->addMinutes(30) // 30分間有効
);
// S3 のURL取得(バケットが public の場合)
$url = Storage::disk('s3')->url($path);
Explicação de config/filesystems.php
A configuração de disco é gerenciada em <code>config/filesystems.php</code>. Também é possível adicionar múltiplos buckets S3 e discos personalizados.
// config/filesystems.php
return [
// デフォルトのファイルシステムディスク
'default' => env('FILESYSTEM_DISK', 'local'),
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'throw' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL') . '/storage',
'visibility' => 'public',
'throw' => false,
],
'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,
],
// カスタムディスク(別のS3バケットなど)
's3-thumbnails' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_THUMBNAILS_BUCKET'),
],
],
// storage:link コマンドで作成するリンクのマッピング
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
Tratamento e segurança de arquivos temporários
Arquivos enviados são armazenados temporariamente em diretórios como <code>/tmp</code>. Após o processamento, são movidos para o local final usando <code>move_uploaded_file()</code> (no caso de PHP) ou métodos <code>store()</code> do Laravel, e os arquivos temporários são automaticamente deletados ao término do script.
- Arquivos salvos no disco <code>public</code> do Storage podem ser acessados pela Web, portanto arquivos confidenciais não devem ser colocados lá
- É seguro gerar um nome de arquivo aleatório usando o método <code>hashName()</code>
- O nome de arquivo original é registrado no banco de dados e separado do nome de salvamento real
- No caso do S3, como é privado por padrão, arquivos que precisam ser públicos devem especificar explicitamente <code>public</code> ou usar URLs assinadas
// セキュアなファイル保存の例
public function store(Request $request)
{
$request->validate([
'document' => 'required|file|mimes:pdf,docx|max:20480',
]);
$file = $request->file('document');
// hashName() でランダムなファイル名を生成(元の拡張子を保持)
$hashedName = $file->hashName(); // 例: 5af75b.pdf
// S3 の private エリアに保存
$path = Storage::disk('s3')->putFileAs(
'documents/' . auth()->id(),
$file,
$hashedName
);
// DBに元のファイル名と保存パスを記録
Document::create([
'user_id' => auth()->id(),
'original_name' => $file->getClientOriginalName(),
'stored_path' => $path,
'mime_type' => $file->getMimeType(),
'size' => $file->getSize(),
]);
return response()->json(['message' => 'アップロード完了']);
}
Arquivo de teste disponível para usar neste artigo (gratuito)
- → <a href="/ja/files/images/" class="text-primary-600 dark:text-primary-400 hover:underline">Lista de imagens de teste</a> — Para teste de validação (mimes/dimensions)
- → <a href="/ja/files/pdf/" class="text-primary-600 dark:text-primary-400 hover:underline">Lista de arquivos de teste PDF</a> — Para validação de upload de PDF
- → <a href="/ja/files/threshold/" class="text-primary-600 dark:text-primary-400 hover:underline">Lista de arquivos de teste de valores limite</a> — Para verificar o limite da regra de validação max
Artigos relacionados
- → <a href="/ja/blog/php-file-upload/" class="text-primary-600 dark:text-primary-400 hover:underline">Como implementar upload de arquivos em PHP | Guia completo de validação, armazenamento e segurança</a>
- → <a href="/ja/blog/s3-upload-limit/" class="text-primary-600 dark:text-primary-400 hover:underline">Resumo dos limites de upload de arquivos do AWS S3 e CloudFront</a>
- → <a href="/ja/blog/file-validation-checklist/" class="text-primary-600 dark:text-primary-400 hover:underline">Lista de verificação de implementação de validação de arquivo para formulários web</a>