Un clic sur « télécharger ». L’utilisateur attend son PDF. Dans la grande majorité des cas, il l’obtient. Dans d’autres, le serveur envoie un fichier qui n’était pas celui prévu — parfois un export voisin, parfois un élément de configuration. Le mécanisme est banal : un paramètre d’URL, et un écran qui fait confiance à la chaîne reçue.
Laravel 13.30, publié le 1er septembre 2026, resserre ce comportement. En maintenance, l’enjeu n’est pas la note de version. C’est le document qui n’aurait jamais dû quitter le serveur. En recette, les noms de fichiers sont sages et le parcours passe. En production, le même écran, sollicité autrement, peut servir autre chose qu’un justificatif.
Ce que l’utilisateur obtient réellement
Lorsqu’on examine ce type d’écran sur une application déjà en service, trois issues reviennent.
- Le fichier attendu, celui des tests. Il ne dit rien sur les autres chemins.
- Un autre fichier du projet : export de la veille, tableur, copie de sauvegarde laissée à proximité.
- Un fichier qui n’est pas un document métier : configuration, secrets, tout ce qui ne doit pas transiter par le navigateur.
La vérification est directe. On ouvre l’écran, on substitue au nom du fichier un chemin qui remonte d’un dossier, on télécharge. Si la réponse n’est pas le document métier, le contrôle est insuffisant. S’il est refusé, il reste à confirmer que tous les téléchargements de l’application passent par la même règle, y compris ceux ajoutés plus tard ou hors du parcours de démonstration.
Le parallèle avec le mode debug laissé actif en production est utile : le défaut est invisible tant que personne ne le provoque. On l’avait déjà classé parmi les angles morts décrits dans Laravel en production. La version 13.30 ne crée pas le risque. Elle aligne enfin la construction du chemin disque sur le contrôle déjà appliqué à la lecture du fichier.
Un exemple dans le code
Le motif à rechercher en premier est un téléchargement dont le nom vient de la requête :
return response()->download(
Storage::path($request->query('path'))
);
Le nom est fourni par le client HTTP. Le serveur le convertit en chemin. Avant 13.30, l’API de lecture pouvait refuser un chemin hors du disque configuré, tandis que path() renvoyait malgré tout une chaîne exploitable par download(). Deux portes, un seul contrôle. Depuis le 1er septembre 2026, les deux refusent. Un code qui s’appuyait sur des segments ../ cessera de fonctionner au déploiement. C’est le comportement attendu. On ne rétablit pas l’ancien contrat en interceptant l’erreur. On cesse de fonder le chemin sur l’URL.
Le téléchargement légitime se reconstruit autrement : identifiant du document en base, contrôle d’appartenance, chemin déterminé côté serveur. Si le métier a besoin d’une arborescence, elle appartient au modèle, pas à la query. En back-end, il s’agit d’un contrat de fichier, pas d’une concaténation de chaînes.
Contrôles avant la mise à jour
On ne déploie pas une version un vendredi au seul motif qu’elle est parue. On parcourt d’abord la liste, le jour même où l’on traite le risque fichier.
- Inventaire des actions « télécharger » et « voir le fichier » : l’origine du nom (URL, champ, archive, identifiant opaque).
- Essai manuel : un chemin qui sort du dossier documents doit échouer, sur le même stockage que la production.
- Voisinage des exports : configuration, clés, copies de sauvegarde. S’ils partagent le disque des PDF, le périmètre du défaut s’élargit.
- Ensuite seulement, la fenêtre de mise à jour, avec une issue prévue si un téléchargement légitime s’appuyait encore sur des
...
Un outil externe qui lisait un chemin calculé par path() peut cesser de fonctionner s’il comptait sortir du disque. On ne revient pas en arrière. On lui fournit un chemin déjà autorisé, après le même contrôle d’appartenance.
Archives et suites
Une archive téléversée pose le même problème sous une autre forme. Les noms qu’elle contient ne sont pas les nôtres. Les recoller tels quels pour un nouveau téléchargement déplace le défaut : plus l’URL, l’archive. On extrait dans un répertoire dédié, on refuse ce qui en sort, on sert un identifiant interne.
Après la mise à jour, un téléchargement légitime peut échouer s’il abusait encore des remontées de dossier. Ce n’est pas une régression à contourner. C’est l’indication que le contrat fichier n’était pas achevé. On corrige l’appelant, on reteste l’écran, on déploie. On ne rouvre pas la porte par un correctif d’urgence.
Ce travail de revue n’a pas vocation à ralentir chaque montée de version. Il évite surtout de découvrir le défaut par un utilisateur, un partenaire ou un audit. Un téléchargement est un point de sortie de données : on le traite avec la même attention qu’une API exposée, y compris lorsqu’il ne sert que des PDF.
Les équipes qui héritent d’un existant n’ont pas toujours la cartographie des écrans de fichiers. Une recherche dans le code sur download et Storage::path ne remplace pas la liste métier (quels documents, pour qui, depuis quel écran), mais elle donne un point de départ mesurable. On complète ensuite par les cas hors cadre : scripts, tâches planifiées qui copient des chemins, outils branchés sur le même disque.
On documente le contrat pour la suite : tout nouveau téléchargement passe par un identifiant interne. Sans cette règle écrite, le prochain écran recréera le même schéma sous un autre nom de paramètre. Le calendrier de la 13.30 (1er septembre 2026) n’impose pas une ruée. Il date le changement de cadre. Les applications qui construisent encore le chemin à partir de l’écran ont un motif pour planifier la revue.
Si vous servez des fichiers depuis une application Laravel, ou si vous reprenez un existant sans avoir ouvert ces écrans, c’est le passage que l’on conduit en maintenance avant le reste. Disponibilité mission dès septembre 2026. Le cadre d’intervention est décrit sur l’expertise Scott-E.
Commentaires 0
Soyez le premier à commenter cet article.
Laisser un commentaire