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

Laravel 13.30: новий метод chunkBy() для колекцій та посилення безпеки Storage::path()

Реліз Laravel 13.30 приніс кілька важливих нововведень: метод chunkBy() для групування сусідніх елементів колекцій, посилення безпеки Storage::path() через нормалізацію шляхів, виведення причини зупинки queue worker у консолі, а також низку інших покращень та виправлень помилок.

Метод chunkBy() для колекцій

Раніше для розбиття колекції на частини за певною ознакою використовувався метод chunkWhile(), де найчастіше доводилося порівнювати поточний елемент з останнім елементом поточного chunk:

$products->chunkWhile(fn ($value, $key, $chunk) => $value->parent == $chunk->last()->parent);

Новий метод chunkBy() спрощує цей паттерн. Він приймає ключ або callback і починає новий chunk щоразу, коли значення змінюється:

$products->chunkBy('parent');
collect([1, 1, 2, 2, 1, 1])->chunkBy(fn ($value) => $value);
// [[1, 1], [2, 2], [1, 1]]

Ключ обробляється через data_get(), тому працює dot-нотація (наприклад, chunkBy('address.city')), а оригінальні ключі зберігаються всередині кожного chunk. Метод доступний як для звичайних, так і для lazy колекцій.

Посилення безпеки Storage::path()

Виявлено серйозну вразливість: усі методи файлової системи, крім одного, проходили через Flysystem драйвер, який нормалізує шлях і викидає PathTraversalDetected при спробі вийти за межі кореневої директорії диска. Метод Storage::path() пропускав цей крок:

Storage::get('../../../.env');  // відхилено
Storage::path('../../../.env'); // повертав шлях за межами диска

На стандартному local диску path() повертав нативний шлях до .env додатка, тоді як get(), delete() та readStream() відхиляли той самий аргумент. Це створювало проблему безпеки, особливо коли шлях надходив від користувача:

response()->download(Storage::path($request->query('path')));

Тепер path() пропускає аргумент через WhitespacePathNormalizer - той самий нормалізатор, що використовується для всіх інших викликів. Відносні сегменти розв'язуються так, як їх розв'язує драйвер, а все, що виходить за межі кореня, викидає PathTraversalDetected. Код, що покладався на прийняття .. сегментів методом path(), тепер викидатиме виключення.

Виведення причини зупинки queue worker

Раніше worker, що завершував роботу, не залишав жодних слідів у консолі про причину виходу. Подія WorkerStopping містила WorkerStopReason, але для його читання потрібно було реєструвати listener, що вимагало багато налаштувань для питання, яке зазвичай виникає при перегляді терміналу чи логів.

Тепер queue:work виводить причину як останній рядок:

2026-09-01 13:20:40 Worker STOPPED Memory limit exceeded

З прапорцем --json інформація виводиться як структурований запис поряд із виводом для кожного job:

{"level":"warning","status":"stopped","reason":"memory","exit_code":12,"jobs_processed":2,"memory":1.2,"timestamp":"2026-09-01T13:20:40.118273+00:00"}

Enum WorkerStopReason отримав метод description() для людиночитаних рядків, що охоплює дев'ять сценаріїв виходу: перервано, втрачено з'єднання, перевищено максимум jobs, перевищено ліміт пам'яті, перевищено максимальний час роботи, черга порожня, черга порожня протягом налаштованого часу, отримано сигнал перезапуску та час виконання job вичерпано. При використанні --quiet або --silent нічого не виводиться.

Відключення vendor та стандартних dev команд

DevCommands реєструє все, про що знає: стандартні команди фреймворку (serve, queue:listen, pail та Vite скрипт), будь-що з пакетів у vendor та команди додатка. Для звуження цього списку потрібно було вказувати всі потрібні команди через only() або небажані через except(). Перший підхід ламався при додаванні черги, другий - коли залежність починала реєструвати щось нове.

Два нові методи фільтрують за походженням команди:

use Illuminate\Foundation\DevCommands;
DevCommands::withoutVendorCommands();  // прибрати все з vendor/
DevCommands::withoutDefaultCommands(); // прибрати стандартні команди фреймворку

Обидва методи є opt-in і залишають команди додатка недоторканими. DevCommands уже відстежував походження кожної команди як пріоритет (default, vendor або userland) для вирішення конфліктів імен; ці методи фільтрують за тим самим значенням.

Нативні DSN рядки підключення SQL Server

Парсер database URL у Laravel припускав URL. Нативний рядок підключення PDO_SQLSRV не є URL:

sqlsrv:Server=127.0.0.1,1433;Database=example;Encrypt=true;TrustServerCertificate=true

parse_url() читав все це як шлях, Laravel видаляв перший символ, і назва бази повертались як erver=127.0.0.1,1433. Результатом було підключення з пошкодженою конфігурацією.

Тепер нативні sqlsrv: DSN виявляються перед парсингом URL і передаються спеціалізованому парсеру, який витягує хост, порт, базу даних та підтримувані опції PDO_SQLSRV (Encrypt, TrustServerCertificate, MultiSubnetFailover, ApplicationIntent, LoginTimeout тощо), відображаючи їх на ключі конфігурації Laravel. Значення, що містять крапки з комою, закриваючі дужки або пробіли, екрануються при відновленні рядка підключення. Власна конвенція Laravel sqlsrv://user:pass@host:port/database продовжує працювати через існуючий URL парсер.

