iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
Software Development

一套真實運作中的 Laravel 系統,拆解它的原生機制系列 第 20

Day 20:XML 容錯——抄一篇公開文章的解法,也要懂它在防什麼

  • 分享至 

  • xImage
  •  

前言:防禦手法一定要自己想出來,才算真的懂嗎?

「這段清理非法字元的 regex 看起來很複雜,是自己想出來的嗎?」

今天要看的這段程式碼,作者的答案很誠實:不是。方法上方直接留了一個外部連結,標明這段解法來自一篇公開文章。這篇不是要講「這段 regex 怎麼寫出來的」,而是想談一個更值得記住的態度:不是每個防禦手法都要自己發明,找到權威來源直接用、但要真的懂它在防什麼,這才是負責任的做法。

今日目標

  • 看一個真實案例:外部系統回傳的 XML 資料,可能帶有什麼樣的髒字元
  • 理解為什麼「抄別人的解法」不等於「不負責任」,關鍵在於懂不懂它在防什麼
  • 認識這段清理邏輯實際在防禦什麼層級的問題
  • 建立「引用外部解法時,誠實標註來源」的習慣

本文主體

問題:外部系統回傳的資料,不一定是乾淨的 UTF-8

這個系統要處理外部系統透過 SOAP 回傳的 XML 資料,這些資料裡有時候會帶有不合法的 UTF-8 位元組序列、或者控制字元。如果直接把這些髒資料塞進資料庫、或者拿去做進一步的 XML/JSON 處理,輕則資料顯示亂碼,重則整個解析流程直接拋出例外中斷。

系統裡有一個工具方法,專門處理這個問題:

public static function stripInvalidXmlString(string $string): string
{
    $string = preg_replace_callback(
        '/&#x(\w+);/',
        static fn ($m) => mb_convert_encoding($m[0], 'UTF-8', 'HTML-ENTITIES'),
        $string
    );

    return self::sanitizeXML($string);
}

裡面呼叫的 sanitizeXML() 私有方法,內容是一段密度很高的 regex 處理邏輯——逐段檢查並移除不合法的 UTF-8 位元組樣式,再逐字元檢查是不是落在 XML 規範允許的合法字元範圍內,不合法的直接濾掉。

誠實標註來源,而不是假裝自己想出來的

這段方法上方的註解,直接寫了一個外部連結,標明這是抄一篇公開文章的解法,不是團隊自己研究出來的成果。這是這篇想強調的核心態度:面對「清理不合法 UTF-8/XML 字元」這種已經有大量前人研究過、有標準答案可以參考的問題,不需要每個團隊都重新發明一次輪子。找到一個講得清楚、有權威來源的解法,直接引用,比自己憑空重新設計一套(很可能還漏掉某些邊角情況)更可靠。

但「抄」跟「照抄卻完全不懂」是兩回事。這段程式碼即使是引用來的,使用它的人也應該理解:它在防的是「不合法的 UTF-8 位元組」跟「XML 規範不允許的控制字元」這兩類問題,理解了這一層,才知道這段防禦函式的適用範圍在哪——它處理的是字元編碼層級的髒資料,不是處理「資料內容邏輯上合不合理」這種業務層級的驗證。如果誤以為這段函式順便做了業務驗證,之後遇到業務層級的髒資料反而漏掉檢查,就是「抄了但沒真的懂」的後果。

這段函式在真實流程裡怎麼被用到

處理外部系統同步資料的 Job,在寫入站內資料表前,會呼叫這個工具方法清理過一次欄位內容,才把資料寫進資料庫。這不是憑空舉的例子——外部系統回傳的資料,格式跟編碼確實不是完全可控的,這段防禦邏輯是真的會在生產環境被觸發、真的會被用到的程式碼,不是寫好放著沒人用的裝飾。

對照:自己重新發明,或誠實引用有來源的解法

自己憑感覺寫一段簡化版的清理邏輯

// 自己土法煉鋼寫一個簡單的過濾,可能漏掉某些邊角的不合法位元組樣式
$string = preg_replace('/[^\x20-\x7E]/', '', $string);
// 這種寫法會把所有非 ASCII 字元都濾掉,中文內容也會被誤殺

引用有來源的完整解法,並理解它在防什麼

/**
 * @link https://example.com/php-skip-invalid-characters-xml-string/
 */
private static function sanitizeXML($string)
{
    // 完整處理 UTF-8 不合法位元組樣式 + XML 規範合法字元範圍
    // 理解這段在防「編碼層級」的問題,不是「業務層級」的驗證
}

今日思考題

你的專案裡有沒有一段程式碼是「抄」來的解法?回想一下,你是真的理解它在防什麼、適用範圍在哪,還是只是「用起來沒出過問題所以繼續用」?如果現在要你跟同事解釋這段程式碼在做什麼,你講得清楚嗎?

今日重點回顧

  • 外部系統回傳的 XML 資料,可能帶有不合法的 UTF-8 位元組或控制字元,需要在寫入前清理
  • 這段清理邏輯誠實標註了外部來源,不是團隊自己憑空研究出來的成果
  • 「抄」跟「照抄卻不懂」是兩回事,理解一段引用來的程式碼在防什麼,才能判斷它的適用範圍
  • 面對已經有標準答案的問題,找到權威來源直接用,通常比自己重新發明更可靠

明日預告

明天要看另一個跟外部系統對接的技巧組合:一支只有 38 行的 Crawler,怎麼用 Generator 分頁、搭配 PSR-18 discovery 跟 retry plugin,做出一支技巧密度很高的爬取邏輯。


上一篇
Day 19:SOAP 逾時防護——從「先能動」到「補上超時控制」的真實演進
系列文
一套真實運作中的 Laravel 系統,拆解它的原生機制20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言