Загрузка и хранение файлов
Аватары, фотографии товаров, вложения — почти в каждом приложении пользователи загружают файлы. Laravel берёт на себя проверку, выбор имени и сохранение, а код не зависит от того, лежат файлы на сервере или в облачном хранилище.
Форма
Форме нужен атрибут enctype:
<form method="POST" action="/avatar" enctype="multipart/form-data">
@csrf
<input type="file" name="avatar">
<button type="submit">Загрузить</button>
</form>Проверка и сохранение
Файл проверяют теми же правилами валидации, что и остальные поля. Метод store() сам придумывает случайное имя и возвращает путь:
public function update(Request $request)
{
$request->validate([
'avatar' => 'required|image|max:2048',
]);
$path = $request->file('avatar')->store('avatars', 'public');
$request->user()->update(['avatar' => $path]);
return back()->with('status', 'Аватар обновлён');
}Правило image проверяет содержимое файла, max:2048 — размер в килобайтах. В базе сохраняют только путь, например avatars/Hk3f9a.jpg.
Диски
Диск — это место хранения. Они описаны в config/filesystems.php:
| Диск | Где лежат файлы | Доступ из браузера |
|---|---|---|
local | storage/app/private | Нет |
public | storage/app/public | Да, после создания ссылки |
s3 | Облачное хранилище | По настройкам хранилища |
Чтобы файлы диска public открывались в браузере, один раз создают ссылку из папки public:
php artisan storage:linkСсылка на файл
Фасад Storage возвращает адрес файла:
use Illuminate\Support\Facades\Storage;
$url = Storage::disk('public')->url($user->avatar);<img src="{{ Storage::disk('public')->url($user->avatar) }}" alt="Аватар">Другие действия
Storage::disk('public')->put('notes/today.txt', 'Текст заметки');
$text = Storage::disk('public')->get('notes/today.txt');
$exists = Storage::disk('public')->exists('notes/today.txt');
Storage::disk('public')->delete($user->avatar);Скачивание закрытого файла
Файлы, которые нельзя отдавать всем подряд, хранят на диске local и отдают через контроллер после проверки прав:
public function download(Invoice $invoice)
{
abort_unless($invoice->user_id === auth()->id(), 403);
return Storage::download($invoice->file_path);
}Частая ошибка
При замене файла старый остаётся на диске, и хранилище постепенно заполняется мусором. Удаляйте прежний файл перед сохранением нового:
if ($user->avatar) {
Storage::disk('public')->delete($user->avatar);
}
$user->update(['avatar' => $request->file('avatar')->store('avatars', 'public')]);