7

望ましくない副作用なしで PDO を使用して、準備済みステートメントに必要以上のパラメーターを送信できますか?

奇妙な質問のように思えるかもしれませんが、同じような異なるパラメーターを使用する 4 つのクエリが連続しているため、質問します。クエリの関連部分:

1番目(選択、他とは異なるテーブル):
WHERE threadID = :tid

2番目 (選択):
WHERE user_ID = :u_ID AND thread_ID = :tid

3番目(2番目が成功した場合は更新):
SET time = :current_time WHERE user_ID = :u_ID AND thread_ID = :tid

4 番目 (2 番目が失敗した場合は挿入):
VALUES (:u_ID, :tid, :current_time)

最初に 3 つのパラメーターを指定して 1 つの配列を宣言し、それを 4 つのクエリすべてに使用できますか?

混乱を避けるために、クエリは個別に実行されます。これはパラメーター変数が再利用されるため、一部のクエリが不要なパラメーターを受け取ることを意味します。次のようなものです:

$parameters = array(':tid' => $tid, ':u_ID' => $u_ID, ':current_time' => $time);

$1st = $db->prepare($query1);
$1st->execute($parameters);

$2nd = $db->prepare($query2);
$2nd->execute($parameters);

$3rd = $db->prepare($query3);
$3rd->execute($parameters);

$4th = $db->prepare($query4);
$4th->execute($parameters);

できるなら、すべきですか?これにより、データベースやスクリプトの速度が低下したり、セキュリティ上の問題が発生したりすることはありますか?

この質問をもう少し明確にすることができれば、尋ねてください。

ありがとうございました!

4

4 に答える 4

5

おそらく、この質問が最初に尋ねられてからドキュメントが更新されたのでしょうが、今では「いいえ」とはっきりと述べられています。

指定した数より多くの値をバインドすることはできません。PDO::prepare() で指定された SQL よりも多くのキーが input_parameters に存在する場合、ステートメントは失敗し、エラーが発生します。

これらの回答は、余分なパラメーターを除外するのに役立ちます。

于 2016-08-19T19:46:13.657 に答える
3

これはすでに回答されており、追加のパラメーターを送信できるかどうかを尋ねるだけであることは知っていますが、人々がこの質問にたどり着き、この制限を回避する方法を知りたいと思った. 私が使用するソリューションは次のとおりです。

$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);

$1st = $db->prepare($query1);
$1st->execute(array_intersect_key($parameters, array_flip(array('tid'))));

$2nd = $db->prepare($query2);
$2nd->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid'))));

$3rd = $db->prepare($query3);
$3rd->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid', 'current_time'))));

$4th = $db->prepare($query4);
$4th->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid', 'current_time'))));

その array_interset_key と array_flip 操作は、次のように独自の関数に抽出できます。

function filter_fields($params,$field_names) {
    return array_intersect_key($params, array_flip($field_names))
}

私はまだそれに慣れていません。

この関数はキー名の配列を反転するため、配列には値がありませんが、正しいキーがあります。次に、最初の配列を交差フィルター処理して、両方の配列にあるキーのみを取得します (この場合、array_flipped 配列のキーのみ)。ただし、元の配列の値を取得します (空ではありません)。したがって、パラメーターの配列を 1 つ作成しますが、実際に PDO に送信されるパラメーターを指定します。

したがって、関数を使用すると、次のようになります。

$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);

$1st = $db->prepare($query1);
$1st->execute(filter_fields($parameters, array('tid')));

$2nd = $db->prepare($query2);
$2nd->execute(filter_fields($parameters, array('u_ID', 'tid')));

$3rd = $db->prepare($query3);
$3rd->execute(filter_fields($parameters, array('u_ID', 'tid', 'current_time')));

$4th = $db->prepare($query4);
$4th->execute(filter_fields($parameters, array('u_ID', 'tid', 'current_time')));

PHP 5.4 を使用している場合は、角かっこ配列構文を使用して、さらにクールにすることができます。

$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);

$1st = $db->prepare($query1);
$1st->execute(filter_fields($parameters, ['tid']));

