Питання на співбесіді: Files
Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів
3 питання
Файл приходить через $request->file(); зберігають через фасад Storage:
$request->validate([
'avatar' => ['required', 'image', 'max:2048'], // до 2 МБ
]);
$path = $request->file('avatar')->store('avatars', 'public');
// або з випадковим унікальним іменем - store() уже так робить
$user->update(['avatar_path' => $path]);
store()повертає шлях для збереження в БД.- Публічний URL -
Storage::url($path)(потребуєphp artisan storage:link). - Валідатори
image,mimes:pdf,docx,max:(в КБ) убезпечують від небажаних файлів.
Laravel абстрагує файлові операції через фасад Storage поверх Flysystem. «Диски» (local, public, s3) налаштовуються в config/filesystems.php.
Storage::disk('s3')->put('reports/q1.pdf', $contents);
$url = Storage::disk('s3')->url('reports/q1.pdf');
$temporary = Storage::disk('s3')->temporaryUrl('reports/q1.pdf', now()->addMinutes(5));
php artisan storage:linkстворює символічне посиланняpublic/storage → storage/app/publicдля публічного доступу.- Зміна сховища (локально ↔ S3) не вимагає переписування коду - лише конфіг.
Файл, покладений у storage/app, недоступний ззовні - це правильно за замовчуванням. Питання в тому, як віддати його тому, кому можна.
Що робити не варто: класти приватні файли в public/ чи публічний бакет і покладатися на те, що адресу ніхто не вгадає. Посилання розходяться, індексуються й лишаються робочими назавжди.
Спосіб 1 - віддати через контролер із перевіркою прав:
public function download(Document $document)
{
$this->authorize('view', $document);
return Storage::disk('private')->download($document->path, $document->name);
}
Кожне звернення проходить авторизацію. Мінус - файл іде крізь PHP, тож на великих файлах воркер зайнятий увесь час передачі.
Спосіб 2 - тимчасове підписане посилання до S3-сумісного сховища:
$url = Storage::disk('s3')->temporaryUrl($document->path, now()->addMinutes(5));
Посилання підписане й саме перестає працювати після строку. Файл віддає сховище напряму, PHP у передачі не бере участі - це те, що потрібно для великих файлів.
Спосіб 3 - підписаний маршрут, коли сховище тимчасових URL не вміє:
URL::temporarySignedRoute('documents.download', now()->addMinutes(5), ['document' => $document->id]);
Middleware signed перевіряє підпис і строк.
Про що часто забувають:
- Спосіб 1 без
authorize()перетворюється на публічний доступ через власний контролер. - Строк життя посилання має бути коротким: доки воно живе, ним може скористатися будь-хто, кому воно потрапило.
- Імʼя файла від користувача не можна підставляти в шлях -
Storage::putFile()генерує безпечне імʼя сам.