TwigのHTMLエスケープとrawフィルタの使い方を完全解説!初心者にもわかるテンプレート表示のコツ
生徒
「SymfonyのTwigテンプレートで、HTMLがそのまま表示されず文字として出ちゃうんですけど、どうしたらいいですか?」
先生
「Twigでは、セキュリティのために自動でHTMLをエスケープして表示しているんですよ。」
生徒
「なるほど…でもHTMLとして表示したいときはどうしたらいいんですか?」
先生
「その場合は|rawというフィルタを使えば、HTMLがそのまま表示されるようになりますよ!」
1. Twigの「自動エスケープ」とは?仕組みをわかりやすく解説
SymfonyなどのPHPフレームワークで使われるテンプレートエンジン「Twig」には、「自動エスケープ(Auto-escaping)」という非常に重要な機能が備わっています。
プログラミング未経験の方には少し難しく聞こえるかもしれませんが、エスケープとは、「HTMLタグとして特別な意味を持つ文字を、ただの文字として表示されるように変換すること」を指します。これにより、意図しないレイアウト崩れや、悪意のあるプログラムの実行を防いでいます。
料理のレシピに「塩を少々」と書く代わりに、間違えて「塩の袋を丸ごと投入せよ」という命令が混ざってしまったとします。エスケープは、この「命令」を無効化し、ただの「文章」として紙に表示させるガードマンのような役割です。
具体的な変換の例
例えば、変数の中に <b>こんにちは</b> というHTML(太字にする命令)が入っていた場合、Twigは裏側で以下のように変換して出力しています。
<(小なり) →<>(大なり) →>
もしエスケープがなければ、ブラウザはこれを「太字にする命令」と受け取りますが、Twigが変換してくれるおかげで、画面上には以下のようにタグそのものが文字として表示されます。
<b>こんにちは</b>
なぜ自動でエスケープされるのか?
これは、「クロスサイトスクリプティング(XSS)」というサイバー攻撃からウェブサイトを守るためです。ユーザーがフォームから入力したデータに、もし勝手に画面を書き換えるような危険なコード(JavaScriptなど)が含まれていても、Twigが自動で無害な文字列に変えてくれるので、安全性が保たれるのです。
初心者のうちは、「HTMLを書いても勝手に文字になっちゃう!」と困ることもあるかもしれませんが、これはTwigがあなたのサイトを全力で守ってくれている証拠なのです。
2. HTMLとして表示したいときは「|raw」
ただし、場合によってはHTMLタグとして表示したいこともあります。たとえば、太字や改行を表示したい場合ですね。そういったときは、Twigの|rawフィルタを使えばOKです。
使い方はとても簡単です。変数の出力に|rawをつけるだけで、その中のHTMLがエスケープされずそのまま出力されます。
{{ message|raw }}
例えば、コントローラから以下のようなHTMLを含んだ文字列を渡したとします。
// コントローラ(PHP)
$message = '<p>ようこそ!</p>';
return $this->render('sample.html.twig', [
'message' => $message
]);
通常はエスケープされて、以下のように文字列のまま表示されます。
<p>ようこそ!</p>
しかし、Twigで|rawをつけて表示すると、次のようにHTMLとして解釈されて表示されます。
ようこそ!
3. |rawを使うときの注意点
|rawは便利ですが、絶対に注意しなければならない点があります。それは、「ユーザーが入力したデータには使わない」ということです。
もし、ユーザーがフォームなどで悪意あるスクリプト(例:<script>悪いコード</script>)を入力してしまった場合、それを|rawで表示してしまうと、クロスサイトスクリプティング(XSS)というセキュリティの脆弱性につながります。
そのため、|rawを使うのは、自分で用意した安全なHTMLだけにしましょう。
4. |rawを使った具体例
ここでは、HTML付きのメッセージを表示する簡単な例を見てみましょう。
// コントローラ(Controller)
$notice = '<p class="text-success">保存が完了しました!</p>';
return $this->render('page.html.twig', [
'notice' => $notice
]);
Twigテンプレートでは次のように|rawを使います。
{{ notice|raw }}
表示結果は以下のようになります。
保存が完了しました!(緑色で表示)
5. TwigとHTMLの関係を理解しよう
HTMLはウェブページを構成するための言語で、TwigテンプレートはそのHTMLをより動的に作るための仕組みです。Twigでは変数を簡単に表示できますが、セキュリティを守るために、表示される内容はHTMLとして解釈されず、文字列として安全に出力されます。
HTMLを意図的に表示したいときだけ、|rawを使い、その他はTwigの自動エスケープに任せるのがベストプラクティスです。
まとめ
ここまで、Symfonyなどのフレームワークで標準採用されているテンプレートエンジン「Twig」における、HTMLエスケープの仕組みとrawフィルタの活用方法について詳しく解説してきました。Web開発において、動的にコンテンツを表示させることは欠かせませんが、そこには常にセキュリティのリスクが隣り合わせであることを忘れてはいけません。
Twigの自動エスケープが私たちを守っている
Twigがデフォルトで有効にしている「自動エスケープ」は、クロスサイトスクリプティング(XSS)などの攻撃からアプリケーションを守るための非常に強力な防壁です。特別な指定をしない限り、すべての変数は安全な形式に変換されて出力されます。例えば、ユーザーがコメント欄にスクリプトを仕込もうとしても、Twigはそれをただの文字列として無害化してくれるのです。
rawフィルタが必要になる具体的なシーン
一方で、CMS(コンテンツ管理システム)からHTMLタグ付きのリッチテキストを出力したい場合や、管理画面で作成した整形済みのHTMLをそのまま反映させたい場合には、この自動エスケープが邪魔になってしまいます。そこで登場するのが |raw フィルタです。このフィルタを適用することで、Twigに対して「この変数は安全だと私が保証するので、そのままHTMLとしてレンダリングしてほしい」と命令することができます。
実装例のおさらい
改めて、PHP側(Controller)とTwig側での記述方法を確認しておきましょう。以下のサンプルコードでは、信頼できるソースから生成されたHTMLメッセージを表示する際の実装を示しています。
// PHP側の実装(Controller)
// 信頼できる内部処理から生成されたHTML文字列
$htmlContent = '<div class="alert alert-info"><strong>お知らせ:</strong>システムメンテナンスを本日22時より実施いたします。</div>';
return $this->render('info/notice.html.twig', [
'maintenance_info' => $htmlContent
]);
この maintenance_info 変数をそのままTwigで表示しようとすると、タグが文字として画面に出てしまいます。そのため、以下のように記述します。
{# Twigテンプレート側の記述 #}
<div class="container">
<h1>インフォメーション</h1>
{# rawフィルタを適用してHTMLとして出力 #}
{{ maintenance_info|raw }}
</div>
このコードの実行結果は、以下のようになります。
インフォメーション
お知らせ:システムメンテナンスを本日22時より実施いたします。(青色の枠線付きで表示)
開発者が守るべきセキュリティの鉄則
プログラミングにおいて「便利さ」と「安全性」はトレードオフの関係になりがちですが、|raw フィルタの使用には慎重さが求められます。以下のポイントを常に意識してください。
- ユーザー投稿データには絶対に使わない: 不特定多数が入力できるフォームからのデータに
|rawを使うのは非常に危険です。 - 信頼できるソースのみに適用: データベースに保存された自社スタッフ作成のデータや、プログラム内部で組み立てたHTMLに限って使用しましょう。
- エスケープの意図を理解する: なぜエスケープが必要なのか、その背景にあるセキュリティ知識を深めることが、一流のエンジニアへの近道です。
テンプレートエンジンの特性を正しく理解することで、安全でかつ表現力の豊かなWebサイトを構築することが可能になります。今回の内容を参考に、適切なエスケープ処理を心がけてみてください。
生徒
「先生、ありがとうございました!|raw フィルタを使うことで、意図した通りのデザインでHTMLを表示させることができました。でも、使いどころを間違えると怖いですね。」
先生
「その通りです。プログラムが自動でやってくれることには、必ず意味があります。Twigがデフォルトでエスケープしてくれるのは、開発者がうっかりミスをしてもユーザーを守れるようにするためなんですよ。」
生徒
「なるほど…。さっき試したんですが、もし |raw を使わずに <br> タグを渡したら、画面にはそのまま <br> って表示されちゃいました。これがエスケープされている証拠なんですね。」
先生
「良い気づきですね!実務では、例えばブログの記事本文のように『どうしてもHTMLが必要な場所』だけを特定して |raw を使います。それ以外の名前やタイトルなどは、常にTwigの保護下に置くのが基本ですよ。」
生徒
「わかりました。あ、もう一つ質問なんですが、PHP側で htmlspecialchars() を使ってからTwigに渡した場合はどうなるんですか?」
先生
「それは二重エスケープになってしまう可能性がありますね。Twigを使うなら、PHP側で加工しすぎず、表示の直前にTwigの機能で制御するのがスマートです。役割分担を意識すると、コードも綺麗になりますよ。」
生徒
「確かにそのほうがControllerのコードもスッキリしますね。これからは、セキュリティに気をつけつつ、必要なときだけ |raw を使うようにします!」
先生
「その意気です。安全なコードを書けるエンジニアは、現場でも非常に信頼されます。この調子で頑張りましょう!」