Отримання однієї Artisan команди

Artisan команди розв'язуються ліниво, але не було способу отримати одну за іменем без втрати цієї переваги. Artisan::all() конструює всі зареєстровані команди для побудови масиву:

// Конструює всі команди
$command = Artisan::all()['app:my-command'] ?? null;
// Конструює лише MyCommand, якщо вона зареєстрована
$command = Artisan::commandNamed('app:my-command');

Метод commandNamed() повертає екземпляр команди або null.

Підсумки для Cloud Queue

Методи totalPendingSize(), totalDelayedSize() та totalReservedSize(), додані в 13.27, повертають 0 на SQS, оскільки SQS не може перелічити черги, які використовує підключення. Laravel Cloud queue може це робити: він уже знає, якими чергами управляє, тому три методи тепер реалізовані там шляхом підсумовування через managedQueues():

use Illuminate\Support\Facades\Cloud;
Cloud::queue()->totalReservedSize();

Інші виправлення та покращення

  • route:cache завантажував другий, тимчасовий додаток для збору чистої копії маршрутів, і bootstrapping переспрямовував глобальний facade application на той контейнер без відновлення. Під php artisan optimize це призводило до LogicException: Route is not bound. Тепер команда відновлює facade application одразу після bootstrap.

  • Request::clamp() повертав 500 для введення, яке не міг обмежити. Нечислові значення тепер проходять до значення за замовчуванням, яке потім обмежується min та max.

  • db:seed --database=mysql перемикає стандартне підключення і повертає його після завершення seeder. Виключення пропускало відновлення. Тепер перемикання обгорнуте в try/finally.

  • setVisibility() на read-through диску торкався лише primary. Тепер розв'язується через readerFor(), як getVisibility(), mimeType() та fileSize().

  • Queue::createPayloadUsing() проходив через QueueManager::__call(), що викликало помилку при реєстрації callback у service provider. Метод тепер визначений безпосередньо на manager.

  • Tooltips на сторінці виключень рендеряться з allowHTML: false за замовчуванням. Власний syntax-highlighted tooltip фреймворку вмикає HTML через окремий атрибут.

  • JSON:API ресурси відстежують відносини, запитані відносно кожного включеного ресурсу, тому вкладені include шляхи розв'язуються на правильному рівні.

  • spl_object_id() замінює spl_object_hash() у контейнері, Eloquent builder, global scopes та Onceable, портовано з 14.x для очищення deprecation warnings.

  • Handler::contextForException() публічно експонує контекст логування виключення, а BladeMapper::findCompiledView() та detectLineNumber() стали публічними.

  • Cloud events transport повертає boolean з emit() та emitMany(), отримав $socketFactory хук для тестування та реєструється під час bootstrap exception-handler.

  • Виправлення квадратичної експансії wildcard правил у ValidationRuleParser::explodeWildcardRules() портовано до 12.x.

1

Читати в документації

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Читайте також

Laravel AI SDK на практиці
Новини 09 жовтня 2026

Laravel AI SDK на практиці: агент, що стоїть за There There

Фрік Ван дер Гертен розповідає, як у Spatie побудували AI-шар хелпдеска There There на Laravel AI SDK: клас агента, інструменти з типізованою JSON-схемою та делегування роботи звичайним domain-діям.

9
CSRF і завантаження
Новини 09 жовтня 2026

Порада з безпеки: як завантаження файлів може обійти захист від CSRF

Стівен Ріс-Картер пояснює, чому файли користувачів варто віддавати з окремого домену: HTML і JS у межах основного застосунку дають доступ до cookie та CSRF-токенів.

18

Вакансії за темою

Wooden Sword
12 днів тому

Senior PHP Developer (Game Backend)

Розробник backend для мобільної RPG з високим навантаженням. Основний стек: PHP Laravel API та TypeScript Nakama Game Server. Відповідальність за повний цикл розробки функцій — від логіки до тестування, code review, оптимізації та документації. Вимоги: 5+ років backend-досвіду, бездоганне знання Laravel/PHP, сильні навички TypeScript, PostgreSQL та асинхронного програмування.

Key2Law
25 днів тому

Full Stack Developer (Laravel)

Full Stack розробник на Laravel для розробки та підтримки веб-додатків. Відповідальний за реалізацію backend (REST APIs, бізнес-логіка, оптимізація БД) і frontend (Blade, Tailwind, Alpine/Livewire/Vue), тестування, деплой та моніторинг. Вимоги: PHP 8.1+, Laravel 10+, знання Eloquent, Queue, Redis, MySQL, JavaScript ES6+, PHPUnit/Pest, Docker, Git, основи AWS. Бажано досвід з Fintech, криптовалютами, high-availability системами.

Пакети за темою

Laravel Medialibrary

spatie/laravel-medialibrary

Пакет для асоціювання файлів з Eloquent-моделями. Надає зручний інтерфейс для управління медіа-файлами, пов'язаними з вашими моделями бази даних.

6,164 11.23.9 13 8

Laravel Backup

spatie/laravel-backup

Пакет для створення резервних копій вашого Laravel-додатку.

6,023 10.3.3 13 11