Laravel 輸出特殊符號全攻略:從 Blade 轉義到 {!! !!} 實作教學

在開發 Laravel 專案的網站後台系統時,我必須預留一些欄位,讓管理者可以自由輸入 HTML 區塊或小段代碼。
這在內容管理系統(CMS)或 Landing Page Builder 類型的專案中非常常見,例如:

  • 在頁面中插入一段追蹤代碼(如 GAMeta Pixel
  • 在特定區塊自訂 HTML 結構
  • 在產品描述區輸入 <ul><li>、或 {} 格式化文字

然而,從資料庫輸出這些內容時,畫面卻完全「不如預期」。
那些 <div>{}<script> 全部被吃掉、變成純文字。

原因其實不難理解:Laravel 的 Blade 模板引擎會自動對所有輸出進行 HTML 轉義(escape),以防範 XSS 攻擊。
但對我們這種必須允許「合法代碼」輸出的後台設計來說,這反而造成了麻煩。

Blade 模板為什麼會吃掉特殊符號?

Laravel 之所以會「吃掉」特殊符號,是因為它的 Blade 模板在輸出變數時,會自動進行 HTML 實體轉義(HTML Escaping)
這是框架內建的防護機制,目的是防止惡意腳本(XSS)被注入到頁面中執行。

🧠 舉例說明:Laravel Blade 的輸出行為

舉例來說,我們在 Blade 中這樣寫:

{{ $message }}
  

$message 的內容是:

<p>Hello <b>World</b></p>
  

瀏覽器最後看到的結果其實是這樣:

<p>Hello <b>World</b></p>
  

也就是說,所有 <>{} 都被轉成了 HTML 實體。
原因在於,Laravel 在底層其實會自動把 {{ }} 轉譯為:

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

e() 這個函式(其實是 Illuminate\Support\helpers.php 中的 e()
會呼叫 PHP 原生的 htmlspecialchars() 來確保輸出的內容是安全的。

✅ 這樣做的好處

  • 避免使用者輸入惡意 <script> 被直接執行。
  • 預設所有輸出都是「安全文字」。

⚠️ 但缺點也很明顯

  • 當我們真的需要輸出 HTML 時(例如管理者填的內容),標籤都會被轉義。
  • 某些動態代碼(像 {!! config('app.name') !!} 或模板占位符)會被錯誤顯示。

✨ 這時候,我們就得出場用到本文的主角:

{!! $message !!}
  

實際解法:{!! $message !!} 與 {{ $message }} 的差異

在 Laravel 的 Blade 模板中,輸出變數主要有兩種寫法:

語法是否自動轉義適合用途
{{ $message }}會自動轉義一般文字輸出,例如文章標題、使用者名稱
{!! $message !!}不會自動轉義已經確認安全的 HTML、後台代碼區塊、信任來源資料

實際範例對比

🧩 實際範例:{!! !!} 與 {{ }} 的差別

假設你的 $message 內容是這樣:

<div class="alert">後台管理員輸入的代碼內容</div>
  

使用一般語法:

{{ $message }}
  

會輸出:

<div class="alert">後台管理員輸入的代碼內容</div>
  

這樣畫面上只會看到純文字。

但若改成:

{!! $message !!}
  

就會正常顯示:

<div class="alert" style="padding:10px;background:#f4f4f4;border-radius:8px;"> 後台管理員輸入的代碼內容 </div>
  

網站後台欄位實務應用

🧰 實務應用場景:後台自訂區塊的輸出

在實務上,我們通常會遇到這樣的情境:

PHP(Controller)

$data['custom_block'] = $request->input('custom_block');
return view('admin.page', $data);
  

HTML(Blade)

<section>
    {!! $custom_block !!}
</section>
  

這樣管理者在後台欄位中填入:

<p style="color:red;">🔥 這是後台自訂段落</p>
  

前端就會原樣呈現,不被 Laravel 轉義。

🧡 重點說明

這個做法最常見於 CMS行銷頁面表單頁自訂代碼區、或是插入 GA / Meta 追蹤碼 的欄位。

對於需要高自由度的管理後台而言,這是幾乎不可或缺的輸出方式

安全考量:何時該用、何時絕對不能用

{!! $message !!} 雖然能解決「HTML 被吃掉」的問題,但它也同時關掉了 Laravel 的安全防護機制。
換句話說,如果輸入內容來自不可信來源(例如前台使用者),這行語法就可能變成攻擊入口。

🚨 什麼情況「不能用」 {!! !!}

  • 前台使用者輸入(留言 / 表單 / 評論)
    絕對不要直接輸出!這類內容最容易被夾帶 <script><iframe> 攻擊;若用 {!! !!},攻擊者可直接在你站上執行惡意程式。
  • 未驗證的 JSON 或外部 API 回傳
    → 有些 API 會回傳含 HTML 的描述欄位,必須先 驗證/轉義或淨化 再輸出,避免把外部 HTML 當成可信內容。
  • 模板可編輯欄位(WYSIWYG 編輯器)
    → CKEditor、TinyMCE、Summernote 等輸出的內容應搭配 HTML Sanitizer(例如 HTMLPurifier 或 DOMPurify)過濾危險標籤/屬性,將允許的標籤白名單化。

建議做法:對「來源不可信」的欄位一律使用 {{ }}(轉義)輸出;若確實需要允許部份 HTML,先在後端執行白名單式的 HTML Sanitization,或由後台流程判定後再以 {!! !!} 有條件放行。

{!! !!} 並不是危險,而是強大。
只要清楚知道「內容來源」與「輸出場景」,再搭配適當防護機制,
它就是讓 Laravel 網頁具備靈活內容控制的關鍵工具。

💬 總之太棒了,真開心能成功輸出代碼!

你在開發 Laravel 後台欄位時,是否也曾遇過 HTML 被吃掉、或 特殊符號亂掉 的情況?

妳有其他問題或經驗想分享嗎?歡迎留言告訴我,
我很樂意一起討論更乾淨、安全又靈活的輸出做法。

我要留言分享經驗

返回頂端