Завантаження публікації
ОГОЛОШЕННЯ

Upload pipeline у Laravel: Storage, валідація типів/розмірів і безпечні імена файлів

Практичний стандарт для завантажень: як приймати файли без дірок у безпеці, як зберігати їх через Storage, як правильно обмежувати MIME/розмір, як генерувати безпечні назви і як не допустити виконання “підсунутого” файлу на сервері.


Максим Третяк
Максим Третяк
Газета Дейком | 03.01.2026, 12:00 GMT+3; 05:00 GMT-4

Завантаження файлів — одна з найризикованіших частин веб-проєктів. Тут найчастіше трапляються інциденти: підміна типу файлу, завантаження “виконуваного” скрипта, переповнення диска великими файлами, колізії назв, витік приватних медіа, або ситуація “в адмінці працює, а на фронті ламається”. Тому upload pipeline має бути стандартизований: є одна точка, де приймаємо файл, одна точка, де валідуюємо, одна точка, де зберігаємо, і одна точка, де видаємо URL.

Перший принцип: файл ніколи не зберігається “як є” і “під тим ім’ям, яке дав користувач”. Оригінальне ім’я може містити небезпечні символи, пробіли, кирилицю, дуже довгі рядки, або взагалі бути спробою path traversal. Навіть якщо Laravel це частково екранує, вам не треба ризикувати. Ви або генеруєте власну назву, або зберігаєте оригінальне ім’я тільки як метадані в базі, але не використовуєте його як шлях на диску.

Другий принцип: валідуюємо не “розширення”, а тип контенту та правила. Користувач може назвати файл image.jpg, а всередині буде що завгодно. Тому валідація має включати контроль MIME (на рівні фреймворка) і, для чутливих сценаріїв, додаткову перевірку реального вмісту (наприклад, через Image бібліотеку для картинок, щоб переконатися, що це справді зображення). На практиці мінімум: mimes/mimetypes + max. Якщо ви приймаєте лише зображення — краще використовувати правило image плюс конкретизацію форматів.

Третій принцип: обмежуйте розміри жорстко. Розмір — це не лише “економія диска”. Це захист від DoS через завантаження величезних файлів, від переповнення storage і від деградації бекенду. Валідація по max — обов’язкова. Далі, якщо ви робите ресайз/транскодинг — ці процеси теж мають ліміти і не повинні запускатися на файлах, які не проходять обмеження.

Четвертий принцип: Storage і диски. У Laravel правильна практика — зберігати файли через Storage на певний “disk”, а не через ручний move() у випадкові папки. Це дає вам контроль: локальний диск, S3, приватний диск, симлінк storage:link, різні базові шляхи і єдина точка для генерації URL. Для публічних медіа використовується public disk (що мапиться на storage/app/public і роздається через public/storage). Для приватних — окремий disk без прямого доступу з веба, і видача йде через контролер (signed URL або streaming).

П’ятий принцип: “публічне” і “приватне” — різні сценарії. Якщо файл можна показувати всім (наприклад, обкладинка новини) — його можна зберігати на public disk. Якщо файл має бачити лише адмін/оплачений користувач (документи, інвойси, вихідні медіа) — зберігайте приватно і не робіть прямого URL на файл. Дуже типова помилка — класти все в public, бо “так простіше”. Це майже гарантований витік у майбутньому.

Тепер pipeline по кроках, як це повинно виглядати в коді.

Починаєте з FormRequest. Там ви описуєте правила: чи файл обов’язковий, які типи дозволені, який max. Наприклад для зображень: required|image|mimes:jpg,jpeg,png,webp|max:4096 (max у кілобайтах). Для відео: mimetypes:video/mp4,video/quicktime|max:512000 і так далі, але з відео ліміти обговорюються окремо, бо там потрібні черги і фонова обробка.

Далі у сервісі (а не в контролері) ви берете файл як об’єкт і робите з ним одну операцію: “зберегти”. Тут формується безпечна назва і шлях. Найкращий стандарт: UUID + правильне розширення. Наприклад: 2025/12/.jpg. Чому з датами в директоріях — щоб не накопичувати мільйони файлів в одній папці і щоб було простіше робити архівацію/прибирання. Чому UUID — щоб не було колізій і щоб неможливо було вгадати імена приватних файлів.

