Junior: питання на співбесіді з теми «Запити й відповіді»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
3 питання
Через об'єкт Request, який Laravel автоматично впроваджує в метод контролера:
public function store(Request $request)
{
$name = $request->input('name', 'default');
$email = $request->string('email'); // типізовані хелпери
$active = $request->boolean('active');
$all = $request->only(['name', 'email']);
}
Динамічний доступ $request->name теж працює, але його уникають через можливі колізії з параметрами маршруту. Для файлів - $request->file('avatar'), для перевірки наявності - $request->has('key').
Дані запиту приходять з різних місць, і Laravel дає окремі методи для кожного.
input() - тіло запиту й рядок запиту разом:
$name = $request->input('name');
$city = $request->input('address.city'); // вкладене поле через крапку
$tags = $request->input('tags.*.name'); // усі значення з масиву
$page = $request->input('page', 1); // значення за замовчуванням
Для форм (application/x-www-form-urlencoded, multipart/form-data) і JSON-тіла (application/json) працює однаково. Якщо поле є і в тілі, і в рядку запиту, перевагу має тіло.
query() - лише рядок запиту (?sort=name&page=2):
$sort = $request->query('sort', 'created_at');
Корисно, коли важливо, звідки прийшло значення: наприклад, параметр фільтра не повинен підмінятися полем у тілі POST-запиту.
json() - лише JSON-тіло:
$items = $request->json('items');
Параметри маршруту - частина URL, а не вхідні дані запиту:
Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) { ... });
$request->route('post'); // з будь-якого місця, наприклад у middleware
Їх отримують аргументами контролера (з прив'язкою до моделі), а не через input().
Інші джерела:
| Метод | Що повертає |
|---|---|
$request->all() |
усі вхідні дані разом з файлами |
$request->only(['name', 'email']) |
лише вказані поля |
$request->except(['password']) |
усе, крім указаних |
$request->header('X-Request-Id') |
заголовок |
$request->cookie('theme') |
cookie (розшифрований) |
$request->file('avatar') |
завантажений файл |
Важливе правило: для збереження даних використовуйте не all() чи input(), а $request->validated() з Form Request - лише ті поля, які пройшли валідацію. Інакше клієнт може надіслати поля, яких ви не очікували.
Форма має відправляти файли як 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') повертає масив.