面對幾十上百個表單字段,逐個 $_POST['field'] 接收、手寫超長 SQL 不僅繁瑣易錯,還難以維護。本文介紹「表單數組命名 + 白名單過濾 + 動態構建 SQL」的通用模式,大幅提升開發效率與代碼質量。
name 統一為 setting[字段名] 格式$setting = $_POST['setting'] 得到關聯數組INSERT/UPDATE 語句<input type="text" name="setting[username]" value="" />
<input type="text" name="setting[email]" value="" />
<input type="text" name="setting[phone]" value="" />
<textarea name="setting[address]"></textarea>
<select name="setting[role_id]"><option value="1">管理員</option></select>
<input type="hidden" name="setting[created_at]" value="{{ date('Y-m-d H:i:s') }}" />
提交後 $_POST['setting'] 即為:
[
'username' => '張三',
'email' => 'zhang@example.com',
'phone' => '13800000000',
'address' => '北京市朝陽區...',
'role_id' => '1',
'created_at' => '2024-01-15 10:30:00'
]
// 允許寫入的字段字典(可從數據庫元數據自動生成) $allowedFields = ['username', 'email', 'phone', 'address', 'role_id', 'created_at'];
**作用**:防止攻擊者偽造 setting[is_admin]=1 等非預期字段注入,實現「默認拒絕,顯式允許」。
4. 動態 UPDATE 構建
進階:使用預處理語句 (Prepared Statements) 杜絕注入
// INSERT 預處理版 $fields = array_intersect_key($setting, array_flip($allowedFields)); $cols = implode(',', array_map(fn($c) => "`$c`", array_keys($fields))); $placeholders = implode(',', array_fill(0, count($fields), '?')); $sql = "INSERT INTO `user_table` ($cols) VALUES ($placeholders)"; $stmt = $conn->prepare($sql); $types = str_repeat('s', count($fields)); // 簡化:全部按字符串綁定 $stmt->bind_param($types, ...array_values($fields)); $stmt->execute(); // UPDATE 預處理版 $set = implode(',', array_map(fn($c) => "`$c` = ?", array_keys($fields))); $sql = "UPDATE `user_table` SET $set WHERE `id` = ?"; $stmt = $conn->prepare($sql); $params = array_values($fields); $params[] = $id; $types = str_repeat('s', count($fields)) . 'i'; $stmt->bind_param($types, ...$params); $stmt->execute();適用場景與擴展
| 場景 | 處理方式 |
|---|---|
| 字段固定、數量 < 20 | 手寫 SQL 可接受,仍建議白名單 |
| 字段多、頻繁變動、多表單復用 | **本文模式最優** |
| 文件上傳混合表單 | $_FILES 另行處理,$_POST['setting'] 只管普通字段 |
| 巢狀數據 (JSON) | 前端 JSON.stringify 後傳單字段,後端 json_decode 再走白名單 |
| 異步分步提交 (向導式) | 每步驗證白名單子集,暫存 Session,最後合併入庫 |
name="model[field]" 命名規範$allowedFields 白名單(可自動從 Migration/Schema 讀取)mysqli_real_escape_string(int)$id, floatval($price), date('Y-m-d', strtotime($dt))NULL 還是空字符串,白名單中標註admin_id, action, table, record_id, diff_json採用此模式後,新增/修改表單字段只需調整 HTML 與白名單,**零修改後端邏輯**,真正實現「配置驅動 CRUD」。