PHP
laravel

【Laravel】Bladeで改行コードのみエスケープさせない


検証バージョン

Laravel:バージョン5.6、5.7です。

5.5以下は試していないので不明です。


TL;DR

HtmlStringインスタンス{{}}のエスケープ対象とならないので、

下記のようなヘルパを作成すれば改行コードのみ適用されます。


app/Helpers/helper.php

use Illuminate\Support\HtmlString;

if ( ! function_exists('unEscapedLine')) {
function unEscapedLine(string $string): HtmlString
{
return new HtmlString(nl2br(e($string)));
}
}



hoge.blade.php

<!-- // $noteは改行されて出力される -->

<p>{{ unEscapedLine($note) }}</p>


{{~}}内でもエスケープされない仕組み


{{~}} の仕様

LaravelにはCSRF対策にcsrf_token()csrf_field()が用意されています。

ただこの2つに限って、出力結果を見ても、{{ }} で囲まれているのに、出力内容はエスケープされません。

定義箇所を見てみましょう。


vendor/laravel/framework/src/Illuminate/Foundation/helpers.php

function csrf_field()

{
return new HtmlString('<input type="hidden" name="_token" value="'.csrf_token().'">');
}

中身は本来エスケープ対象である、<>等を含んだhiddenタグを生成し、

HtmlStringインスタンスを返しているのが分かります。

このHtmlStringインスタンスが肝です。


e()タグの仕様

マニュアルにも記載のあるように、{{}}で囲むと htmlspecialchars()=e()を通るようになっています。


Tip!! Bladeの{{ }}記法はXSS攻撃を防ぐため、自動的にPHPのhtmlspecialchars関数を通されます。


なのでe()の実装を見てみると、Htmlableインスタンスだった場合、

与えられたHTMLをそのまま返す分岐が設けられています。


vendor/laravel/framework/src/Illuminate/Support/helpers.php

if (! function_exists('e')) {

function e($value, $doubleEncode = true)
{
if ($value instanceof Htmlable) {
return $value->toHtml();
}

return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', $doubleEncode);
}
}



\Illuminate\Support\HtmlString

// 与えられたHTMLをそのまま返すだけ

public function toHtml()
{
return $this->html;
}

つまり{{ }}内でもHtmlStringインスタンスはエスケープ対象にならないような仕様です。

なのでHtmlStringインスタンスを返す、下記のようなヘルパーを実装すれば、

改行コードのみ適用するヘルパーを作成することができます。

// app/Helpers/helper.php

use Illuminate\Support\HtmlString;

if ( ! function_exists('unEscapedLine')) {
function unEscapedLine(string $string): HtmlString
{
return new HtmlString(nl2br(e($string)));
}
}

blade側では以下のように書けばOKです。


hoge.blade.php

<!-- // $noteは改行されて出力される -->

<p>{{ unEscapedLine($note) }}</p>