Форма має відправляти файли як multipart/form-data:
<form method="POST" action="/profile/avatar" enctype="multipart/form-data">
@csrf
<input type="file" name="avatar">
</form>
Без enctype браузер відправить лише назву файлу.
Отримання файлу:
$file = $request->file('avatar'); // UploadedFile чи null
$request->hasFile('avatar'); // чи є файл у запиті
$file->isValid(); // чи завантажився без помилок
Спершу - валідація:
$validated = $request->validate([
'avatar' => ['required', 'image', 'mimes:jpg,png,webp', 'max:2048'], // max у кілобайтах
'documents.*' => ['file', 'mimes:pdf', 'max:10240'],
]);
Збереження:
$path = $request->file('avatar')->store('avatars', 's3');
// avatars/Xk9...q2.jpg - унікальна випадкова назва
$path = $request->file('avatar')->storeAs('avatars', "{$user->id}.webp", 'public');
store() сам генерує унікальну назву - це правильний варіант за замовчуванням. У базу зберігають шлях, а не сам файл.
Інформація про файл:
| Метод | Що повертає | Чи можна довіряти |
|---|---|---|
getClientOriginalName() |
назва з комп'ютера користувача | ні - лише для відображення |
getClientOriginalExtension() |
розширення з назви | ні |
extension() |
розширення за вмістом (MIME) | так |
getSize() |
розмір у байтах | так |
getMimeType() |
тип за вмістом | так |
Типові помилки:
- зберігати файл під оригінальною назвою - перезапис чужих файлів, обхід шляху,
shell.php; - перевіряти лише розширення з назви файлу;
- забути про ліміти PHP:
upload_max_filesizeіpost_max_sizeуphp.ini(іclient_max_body_sizeу Nginx). Якщо файл більший, запит приходить без файлу і без зрозумілої помилки валідації - виглядає, ніби поле порожнє; - завантажувати користувацькі файли в
public/поруч з кодом.
Множинне завантаження: <input type="file" name="photos[]" multiple> і $request->file('photos') повертає масив.