问题
I have an array with ids that I get from client. And I want use those ids in my sql query with IN
clause. But this query goes on a table that has no model. So there is no active record (criteria) query possible.
** Table userTasks **
--------------------
| idUser | idTasks |
---------+----------
| 1 | 1 |
---------+----------
| 1 | 2 |
---------+----------
| 1 | 3 |
---------+----------
First approach does not work because params are always considered as strings. So :tasks
is a string '1,2,3' instead of a comma separated list of ids:
$sql = 'SELECT COUNT(*) AS matches
FROM userTasks
WHERE idUser = :idUser
AND idTask IN (:tasks)';
$result = Yii::app()->db->createCommand($sql)
->queryRow(true,[
':idUser' => $idUser,
':tasks' => implode(',', $tasks)]); //$tasks is a simple array of ids [1,2,3]
So my workaround:
foreach($tasks as $task) //$tasks is a simple array of ids [1,2,3]
{
$inTasks[] = (int) $task;
}
$sql = 'SELECT COUNT(*) AS matches
FROM userTasks
WHERE idUser = :idUser
AND idTask IN (' . implode(',', $inTasks . ')';
$result = Yii::app()->db->createCommand($sql)
->queryRow(true,[':idUser' => $idUser]);
回答1:
Having come across this problem a few times in my projects I have come-up with the following Yii work-around using CDbCriteria which is a little hacky, but gives the security of param count matching.
I would also use queryScalar()
in this instance to get the result directly.
When applied to your example my code would be:
$idUser = 1;
$tasks = array(1,2,3);
$criteria = new CDbCriteria();
$criteria->addInCondition('idTask',$tasks);
$sql = '
SELECT COUNT(*) matches
FROM userTasks
WHERE idUser = :idUser
AND '.$criteria->condition;
$command = Yii::app()->db->createCommand($sql);
$command->bindValue('idUser',$idUser);
$command->bindValues($criteria->params);
$result = $command->queryScalar();
回答2:
For preventing SQL injection in Yii IN clause we need to bind parameters in IN clause, Yii CDB criteria queries don't have this functionality in built. so you can use below code.
$products_ids = array(234,100,405,506);
map the array for binding
$in_query = implode(',', array_fill(0, count($products_ids), '?'));
Prepare the commadn object for select
$command = Yii::app()->db->createCommand()
->select('product_id, product_name, product_image, product_price')
->from('products')
->where('product_id IN(' . $in_query . ')');
bind the parameters
foreach ($products_ids as $k => $product_id){
$command->bindValue(($k+1),$product_id,PDO::PARAM_INT);
}
get the result
$products = $command->queryAll();
来源:https://stackoverflow.com/questions/24805247/how-to-prevent-mysql-injection-when-using-mysql-in-clause-without-activerecord-i