I like the flexibility of Dynamic SQL and I like the security + improved performance of Prepared Statements. So what I really want is Dynamic Prepared Statements, which is troublesome to make because bind_param and bind_result accept "fixed" number of arguments. So I made use of an eval() statement to get around this problem. But I get the feeling this is a bad idea. Here's example code of what I mean
// 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);
Is that last eval() statement a bad idea? I tried to avoid code injection by encapsulating values behind the variable name $param.
Does anyone have an opinion or other suggestions? Are there issues I need to be aware of?
I made a filter function which recives an array an asociative array like $_GET:
In model class I've defined a couple of properties including the schema:
Then a filter method which recive an asociative arrays of conditions:
And works great to filter results
You don't really need prepared statements and bound arguments, because you can always use mysql_real_escape_string(). And you're right; dynamically generated SQL is far more flexible and valuable.
Here's a simple example using the regular mysql_* interface:
Of course, this is a simplistic example, and to make it useful you have to build and refine it a lot, but it shows the ideas and it's really very very useful. For example, here is a completely generic function to insert a new row into an arbitrary table, with the columns filled with the values from an associative array and completely SQL-injection safe:
I think it is dangerous to use
eval()
here.Try this:
"SELECT * FROM t1 WHERE p1 = ? AND p2 = ?"
prepare()
on thatcall_user_func_array()
to make the call tobind_param()
, passing in the dynamic params array.The code: