2013-05-17 109 views
1

對於給定的代碼,我收到以下SQL錯誤。PDO綁定問題

您的SQL語法錯誤;檢查coresponds 你的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 =>新列值)的值數組。 $ passed_columns只包含一個與$ _POST ['cols']中的鍵匹配的列名稱數組我相信問題與值的綁定方式有關。如果我回顯$ SQL變量,則輸出是有效的SQL(使用我正在測試的值)。

但奇怪的是,如果我手動設置$ SQL到有效的SQL,它只是輸出(「更新用戶設置的角色=:角色其中USER_ID IN(100)」),劇本的作品。

+0

這是一個MySQL錯誤,在綁定之前。 'echo $ SQL'來查看構造語句的樣子。它會有一些奇怪的東西導致這個模棱兩可的錯誤信息。 –

+0

您是否試過迴應您的查詢?它是什麼樣子的? – andrewsi

+0

回顯的查詢是有效的SQL(在構建之後),如果我將查詢複製到Workbench /手動執行它,它將起作用。它看起來像這樣:「更新用戶SET角色=:角色WHERE user_id IN(100)」 – syl

回答

3

反饋:

  • 使用"string" . $var變得非常不可讀迅速。 PHP可以直接在字符串中嵌入變量:"string $var",如果您需要執行數組表達式,則可以使用大括號"string {$arr['key']}"

  • 我建議劃定與後臺蜱列名。

  • 搓背最後一個逗號落定名單是笨拙的。最好使用逗號將數組設置爲數組並使用implode。

  • 您的IN列表易受SQL注入攻擊。使用(int)映射user_id值以刪除可能的惡意內容。如果user_id值不是整數,則使用查詢參數(但不要在一個語句中將?位置參數與命名參數混合在一起 - 它會混淆PDO)。

  • bind_param()是不必要的。只需將參數值傳遞給execute()即可。在PHP的現代版本中,鍵值中的前導冒號是不必要的,這使得直接從鍵/值數組傳遞參數變得更簡單。

  • 這不是從你的例子清楚,如果$ passed_columns從用戶輸入取東西,或者在您的應用程序,如果是硬編碼。注意以這種方式引入SQL注入。我假設$ passed_columns只包含您控制的值。

  • prepare()返回false出錯,所以您應該始終檢查其返回值並適當地響應錯誤。

  • print_r()實際打印輸出,而不是返回一個字符串,除非你通過可選的第二個參數真。

  • 這是一個驚喜,大多數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:剛開始使用模具(),如果你得到一個錯誤,未必是最好的事情。專業的網絡界面會爲開發人員記錄錯誤,然後向用戶展示更好的屏幕。

+0

這有效,比我寫的方式更好。我只是希望我知道我爲什麼不行。 – syl

+0

是的,這是一個謎。您可以啓用[通用查詢日誌](http://dev.mysql.com/doc/refman/5.6/en/query-log.html),它記錄失敗的查詢,並查看實際到達MySQL服務器的SQL當它認爲有錯誤時。但是有時我會遇到神祕失敗的代碼,當我重寫它時,過程中會有某些東西被修復。很高興知道原來的問題是什麼,但除此之外取勝並繼續前進。 :-) –