質問のセキュリティ部分に関しては、プレースホルダーを使用した準備済みステートメントは、これらのプレースホルダーに値を入力する際の検証メカニズムと同じくらい安全です。mysqli の準備済みステートメントの場合、ドキュメントには次のように記載されています。
マーカーは、SQL ステートメントの特定の場所でのみ有効です。たとえば、INSERT ステートメントの VALUES() リストで (行の列の値を指定するために)、または WHERE 句の列との比較で比較値を指定することができます。
ただし、識別子 (テーブル名や列名など)、SELECT ステートメントによって返される列を指定する選択リスト、または = 等号などの二項演算子の両方のオペランドを指定することはできません。後者の制限が必要なのは、パラメーターの型を判別できないためです。? によってマーカーを NULL と比較することはできません。IS 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
クエリ内の対応するプレースホルダーにバインドする必要があります。
補遺:
ただし、次の 2 つの点に注意する必要があります。
call_user_func_array
は、2 番目のパラメーターに整数のインデックス付き配列を想定しています。辞書でどのように動作するかわかりません。
mysqli_stmt_bind_param
パラメータを参照渡しする必要があります。
最初の点については、 が整数インデックスを使用していることを確認するだけで済みます$bindArray
。これは上記のコードの場合です (または、call_user_func_array
提供している配列で がチョークしないことを確認してください)。
2 番目の点については、呼び出し$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();});