[英]PDO Binding Issue
我給出了給定代碼的以下SQL錯誤。
您的SQL語法有錯誤; 查看與您的MySQL服務器版本相對應的手冊,以便在第1行的''附近使用正確的語法
編碼:
$set_query = "";
foreach ($passed_columns as $c)
{
$set_query .= $c . " = " . ':' . $c . ',';
}
$p = strlen($set_query);
$set_query[$p-1] = "";
$SQL = 'UPDATE users SET ' . $set_query . ' WHERE user_id IN (' . implode(",", $_POST['user_id']) . ')';
$stmt = $dbh->prepare($SQL);
foreach($_POST['cols'] as $key => $val)
{
$stmt->bindValue(':' . $key, $val);
}
if (!$stmt->execute()) {
die(print_r($stmt->errorInfo()));
}
$ _POST ['cols']包含一個鍵值數組(column_name => new column value)。 $ passed_columns只包含一個與$ _POST ['cols']中的鍵匹配的列名數組
我認為這個問題與價值觀的約束方式有關。 如果我回顯$ SQL變量,則輸出是有效的SQL(帶有我正在測試的值)。
但奇怪的是,如果我手動將$ SQL設置為有效的SQL,它只輸出(“UPDATE users SET role =:role WHERE user_id IN(100)”),腳本可以工作。
反饋:
使用"string" . $var
"string" . $var
很快就變得難以理解了。 PHP可以直接在字符串中嵌入變量: "string $var"
如果你需要做數組表達式,你可以使用大括號,如"string {$arr['key']}"
。
我建議使用反向標記來分隔列名稱。
從列表中刪除最后一個逗號是笨拙的。 最好將set-list構建為數組並使用逗號進行內爆。
您的IN列表容易受到SQL注入攻擊。 使用(int)映射user_id值以刪除可能的惡意內容。 如果USER_ID值不是整數,然后使用查詢參數(但不要混用?
使用命名參數的位置參數在單個語句-它混淆了PDO)。
bind_param()是不必要的。 只需將參數值傳遞給execute()即可。 在現代版本的PHP中,鍵值中的前導冒號是不必要的,這使得直接從鍵/值數組傳遞參數變得更加簡單。
從您的示例中不清楚$ passed_columns是從用戶輸入中獲取的內容,還是在應用程序中硬編碼的內容。 小心以這種方式引入SQL注入。 我假設$ passed_columns只包含你控制的值。
prepare()在出錯時返回false
,因此您應該始終檢查其返回值並適當地響應錯誤。
print_r()實際打印到輸出,而不是返回一個字符串,除非你傳遞可選的第二個參數為true。
這對大多數PHP開發人員來說都是一個驚喜,但雙引號字符串實際上比單引號字符串略快。 不管是差異都很小,但是雙引號字符串允許你將變量直接放在字符串中,為什么不呢?
以下是我編寫代碼的方法:
$set_terms = array();
foreach ($passed_columns as $c)
{
$set_terms[] = "`$c` = :$c";
}
$set_clause = implode(",", $set_terms);
$user_id_list = implode(",", array_map(function($id) { return (int) $id; },
$_POST["user_id"]);
$SQL = "UPDATE users SET {$set_clause} WHERE user_id IN ({$user_id_list})";
if (!($stmt = $dbh->prepare($SQL)) {
die(print_r($dbh->errorInfo(), true));
}
if (!$stmt->execute($_POST["cols"])) {
die(print_r($stmt->errorInfo(), true));
}
PS:如果你收到錯誤,只使用die()可能不是最好的事情。 專業的Web界面會為開發人員記錄錯誤,然后為用戶提供更好的屏幕。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.