Безпечне розширення. Ви не берете розширення з імені користувача “як є”. Ви або берете його з визначеного MIME ($file->extension() після перевірки), або явно мапите допустимі формати. Для зображень можна навіть перекодовувати все в один формат (наприклад, webp) — це додатковий захист і контроль. Але перекодування — це окремий крок, часто через чергу, щоб не блокувати HTTP.

Після збереження ви записуєте в базу метадані: disk, path, original_name (якщо треба), size, mime, width/height (для зображень), user_id (хто завантажив), прив’язка до сутності (news_id або polymorphic). Чому це важливо: файл — це не просто шлях. Його треба вміти знайти, почистити при видаленні запису, перекинути на інший disk, перевірити доступи.

Далі ви повертаєте з сервісу або шлях, або модель Media, і контролер робить редирект з flash. Контролер не повинен вирішувати, як назвати файл і куди покласти. Це частина upload pipeline і повинна бути централізованою, бо інакше ви отримаєте “в одному місці так, в іншому — інакше”, і через місяць storage стане смітником.

Окремо про безпечні імена та шляхи. Головне — ніяких “../”, ніяких пробілів і спецсимволів, ніяких дуже довгих імен, ніяких нестандартних розширень. Якщо ви генеруєте UUID-ім’я, ви автоматично прибираєте 99% проблем. Оригінальне ім’я, якщо воно потрібно, зберігається лише як текст у БД і показується в UI, але не використовується як шлях.

Ще один рівень безпеки — захист від виконання файлів. Важливе правило: ніколи не дозволяйте завантажувати .php, .phtml, .phar та інші виконувані типи, і не зберігайте upload-директорії так, щоб веб-сервер виконував у них скрипти. У Laravel стандартна схема з storage/app і public/storage знижує ризик, але якщо ви кладете файли прямо в public/ без контролю — це потенційна катастрофа. Для критичних систем краще, щоб “не ваші” файли не були виконуваними в принципі, і щоб сервер був налаштований забороняти виконання в директоріях upload.

Тепер про користувацький досвід та підтримку. Після завантаження вам треба показати людині зрозумілий результат: що завантажено, який файл, який розмір, і якщо помилка — чому саме (тип не дозволений або перевищено розмір). Це робиться через валідаційні повідомлення в FormRequest і нормальне відображення errors у Blade. Без цього користувачі починають “тикати” і вантажити все підряд.

Для масштабування важливо закласти ще дві речі. Перша — обробку важких файлів у черзі: ресайз зображень, генерація прев’ю, транскодинг відео. Друга — lifecycle: що робити з файлами, коли запис видалили або замінили файл. Потрібен стандарт: при заміні — видаляти старий файл (або відправляти в архів), при видаленні сутності — чистити прив’язані файли, але обережно, якщо файл може бути спільним для кількох записів.

Висновок: upload pipeline — це місце, де “простота” швидко перетворюється на діри. Правильний стандарт такий: валідація типу і розміру в FormRequest, збереження через Storage на правильний disk, генерація безпечного імені (UUID), чітке розділення public/private, і запис метаданих у БД. Якщо ви зробите це зараз, у майбутньому ви зможете безболісно додавати ресайз, S3, приватні файли та кешування, не розгрібаючи хаос у файловій системі.


Максим Третяк — Кореспондент, який спеціалізується на суспільно важливих темах, пише про політику, фінансові ринки та економіку. Він проживає та працює в Україні.

Цей матеріал є частиною розгорнутої теми: Web-програмування, яка охоплює численні цікаві аспекти цієї події. Газета «Дейком» ретельно відстежує події, проводячи перевірку джерел та інформації, щоб забезпечити нашим читачам найбільш точне та актуальне інформування.

Цей матеріал опубліковано 03.01.2026 року о 12:00 GMT+3 Київ; 05:00 GMT-4 Вашингтон, розділ: Освіта, із заголовком: "Upload pipeline у Laravel: Storage, валідація типів/розмірів і безпечні імена файлів". Якщо в публікації з'являться зміни, про це буде зазначено та описано у кінці публікації.

Читайте щоденну газету та загальну стрічку новин газети Дейком, яка поєднує багато цікавого в понад 40 розділах з усіх куточків світу.


Save
ОГОЛОШЕННЯ

Новини, які можуть Вас зацікавити:

Штатні та позаштатні журналісти газети «Дейком» щодня готують сотні публікацій, щоб читачі отримували найоперативнішу, перевірену й глибоку інформацію. Ми працюємо для тих, хто хоче розуміти суть подій, бачити широку картину та бути на крок попереду.

Останні новини

Вибір редакції