2008-10-14 59 views
7

我喜歡Dynamic SQL的靈活性,我喜歡安全性+改進的Prepared Statements性能。所以我真正想要的是Dynamic Prepared Statements,這很麻煩,因爲bind_param和bind_result接受「固定」數量的參數。所以我使用了一個eval()語句來解決這個問題。但我覺得這是一個糟糕的主意。這裏是我的意思的示例代碼動態準備的語句錯誤嗎? (使用php + mysqli)

// array of WHERE conditions 
$param = array('customer_id'=>1, 'qty'=>'2'); 
$stmt = $mysqli->stmt_init(); 

$types = ''; $bindParam = array(); $where = ''; $count = 0; 

// build the dynamic sql and param bind conditions 
foreach($param as $key=>$val) 
{ 
    $types .= 'i'; 
    $bindParam[] = '$p'.$count.'=$param["'.$key.'"]'; 
    $where .= "$key = ? AND "; 
    $count++; 
} 

// prepare the query -- SELECT * FROM t1 WHERE customer_id = ? AND qty = ? 
$sql = "SELECT * FROM t1 WHERE ".substr($where, 0, strlen($where)-4); 
$stmt->prepare($sql); 

// assemble the bind_param command 
$command = '$stmt->bind_param($types, '.implode(', ', $bindParam).');'; 

// evaluate the command -- $stmt->bind_param($types,$p0=$param["customer_id"],$p1=$param["qty"]); 
eval($command); 

是最後一個eval()語句是個壞主意嗎?我試圖通過在變量名稱$ param後面封裝值來避免代碼注入。

有沒有人有意見或其他建議?我需要注意哪些問題?

+0

您可能要改一下你的問題標題有點,所以其他人可以更容易地找到你的問題。 – Tomalak 2008-10-14 16:06:31

回答

13

我認爲這裏使用eval()是危險的。

試試這個:

  • 迭代參數數組建立與問號上
  • 使用call_user_func_array() SQL字符串"SELECT * FROM t1 WHERE p1 = ? AND p2 = ?"
  • 呼叫prepare()撥打電話到bind_param(),通過在動態PARAMS陣列。

代碼:

call_user_func_array(array($stmt, 'bind_param'), array($types)+$param); 
+2

小心使用`array($ types)+ $ param`。如果$ param是一個索引爲0的數組,那麼$ param中的那個值將被拋棄,而偏向$ types,並且您的變量會少於字符串中指定的變量。 http://php.net/manual/en/language.operators.array.php – Tushar 2012-05-12 04:40:24

-1

你並不真的需要準備的語句和綁定參數,因爲你總是可以使用mysql_real_escape_string()。你說得對;動態生成的SQL更加靈活和有價值。

下面是使用常規mysql_ *接口一個簡單的例子:

// Array of WHERE conditions 
$conds = array("customer_id" => 1, "qty" => 2); 

$wherec = array("1"); 
foreach ($conds as $col=>$val) $wherec[] = sprintf("`%s` = '%s'", $col, mysql_real_escape_string($val)); 

$result_set = mysql_query("SELECT * FROM t1 WHERE " . implode(" AND ", $wherec); 

當然,這是一個簡單的例子,並使其有用,你必須建立和完善了很多,但它顯示了想法和它真的非常非常有用。例如,這裏是一個完全通用的功能,插入新行成任意表,與充滿值從一個關聯數組,完全SQL注入安全列:

function insert($table, $record) { 
    $cols = array(); 
    $vals = array(); 
    foreach (array_keys($record) as $col) $cols[] = sprintf("`%s`", $col); 
    foreach (array_values($record) as $val) $vals[] = sprintf("'%s'", mysql_real_escape_string($val)); 

    mysql_query(sprintf("INSERT INTO `%s`(%s) VALUES(%s)", $table, implode(", ", $cols), implode(", ", $vals))); 
} 

// Use as follows: 
insert("customer", array("customer_id" => 15, "qty" => 86)); 
+2

綁定參數增加了額外的安全性而不是轉義。使用它們是一個很好的做法。 – troelskn 2008-10-15 22:02:02