$2nd = $db->prepare($query2);
$2nd->execute(filter_fields($parameters, ['u_ID', 'tid']));

$3rd = $db->prepare($query3);
$3rd->execute(filter_fields($parameters, ['u_ID', 'tid', 'current_time']));

$4th = $db->prepare($query4);
$4th->execute(filter_fields($parameters, ['u_ID', 'tid', 'current_time']));
于 2013-10-18T16:04:20.110 に答える
2

I got a chance to test my question, and the answer is you cannot send more parameters than the query uses. You get the following error:

PDOException Object
(
    [message:protected] => SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
    [string:Exception:private] => 
    [code:protected] => HY093
    [file:protected] => C:\Destination\to\file.php
    [line:protected] => line number
    [trace:Exception:private] => Array
        (
            [0] => Array
                (
                    [file] => C:\Destination\to\file.php
                    [line] => line number
                    [function] => execute
                    [class] => PDOStatement
                    [type] => ->
                    [args] => Array
                        (
                            [0] => Array
                                (
                                    [:u_ID] => 1
                                    [:tid] => 1
                                    [:current_time] => 1353524522
                                )

                        )

                )

            [1] => Array
                (
                    [file] => C:\Destination\to\file.php
                    [line] => line number
                    [function] => function name
                    [class] => class name
                    [type] => ->
                    [args] => Array
                        (
                            [0] => SELECT
                                                column
                                            FROM
                                                table
                                            WHERE
                                                user_ID  = :u_ID AND
                                                thread_ID = :tid
                            [1] => Array
                                (
                                    [:u_ID] => 1
                                    [:tid] => 1
                                    [:current_time] => 1353524522
                                )

                        )

                )

        )

    [previous:Exception:private] => 
    [errorInfo] => Array
        (
            [0] => HY093
            [1] => 0
        )

)

I don't know a huge amount about PDO, hence my question, but I think that because :current_time is sent but not used and the error message is "Invalid parameter number: parameter was not defined" you cannot send extra parameters which are not used.

Additionally the error code HY093 is generated. Now I can't seem to find any documentation explaining PDO codes anywhere, however I came across the following two links specifically about HY093:
What is PDO Error HY093
SQLSTATE[HY093]

It seems HY093 is generated when you incorrectly bind parameters. This must be happening here because I am binding too many parameters.

于 2012-11-21T19:35:24.313 に答える
0

1 回の実行で異なるタイプの複数のクエリを実行すると、問題が発生します。1 回の実行で複数の選択または複数の更新を実行できます。この場合、さまざまな準備済みステートメント オブジェクトを作成し、それに応じてパラメーターを渡します。

// for WHERE threadID = :tid
$st1 = $db->prepare($sql);
$st1->bindParam(':tid', $tid);
$st1->execute();
or
$st1->execute(array(':tid'=>$tid);

// for WHERE user_ID = :u_ID AND thread_ID = :tid
$st2 = $db->prepare($sql);
$st2->bindParam(':u_ID', $u_ID);
$st2->bindParam(':tid', $tid);
$st2->execute();
or
$st2->execute(array(':tid'=>$tid, ':u_ID' => $u_ID);

// for SET time = :current_time WHERE user_ID = :u_ID AND thread_ID = :tid
$st3 = $db->prepare($sql);
$st3->bindParam(':u_ID', $u_ID);
$st3->bindParam(':tid', $tid);
$st3->bindParam(':current_time', $current_time);
$st3->execute();
or
$st3->execute(array(':tid'=>$tid, ':u_ID' => $u_ID, ':current_time' => $current_time);

// for VALUES (:u_ID, :tid, :current_time)
$st4 = $db->prepare($sql);
$st4->bindParam(':u_ID', $u_ID);
$st4->bindParam(':tid', $tid);
$st4->bindParam(':current_time', $current_time);
$st4->execute();
or
$st4->execute(array(':tid'=>$tid, ':u_ID' => $u_ID, ':current_time' => $current_time);
于 2012-11-21T11:14:43.083 に答える