关于问题的安全部分,带有占位符的准备好的语句与用值填充这些占位符所涉及的验证机制一样安全。对于 mysqli 准备好的语句,文档说:
标记仅在 SQL 语句中的某些位置是合法的。例如,它们可以在 INSERT 语句的 VALUES() 列表中使用(以指定行的列值),或者在与 WHERE 子句中的列进行比较以指定比较值时。
但是,它们不允许用于标识符(例如表名或列名),在命名要由 SELECT 语句返回的列的选择列表中,或指定二元运算符(例如 = 等号)的两个操作数。后一个限制是必要的,因为不可能确定参数类型。不允许将标记与 NULL 进行比较?也为空。通常,参数仅在数据操作语言 (DML) 语句中合法,在数据定义语言 (DDL) 语句中不合法。
这显然排除了修改查询的一般语义的任何可能性,这使得更难(但并非不可能)将其从最初的意图转移。
关于查询的动态部分,您可以str_repeat
在查询条件构建部分中使用,而不是执行循环:
$searchStr = 'WHERE tags.tag LIKE ?' .
str_repeat($searchNumber - 1, ' OR tags.tag LIKE ?');
对于bind_param
通话,您应该call_user_func_array
像这样使用:
$bindArray[0] = str_repeat('s', $searchNumber);
array_walk($searchArray,function($k,&$v) use (&$bindArray) {$bindArray[] = &$v;});
call_user_func_array(array($stmt,'bind_param'), $bindArray);
希望上面的代码片段应该将查询中的每个值$bindArray
与其对应的占位符绑定。
附录:
但是,您应该警惕两件事:
call_user_func_array
需要一个整数索引数组作为其第二个参数。我不确定它在字典中的表现如何。
mysqli_stmt_bind_param
要求其参数通过引用传递。
对于第一点,您只需要确保它$bindArray
使用整数索引,上面的代码就是这种情况(或者检查它call_user_func_array
不会阻塞您提供的数组)。
对于第二点,如果您打算在调用$bindArray
之后bind_param
(即通过call_user_func_array
函数)和执行查询之前修改数据,这将是一个问题。如果您希望这样做 - 例如,通过在同一脚本中使用不同参数的值多次运行相同的查询,那么您将必须使用相同的数组 ( $bindArray
) 来执行以下查询,并使用相同的键。除非手动完成,否则复制另一个数组是行不通的:
foreach($bindArray as $k => $v)
$bindArray[$k] = some_new_value();
或者
foreach($bindArray as &$v)
$v = some_new_value();
上面的方法会起作用,因为它不会破坏bind_param
先前调用时与该语句绑定的数组条目上的引用。同样,以下应该有效,因为它不会更改之前设置的引用。
array_walk($bindArray, function($k,&$v){$v = some_new_value();});