Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

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().

Докладніше в документації: Тимчасові URL для завантаження

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).

Не забути негативні випадки: завеликий файл, неправильний тип, чужий користувач не може видалити файл. Саме там зазвичай діри.

Докладніше в документації: Тестування