25

毎回異なる数の引数を取る準備済みの MySQL ステートメントを PHP でどのように記述しますか? このようなクエリの例は次のとおりです。

SELECT `age`, `name` FROM `people` WHERE id IN (12, 45, 65, 33)

IN句は、実行されるたびに異なる数の s を持ちますid

考えられる解決策は 2 つありますが、より良い方法があるかどうかを確認したいと考えています。

考えられる解決策 1ステートメントに 100 個の変数を受け入れさせ、残りをテーブルにないことが保証されたダミー値で埋めます。100 を超える値に対して複数の呼び出しを行います。

考えられる解決策 2準備済みステートメントを使用しないでください。インジェクション攻撃の可能性を厳密にチェックするクエリを作成して実行します。

4

7 に答える 7

21

いくつかの解決策を考えることができます。

解決策の 1 つは、一時テーブルを作成することです。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);

証拠はありませんが、最初の解決策はより大きなリストに適している可能性があり、後者の解決策はより小さなリストに適していると思われます。


ここで@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);

于 2008-11-29T09:36:05.837 に答える
10

2 番目のパラメーターがコンマ区切りの値の文字列であるFIND_IN_SET関数もあります。

SELECT age, name FROM people WHERE FIND_IN_SET(id, '12,45,65,33')
于 2012-06-10T09:39:36.797 に答える
4

適切な SQL ラッパーは、配列値へのバインドをサポートしています。すなわち

$sql = "... WHERE id IN (?)";
$values = array(1, 2, 3, 4);
$result = $dbw -> prepare ($sql, $values) -> execute ();
于 2008-11-29T09:55:41.083 に答える
2

#2をテーブルから降ろしてください。プリペアド ステートメントは、SQL インジェクションから身を守ることを検討すべき唯一の方法です。

ただし、できることは、バインディング変数の動的セットを生成することです。つまり、7 (または 103) が必要な場合は 100 を作成しないでください。

于 2008-11-29T09:47:51.210 に答える
2

http://bugs.php.net/bug.php?id=43568
これは私の問題に対する私の実用的な解決策です。これで、必要な数のパラメーターを動的に使用できるようになりました。それらは私が配列に持っているのと同じ数になるか、この場合は最後のクエリ(email = 'johndoe@gmail.com'のすべてのIDを見つけた)からのIDを動的クエリに渡してすべてを取得します最終的にいくつ必要になったとしても、これらの各 ID に関する情報。

<?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();
?>
于 2009-01-18T19:27:14.897 に答える
1

句で整数値のみを使用しているIN場合は、SQL パラメーターを使用せずにクエリを動的に作成することに反対するものは何もありません。

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)

しかし、ここでの解決策は、この問題に対するより一般的なアプローチであることは間違いありません。

于 2008-11-29T10:02:04.207 に答える
0

今日も同様の問題があり、このトピックを見つけました。答えを見て、グーグルを検索すると、かなりの解決策が見つかりました。

ただし、私の問題はもう少し複雑です。バインディング値と動的も固定されているためです

これが解決策です。

$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=49946PHP は配列を別の配列に追加します (array_push または + ではありません)[PHP]: エラー -> 少なすぎますsprintf() の引数; http://no2.php.net/manual/en/mysqli-stmt.bind-param.php#89171PHP 5.3.1 での参照渡しの問題

于 2014-01-17T10:35:14.460 に答える