Ce qui change vraiment
Tous les appels du système de fichiers passent par le pilote Flysystem, qui
normalise le chemin et lève PathTraversalDetected s'il résout hors de la
racine du disque. Un seul y échappait : Storage::path(), qui remettait la
chaîne telle quelle au PathPrefixer — lequel se contente de concaténer.
Storage::get('../../../.env'); // refusé
Storage::path('../../../.env'); // résolvait hors du disqueSur le disque local par défaut, path() renvoyait donc un chemin natif pointant
sur le .env de l'application, là où get(), delete() et readStream()
refusaient le même argument. Le danger apparaît dès que le chemin vient de
l'extérieur :
response()->download(Storage::path($request->query('path')));En 13.30, path() fait passer son argument par WhitespacePathNormalizer,
le normalisateur que League\Flysystem\Filesystem construit pour tous les
autres appels. Contribution de Kiril Manasijev, PR #61343.
L'effet de bord est réel : le code qui s'appuyait sur path() pour accepter
des segments .. ne recevra plus une chaîne, il recevra une exception. À
vérifier avant de déployer.
chunkBy() sur les collections
chunkWhile() existait déjà, et la comparaison qu'on y écrivait neuf fois sur
dix était toujours la même : l'élément courant contre le dernier du groupe en
cours. chunkBy() est cette comparaison, en méthode.
$products->chunkBy('parent');
collect([1, 1, 2, 2, 1, 1])->chunkBy(fn ($value) => $value);
// [[1, 1], [2, 2], [1, 1]]La clé passe par data_get(), donc la notation par points fonctionne
(chunkBy('address.city')), et les clés d'origine sont préservées dans chaque
groupe. Attention à la nuance : c'est un regroupement d'éléments adjacents,
pas un groupBy() — d'où trois groupes ci-dessus, et non deux. Contribution de
Joseph Silber, PR #61357.
queue:work dit pourquoi il s'arrête
L'événement WorkerStopping portait déjà un WorkerStopReason, mais le lire
imposait d'enregistrer un écouteur — beaucoup de plomberie pour une question
qu'on se pose en regardant un terminal. La raison est maintenant écrite en
dernière ligne :
2026-09-01 13:20:40 Worker STOPPED Memory limit exceededAvec --json, elle sort en enregistrement structuré :
{"level":"warning","status":"stopped","reason":"memory","exit_code":12,"jobs_processed":2,"memory":1.2,"timestamp":"2026-09-01T13:20:40.118273+00:00"}L'énumération WorkerStopReason gagne une méthode description() couvrant neuf
scénarios : interruption, perte de connexion, maximum de jobs atteint, limite
mémoire, durée maximale, file vide, file vide pendant la durée configurée,
signal de redémarrage reçu, job expiré. Rien n'est écrit sous --quiet ni
--silent.
Le reste de la version
DevCommands::withoutVendorCommands()etwithoutDefaultCommands()filtrent les commandesdevpar origine plutôt que par nom — la liste ne casse plus quand une dépendance en enregistre une nouvelle.- Chaînes de connexion
sqlsrv:natives pour SQL Server. Artisan::commandNamed()résout une commande sans construire les autres.- Files cloud :
totalPendingSize(),totalDelayedSize(),totalReservedSize(). route:cachene laisse plus les façades pointer sur une application jetable.
À retenir
- Avant de monter en 13.30, chercher les appels à
Storage::path()qui reçoivent des segments relatifs. chunkBy()remplace lechunkWhile()à callback de comparaison, sur les collections comme sur les lazy collections.- Un worker qui disparaît laisse désormais une trace lisible dans la sortie.
Source : Laravel News