MySQL使用可变大小variables列表准备语句
你将如何在PHP中编写一个准备好的MySQL语句,每次都有不同数量的参数? 这样的查询的例子是:
SELECT `age`, `name` FROM `people` WHERE id IN (12, 45, 65, 33)
IN
子句每次运行时都会有不同数量的id
。
我脑海里有两种可能的解决方法,但是想看看有没有更好的办法。
可能的解决scheme1使语句接受100个variables,并用保证不在表中的虚拟值填充剩余的variables; 多次调用超过100个值。
可能的解决scheme2不要使用准备好的语句; build立并运行查询,严格检查可能的注入攻击。
我可以想到一些解决scheme。
一种解决scheme可能是创build一个临时表。 对in子句中的每个参数执行插入操作。 然后对临时表进行简单的连接。
另一种方法可能是做这样的事情。
$dbh=new PDO($dbConnect, $dbUser, $dbPass); $parms=array(12, 45, 65, 33); $parmcount=count($parms); // = 4 $inclause=implode(',',array_fill(0,$parmcount,'?')); // = ?,?,?,? $sql='SELECT age, name FROM people WHERE id IN (%s)'; $preparesql=sprintf($sql,$inclause); // = example statement used in the question $st=$dbh->prepare($preparesql); $st->execute($parms);
我怀疑,但没有任何证据,第一个解决scheme可能会更好的更大的名单,而后者将工作更小的名单。
让@orrd快乐在这里是一个简洁的版本。
$dbh=new PDO($dbConnect, $dbUser, $dbPass); $parms=array(12, 45, 65, 33); $st=$dbh->prepare(sprintf('SELECT age, name FROM people WHERE id IN (%s)', implode(',',array_fill(0,count($parms),'?')))); $st->execute($parms);
还有一个FIND_IN_SET
函数,其第二个参数是一个逗号分隔的string:
SELECT age, name FROM people WHERE FIND_IN_SET(id, '12,45,65,33')
体面的SQL包装器支持绑定到数组值。 即
$sql = "... WHERE id IN (?)"; $values = array(1, 2, 3, 4); $result = $dbw -> prepare ($sql, $values) -> execute ();
我从我的答案: http : //bugs.php.net/bug.php? id= 43568
这是我对我的问题的工作解决scheme。 现在我可以dynamic地使用尽可能多的参数。 他们将是相同的数字,因为我有一个数组中,或者在这种情况下,我通过从最后一个查询(其中find所有电子邮件='johndoe@gmail.com'ID)的ID到dynamic查询获取所有关于每个这些id的信息,无论我最终需要多less。
<?php $NumofIds = 2; //this is the number of ids i got from the last query $parameters=implode(',',array_fill(0,$NumofIds,'?')); // = ?,? the same number of ?'s as ids we are looking for<br /> $paramtype=implode('',array_fill(0,$NumofIds,'i')); // = ii<br/> //make the array to build the bind_param function<br/> $idAr[] = $paramtype; //'ii' or how ever many ?'s we have<br/> while($statement->fetch()){ //this is my last query i am getting the id out of<br/> $idAr[] = $id; } //now this array looks like this array:<br/> //$idAr = array('ii', 128, 237); $query = "SELECT id,studentid,book_title,date FROM contracts WHERE studentid IN ($parameters)"; $statement = $db->prepare($query); //build the bind_param function call_user_func_array (array($statement, "bind_param"), $idAr); //here is what we used to do before making it dynamic //statement->bind_param($paramtype,$v1,$v2); $statement->execute(); ?>
请从桌子上拿下2号。 准备好的语句是您应该考虑保护自己免受SQL注入攻击的唯一方法。
但是,您可以执行的操作是生成一组dynamic绑定variables。 即如果你需要7(或103),不要做100。
如果您只在IN
子句中使用整数值,则没有任何理由不使用SQL参数dynamic构build查询。
function convertToInt(&$value, $key) { $value = intval($value); } $ids = array('12', '45', '65', '33'); array_walk($ids, 'convertToInt'); $sql = 'SELECT age, name FROM people WHERE id IN (' . implode(', ', $ids) . ')'; // $sql will contain SELECT age, name FROM people WHERE id IN (12, 45, 65, 33)
但毫无疑问, 这里的解决scheme是解决这个问题的更一般的方法。
今天我遇到了一个类似的问题,我find了这个话题。 看看答案和search谷歌我find了一个漂亮的解决scheme。
虽然,我的问题稍微复杂一点。 因为我有固定的绑定值,也是dynamic的 。
这是解决scheme。
$params = array() $all_ids = $this->get_all_ids(); for($i = 0; $i <= sizeof($all_ids) - 1; $i++){ array_push($params, $all_ids[$i]['id']); } $clause = implode(',', array_fill(0, count($params), '?')); // output ?, ?, ? $total_i = implode('', array_fill(0, count($params), 'i')); // output iiii $types = "ss" . $total_i; // will reproduce : ssiiii ..etc // %% it's necessary because of sprintf function $query = $db->prepare(sprintf("SELECT * FROM clients WHERE name LIKE CONCAT('%%', ?, '%%') AND IFNULL(description, '') LIKE CONCAT('%%', ?, '%%') AND id IN (%s)", $clause)); $thearray = array($name, $description); $merge = array_merge($thearray, $params); // output: "John", "Cool guy!", 1, 2, 3, 4 // We need to pass variables instead of values by reference // So we need a function to that call_user_func_array('mysqli_stmt_bind_param', array_merge (array($query, $types), $this->makeValuesReferenced($merge)));
而函数makeValuesreferenced :
public function makeValuesReferenced($arr){ $refs = array(); foreach($arr as $key => $value) $refs[$key] = &$arr[$key]; return $refs; }
获得这个'知识'的链接: https : //bugs.php.net/bug.php?id = 49946 , PHP追加一个数组到另一个(不是array_push或+) , [PHP]:错误 – >太lesssprintf()中的参数; , http://no2.php.net/manual/en/mysqli-stmt.bind-param.php#89171 , 通过引用问题与PHP 5.3.1