Blade: definir uma variável e mostrar HTML sem falhas

Blade: definir uma variável e mostrar HTML sem falhas
Resposta rápida

Numa view Blade, declara uma variável com @php $nom = '…'; @endphp, ou passa-a a partir do controlador com view('vue', compact('nom')). Para a mostrar, {{ $nom }} escapa o HTML e {!! $nom !!} insere-o tal como está. Só uses a segunda forma em conteúdo de confiança: é aí que nascem as falhas XSS.

Há duas necessidades que aparecem sempre numa view Blade: declarar lá uma variável e decidir se o seu conteúdo deve ser escapado ou mostrado tal como está. A segunda não é um detalhe de conforto, é o ponto onde se abre uma falha XSS.

Publicado no percurso Desenvolvimento web. Este guia cobre as duas: fazer chegar uma variável à view, declarar uma no próprio sítio e escolher entre {{ }} e {!! !!} com conhecimento de causa. Exemplos executados em Laravel 13.30.1 com PHP 8.4.25.

Passar uma variável a partir do controlador

É a via normal, e a que deves privilegiar: a view mostra, o controlador decide. O segundo argumento de view() é um array associativo em que cada chave se torna uma variável.

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

Para mostrar uma data vinda de um modelo, vê a gestão de datas com o Carbon.

Para várias variáveis já presentes em variáveis PHP, o compact() evita repetir os nomes:

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

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

O with() permite acrescentar uma pelo caminho, o que dá jeito quando o valor só se calcula à última hora:

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

Se uma variável puder faltar, dá-lhe um valor por omissão na view em vez de acrescentares uma condição:

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

Declarar uma variável diretamente na view

Quando o valor só serve para o ecrã, a diretiva @php permite declará-lo no próprio sítio:

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

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

As tags PHP clássicas também funcionam, mas o @php é mais legível e mais coerente com o resto do template.

Duas diretivas cobrem os casos vizinhos sem passar por uma variável. O @class constrói um atributo de classe a partir de condições:

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

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

E o @once garante que um bloco só é renderizado uma vez, mesmo que a view seja incluída várias vezes na página:

php
@once
    <script src="/js/carte.js" defer></script>
@endonce
Onde acaba o razoável

O @php serve para um valor de apresentação. A partir do momento em que se trata de uma consulta à base de dados, de um cálculo de negócio ou de um ciclo de transformação, o código pertence ao controlador, a um componente Blade ou a um acessor do modelo. Uma view que interroga a base gera consultas N+1 invisíveis a partir do controlador.

Mostrar HTML: {{ }} contra {!! !!}

O Blade compila {{ $variable }} numa chamada à função e(), que escapa os caracteres especiais. Isso vê-se na view compilada, em storage/framework/views:

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

Consequência: se a variável contiver tags, elas aparecem por extenso em vez de serem interpretadas.

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

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

A sintaxe {!! !!} insere o valor sem transformação nenhuma. É o que precisas para mostrar o corpo de um artigo escrito em HTML, e é também a porta de entrada de uma injeção de script se o valor vier de um utilizador.

A regra que não se contorna

Só uses {!! !!} em HTML cuja origem controlas, ou que foi limpo antes. Com o valor <script>alert(1)</script>, {{ }} mostra o texto ao passo que {!! !!} executa o script no browser do visitante. Os dois comportamentos foram verificados.

Para conteúdo vindo de um formulário, que terás tido o cuidado de proteger contra os envios automatizados, limpa antes de mostrar. Uma biblioteca como o HTML Purifier aplica uma lista branca de tags, em alternativa, guarda Markdown e converte-o no momento da renderização, o que te deixa o controlo das tags produzidas.

Os casos particulares úteis

Para passar dados para JavaScript, o @json produz um literal válido e escapado:

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

Para mostrar chavetas sem que o Blade as interprete, por exemplo num template destinado a uma framework JavaScript, o @verbatim neutraliza o bloco inteiro:

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

Para uma expressão isolada, basta antecedê-la de uma arroba: @{{ message }}.

Não chames e() dentro de chavetas duplas

{{ e($valeur) }} escapa duas vezes: <b> passa a &amp;lt;b&amp;gt; e aparece literalmente no ecrã. O {{ }} já o faz. A função e() só serve fora do Blade, ou dentro de um {!! !!} numa parte específica.

Erros frequentes

{!! !!} num valor vindo do utilizador A string <script>alert(1)</script> executa-se mesmo no browser do visitante. Limpa o HTML antes, ou guarda Markdown.
{{ e($valeur) }} escapa duas vezes As chavetas duplas já chamam e(). O resultado mostra as entidades no ecrã em vez do texto.
Uma consulta à base dentro de @php A view dispara consultas que o controlador não vê, o que produz N+1 invisíveis. Passa a lógica para o controlador ou para um componente.
Esquecer o valor por omissão numa variável opcional {{ $var ?? 'défaut' }} evita um erro se o controlador não a tiver enviado em todos os casos.

BladeLaravelPHP

Damien Flandrin Programador web desde 2010, criador da Gekkode e do Email Impact. Cada artigo é testado num projeto real antes de ser publicado. Contacto
Newsletter

Os novos testes, tutoriais e projetos, por e-mail.

Testes reproduzíveis, código versionado, resultados datados. Nunca spam.