Laravel收到false字串卻當成true:用Request boolean讀表單開關

設定表單送來 enabled=false,後端卻把開關打開。若程式用了 (bool)$request->input('enabled'),先看輸入是否為字串。PHP的布林轉型不會把英文單字false理解為否;非空字串false反而會轉成true。

Laravel的Request提供 boolean()來讀取常見開關值。這能讓字串false與on等表單值按明確方式轉換,但它不是驗證器:不認得的值也可能得到false。先分清「把輸入轉成布林」與「拒絕不符合契約的輸入」,再接回設定保存。

先比較型別,不只看文字

下面兩個值在人眼看來都像false,型別卻不同。JSON布林值是布林,表單或查詢字串通常是文字;PHP轉型因此有不同結果。

dump((bool) false);    // false
dump((bool) 'false');  // true
dump((bool) '0');      // false

這不是Laravel偷偷改了開關,而是一般PHP轉型規則。若你把任何非空文字都當作有效的開關,banana也會變true。不要為了這個問題只把false特判掉,再留下其他未定義的值可以任意打開設定。

在查修紀錄裡,同時記合成輸入值與型別。單看一行輸出的false,有可能其實是字串,也可能是布林。用測試資料先重現,不需要把真使用者的整份表單寫進日誌。

用Request的boolean讀常見開關值

在一般請求裡,可以直接讀你需要的欄位。Laravel官方文件列出1、字串1、true、字串true、on、yes等會被讀為true,其他值讀為false。

$enabled = $request->boolean('enabled');

例如HTML checkbox未指定value時,勾選常會送on;明確送字串false則得到false。這比PHP的任意非空字串轉型更貼近常見表單開關,但你仍應確認前端真的採用這份契約,不要假定不同客戶端會送相同型別。

如果API只接受真正的JSON布林,就應要求呼叫端送 true或 false,並按那個契約驗證。boolean方法讓你方便取值,不代表所有可被它轉換的字串都必須允許進入API。

用八種輸入跑同一個Request

在自有Laravel測試專案,可以建立合成Request,不連到正式設定資料。每次分別放入一種輸入,對照一般PHP轉型與Request boolean。

use Illuminate\Http\Request;
$request = Request::create('/demo', 'POST', ['enabled' => 'false']);
dump((bool) $request->input('enabled'));
dump($request->boolean('enabled'));

本文在PHP8.4.2、Laravel13.34.0測了missing、字串false、字串true、on、0、1、布林false與banana。字串false的PHP轉型是true,Request boolean是false;banana也出現true對false。true字串、on與1兩邊都是true,0、布林false與missing兩邊都是false。

這份比較看的是解讀方式,不是設定更新成功。尤其banana得到false,並沒有產生驗證錯誤。如果你的要求是非法值必須拒絕,就不能把「最後得到false」當成「輸入有效且使用者明確關閉」。

真HTTP請求還可能先經過字串整理等中介層。本文合成Request用固定測試值,沒有聲稱已涵蓋所有表單序列化與中介層設定。把程式接回網站後,用Network核實送出的值,再看伺服器實際讀到什麼,才能對上完整流程。

轉換與boolean驗證不是同一份允許集合

Laravel驗證的 boolean規則有自己的允許值,官方文件列出true、false、1、0以及字串1、字串0。它不等同Request boolean對on、yes等字串的轉換方式。不要以為兩個API都叫boolean,就可以交換使用而結果完全一樣。

例如你先用嚴格的boolean規則驗證,表單送on可能被拒絕;如果需求是標準checkbox輸入,應先設計一致的輸入與驗證流程。也可以讓前端明確送1或0,減少各端的差異。選擇哪種方式,要由這個入口的資料契約決定。

更不應先把任意非法文字轉成false,再驗證轉換後的布林值,結果宣稱原輸入已通過檢查。那樣已經丟失原值,驗證器看不到輸入原本不合理。要拒絕未知值時,先對原輸入做你選定的驗證,再轉成業務要用的布林。

沒送checkbox,可能是關閉,也可能是不改

HTML checkbox未勾選時,常不會送出該欄位。Request boolean在欄位缺席時的預設結果是false,對完整設定表單可能正好代表關閉。但部分更新API的missing可能表示保留原值,兩種情境不能用同一段無條件保存來處理。

如果部分更新契約是「沒送就不改」,先判斷輸入key是否存在,再對有送來的值進行驗證與轉換。不要只是每次把 $request->boolean('enabled')保存,否則只修改標題的請求也可能把開關關掉。

反過來,完整表單若用隱藏欄位與checkbox一起補送值,也要確認同名輸入如何被序列化。不同表單與客戶端可能讓伺服器收到單值或陣列,不應把未知陣列直接當成可用開關。本文八種值都不是陣列,真專案要按自己的輸入契約補測。

程式中的if也要讀正確資料

修正取值後,後續判斷應使用已經解析出的布林,而不是另一處又直接讀原字串。否則保存可能是false,發送通知的if仍把false字串當true,形成看起來很矛盾的行為。

$enabled = $request->boolean('enabled');
if ($enabled) {
    // 這裡只處理已明確解析為開啟的情況。
}

這段只是判斷示意,真功能的授權、業務條件與保存要各自完成。開關值是false,不表示使用者有權停用某個資源;值為true也不代表可觸發任何外部工作。讓輸入解讀、權限與動作有各自明確的責任。

回到前後端核三條路

至少測勾選、未勾選與明確傳false;若是API,再加missing與未知字串。每條路都看原payload、解析結果與最終設定。設定畫面顯示關閉而資料仍開啟,可能是保存問題;解析已經錯了,則先修輸入層,不必一開始就查快取。

將前端預期型別寫清楚,讓後來加新客戶端的人知道應送布林或哪種字串。Request boolean是合適的取值工具,但只有與驗證和更新契約配合,才能避免把缺席、非法與明確關閉全部混成一個false。

驗證案例別只斷言最後是false

如果系統要求非法值應被拒絕,測試就要另外核對驗證失敗,而不是只斷言最後布林為false。banana與合法false在轉換後都相同,卻應有不同的輸入結果;只測轉換值會把這項需求漏掉。

例如測試API採Laravel boolean規則,就把真正的false、0與字串0放進有效案例,把字串false與任意文字放進拒絕案例。若表單另採可接受on的規則,則保存另一份對應測試,別把兩個入口的允許集合硬併成一個。這些選擇是你的契約,不是某個字串在人眼看來合理就能自動成立。

對部分更新,還要核對省略欄位後原設定保持不變。這是更新行為的斷言,與Request boolean的單元比較不同。最後讓有效開啟、有效關閉、缺席與非法輸入各自有明確結果,才能在前端改序列化方式時及早發現差異。

同一份測試資料應保留原型別,避免測試工具先替你把字串轉成布林。

參考資料

原文鏈接:https://wntheme.com/laravel-request-boolean-false-string/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?