後台列表頁常見「勾選多行 → 批量刪除」需求。前端用同名 name="ids[]" 發送陣列,後端需將陣列安全轉為 SQL IN (...) 條件。本文展示完整流程與防注入要點。
<form action="?action=doing" method="post">
<input name="ID_Dele[]" type="checkbox" value="1"/> 項目 1
<input name="ID_Dele[]" type="checkbox" value="2"/> 項目 2
<input name="ID_Dele[]" type="checkbox" value="3"/> 項目 3
<input name="ID_Dele[]" type="checkbox" value="4"/> 項目 4
<input type="submit" value="批量刪除"/>
</form>
瀏覽器將勾選的值作為陣列提交:$_POST['ID_Dele'] = ['1','2','3']。
<?php
if ($_GET['action'] === 'doing' && $_POST) {
// 1. 獲取陣列(未勾選時可能為 null)
$ids = $_POST['ID_Dele'] ?? [];
// 2. 過濾驗證:確保全為整數 ID
$ids = array_map('intval', $ids); // 強制轉整數,過濾非數字
$ids = array_filter($ids, fn($v) => $v > 0); // 移除 0 或負數
$ids = array_unique($ids); // 去重
if (empty($ids)) {
die('未選擇有效項目');
}
// 3. 安全構建 IN 條件:佔位符動態生成
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$sql = "DELETE FROM `doing` WHERE `id` IN ($placeholders)";
// 4. 預處理語句綁定參數(防 SQL 注入)
$stmt = $pdo->prepare($sql);
$stmt->execute($ids);
echo "成功刪除 {$stmt->rowCount()} 條記錄";
}
?>
name="ID_Dele[] 方括號告訴 PHP 將同名字段組裝為陣列,ASP 直接給字串 1,2,3,PHP 需額外處理。intval + > 0 確保只有合法正整數進入 SQL,徹底阻斷注入。array_fill(0, count($ids), '?') 產生 ['?','?','?'],implode 拼成 ?,?,?,數量與參數嚴格對應。execute($ids) 自動綁定陣列值到佔位符,無需手動 bindValue 循環。// ❌ 危險:直接拼接字串,若 $ids 含惡意輸入將導致注入
$ID_Dele = implode(",", $_POST['ID_Dele']);
$SQL = "delete from `doing` where id in ($ID_Dele)";
若攻擊者構造提交 ID_Dele[]=1; DROP TABLE users;--,經 implode 後 SQL 變為:
DELETE FROM `doing` WHERE id IN (1; DROP TABLE users;--)
雖多語句執行受驅動限制,但聯合查詢、子查詢注入風險極高。
// 若 ID 連續或量極大 (萬級+),考慮分塊或臨時表
// 方案 A:分塊執行,避免單條 SQL 過長 / 鎖表過久
$chunks = array_chunk($ids, 500);
foreach ($chunks as $chunk) {
$ph = implode(',', array_fill(0, count($chunk), '?'));
$pdo->prepare("DELETE FROM `doing` WHERE `id` IN ($ph)")->execute($chunk);
}
// 方案 B:臨時表 + JOIN(適合極大批量、需事務一致性)
$pdo->exec('CREATE TEMPORARY TABLE tmp_del (id INT PRIMARY KEY)');
$stmt = $pdo->prepare('INSERT INTO tmp_del (id) VALUES (?)');
foreach ($ids as $id) { $stmt->execute([$id]); }
$pdo->exec('DELETE d FROM `doing` d JOIN tmp_del t ON d.id = t.id');
<input type="checkbox" id="checkAll"> + JS 同步子項狀態。onclick="return confirm('確定刪除選中的 ' + checkedCount + ' 項?')"。fetch('/api/delete', {method:'POST', body: JSON.stringify(ids)}),無刷新更新列表。批量刪除看似簡單,實則是「前端陣列傳輸 → 後端白名單過濾 → 參數化查詢」安全鏈路的經典練習。養成預處理習慣,讓 SQL 注入無處遁形。