Middle: питання на співбесіді з теми «Файли»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
3 питання
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) не вимагає переписування коду - лише конфіг.
Через тимчасовий підписаний URL для завантаження: сервер лише видає дозвіл, а файл іде з браузера чи мобільного застосунку напряму в сховище.
public function store(Request $request): JsonResponse
{
$path = 'uploads/'.$request->user()->id.'/'.Str::uuid().'.mp4';
['url' => $url, 'headers' => $headers] = Storage::disk('s3')->temporaryUploadUrl(
$path, now()->plus(minutes: 10),
);
return response()->json(compact('url', 'headers', 'path'));
}
Клієнт робить PUT на url з headers, потім повідомляє застосунку path.
Чому це краще за завантаження через PHP:
- великий файл не займає воркер PHP і не впирається в
upload_max_filesize,post_max_sizeі таймаути; - немає подвійного трафіку «клієнт → сервер → S3».
Що контролює сервер:
- шлях генерує сам (а не приймає від клієнта) - користувач пише лише у свою теку;
- короткий термін дії URL;
- після завантаження - перевірка: файл існує, розмір і тип відповідають очікуванням (
Storage::size(),mimeType()), лише тоді запис у базі; - незавершені завантаження прибирає правило життєвого циклу бакета.
Підтримують драйвери s3 і local. Для перегляду приватних файлів - temporaryUrl().
Storage::fake() підміняє диск тимчасовою текою, а UploadedFile::fake() створює файл-заглушку.
it('stores the avatar', function () {
Storage::fake('public');
$user = User::factory()->create();
$this->actingAs($user)
->post('/profile/avatar', ['avatar' => UploadedFile::fake()->image('me.jpg', 400, 400)])
->assertRedirect();
Storage::disk('public')->assertExists($user->fresh()->avatar_path);
});
it('rejects a file that is too big', function () {
Storage::fake('public');
$this->actingAs(User::factory()->create())
->post('/profile/avatar', ['avatar' => UploadedFile::fake()->create('big.jpg', 5000)])
->assertInvalid(['avatar']);
Storage::disk('public')->assertDirectoryEmpty('avatars');
});
Що варто знати:
fake()->image()створює справжнє зображення (потрібен GD) - пройдеimageіdimensions;fake()->create('doc.pdf', 1024, 'application/pdf')- файл заданого розміру в кілобайтах і MIME-типу, без реального вмісту;- перевірки:
assertExists,assertMissing,assertCount,assertDirectoryEmpty; - шлях краще брати з моделі, а не вгадувати: збережене ім'я генерується (
hashName).
Не забути негативні випадки: завеликий файл, неправильний тип, чужий користувач не може видалити файл. Саме там зазвичай діри.