2008-10-14 81 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