Blade : définir une variable et afficher du HTML sans faille

Blade : définir une variable et afficher du HTML sans faille
Réponse rapide

Dans une vue Blade, déclarez une variable avec @php $nom = '…'; @endphp, ou passez-la depuis le contrôleur avec view('vue', compact('nom')). Pour l’afficher, {{ $nom }} échappe le HTML et {!! $nom !!} l’insère tel quel. N’utilisez la seconde forme que sur du contenu de confiance : c’est là que se créent les failles XSS.

Deux besoins reviennent sans cesse dans une vue Blade : y déclarer une variable, et décider si son contenu doit être échappé ou rendu tel quel. Le second n’est pas un détail de confort, c’est le point où l’on introduit une faille XSS.

Publié dans le parcours Développement web. Ce guide couvre les deux : faire arriver une variable dans la vue, en déclarer une sur place, et choisir entre {{ }} et {!! !!} en connaissance de cause. Exemples exécutés sur Laravel 13.30.1 avec PHP 8.4.25.

Passer une variable depuis le contrôleur

C’est la voie normale, et celle qu’il faut privilégier : la vue affiche, le contrôleur décide. Le second argument de view() est un tableau associatif dont chaque clé devient une variable.

app/Http/Controllers/DashboardController.php
return view('dashboard', ['name' => 'Gekko']);
resources/views/dashboard.blade.php
<p>Bienvenue {{ $name }} !</p>

Pour afficher une date issue d’un modèle, voyez la gestion des dates avec Carbon.

Pour plusieurs variables déjà présentes dans des variables PHP, compact() évite de répéter les noms :

php
$name    = 'Gekko';
$reseau  = 'gekkode';

return view('dashboard', compact('name', 'reseau'));

with() permet d’en ajouter une au passage, ce qui est pratique quand la valeur se calcule au dernier moment :

php
return view('dashboard', compact('name'))->with('extra', 'valeur ajoutée');

Si une variable peut manquer, donnez-lui une valeur de repli dans la vue plutôt que d’ajouter une condition :

php
{{ $inconnu ?? 'valeur par défaut' }}

Déclarer une variable directement dans la vue

Quand la valeur ne sert qu’à l’affichage, la directive @php permet de la déclarer sur place :

resources/views/dashboard.blade.php
@php
    $nom = 'Gekko';
    $classe = $task->active ? 'is-active' : 'is-done';
@endphp

<p class="{{ $classe }}">Bonjour {{ $nom }}</p>

Les balises PHP classiques fonctionnent aussi, mais @php reste plus lisible et cohérent avec le reste du gabarit.

Deux directives couvrent les cas voisins sans passer par une variable. @class construit un attribut de classe à partir de conditions :

php
<div @class(['actif' => $task->active, 'masque' => $task->hidden])></div>

<!-- rendu quand active vaut true et hidden false -->
<div class="actif"></div>

Et @once garantit qu’un bloc n’est rendu qu’une fois, même si la vue est incluse plusieurs fois dans la page :

php
@once
    <script src="/js/carte.js" defer></script>
@endonce
Où s’arrête le raisonnable

@php convient pour une valeur d’affichage. Dès qu’il s’agit d’une requête en base, d’un calcul métier ou d’une boucle de transformation, le code appartient au contrôleur, à un composant Blade ou à un accesseur du modèle. Une vue qui interroge la base génère des requêtes N+1 invisibles depuis le contrôleur.

Afficher du HTML : {{ }} contre {!! !!}

Blade compile {{ $variable }} en un appel à la fonction e(), qui échappe les caractères spéciaux. C’est visible dans la vue compilée, sous storage/framework/views :

php
<?php echo e($nom); ?>

Conséquence : si la variable contient des balises, elles s’affichent en toutes lettres au lieu d’être interprétées.

php
@php $html = '<strong>gras</strong>'; @endphp

{{ $html }}     {{-- affiche : &lt;strong&gt;gras&lt;/strong&gt; --}}
{!! $html !!}   {{-- affiche : gras, en gras --}}

La syntaxe {!! !!} insère la valeur sans aucune transformation. C’est ce qu’il faut pour afficher un corps d’article rédigé en HTML, et c’est aussi la porte d’entrée d’une injection de script si la valeur vient d’un utilisateur.

La règle à ne pas contourner

N’utilisez {!! !!} que sur du HTML dont vous maîtrisez l’origine, ou qui a été nettoyé avant. Avec la valeur <script>alert(1)</script>, {{ }} affiche le texte tandis que {!! !!} exécute le script dans le navigateur du visiteur. Les deux comportements ont été vérifiés.

Pour du contenu venant d’un formulaire, que vous aurez pris soin de protéger contre les envois automatisés, nettoyez avant d’afficher. Une bibliothèque comme HTML Purifier applique une liste blanche de balises, à défaut, stockez du Markdown et convertissez-le au rendu, ce qui vous laisse le contrôle des balises produites.

Les cas particuliers utiles

Pour passer des données à du JavaScript, @json produit un littéral valide et échappé :

php
<script>
    const config = @json(['id' => $task->id, 'titre' => $task->title]);
</script>

Pour afficher des accolades sans que Blade les interprète, par exemple dans un gabarit destiné à un framework JavaScript, @verbatim neutralise le bloc entier :

php
@verbatim
    <div id="app">{{ message }}</div>
@endverbatim

Pour une seule expression, la faire précéder d’un arobase suffit : @{{ message }}.

N’appelez pas e() dans des accolades doubles

{{ e($valeur) }} échappe deux fois : <b> devient &amp;lt;b&amp;gt; et s’affiche littéralement à l’écran. {{ }} le fait déjà. La fonction e() ne sert qu’en dehors de Blade, ou à l’intérieur d’un {!! !!} sur une portion précise.

Erreurs fréquentes

{!! !!} sur une valeur d’utilisateur La chaîne <script>alert(1)</script> s’exécute réellement dans le navigateur du visiteur. Nettoyez le HTML avant, ou stockez du Markdown.
{{ e($valeur) }} échappe deux fois Les accolades doubles appellent déjà e(). Le résultat affiche les entités à l’écran au lieu du texte.
Une requête en base dans @php La vue déclenche des requêtes que le contrôleur ne voit pas, ce qui produit des N+1 invisibles. Déplacez la logique dans le contrôleur ou un composant.
Oublier le repli sur une variable optionnelle {{ $var ?? 'défaut' }} évite une erreur si le contrôleur ne l’a pas transmise dans tous les cas.

BladeLaravelPHP

Damien Flandrin Développeur web depuis 2010, créateur de Gekkode et d’Email Impact. Chaque article est testé sur un projet réel avant publication. Contact
Newsletter

Les nouveaux tests, tutoriels et projets, par e-mail.

Tests reproductibles, code versionné, résultats datés. Jamais de spam.