2013-07-24 12 views
8

現在、私はsearchという名前のテキスト入力とparamという名前の「選択」ボックスの2つの要素のみを持つ小さな検索フォームを持っています。そのボックス内で選択されたオプションは、DB内のどのテーブル列をフェッチするかを選択するパラメータとして使用する必要があります。 mysql_機能を使用してmysqliを使用して変数をWHERE節に渡すにはどうすればよいですか?

は、このような何かを行うことができます。

$param = $_POST['param' ]; 
$search = $_POST['search']; 

$query = 'SELECT * FROM table WHERE $param LIKE "%$search%"'; 

しかし、私はそれはmysqli_構文で動作させることはできません。私は、プリペアドステートメントを使用しようとしていますが、私がこれまで行ってきた最高のはこれです:

$param = $_POST['param' ]; 
$search = $_POST['search']; 

if($param == 'first_name') 
{ 
    if($prep = $link->prepare('SELECT * FROM table 
           WHERE first_name 
           LIKE CONCAT("%", ?, "%")')) 
    { 
     $prep->bind_param('s', $search); 
     $prep->execute(); 
     $prep->bind_result($first_name, $last_name); 

     while($prep->fetch()) 
      echo $first_name . ' ' . $last_name; 

     $prep->close(); 
    } 
    else 
     echo 'Error while preparing statement.'; 
} 
else if($param == 'last_name') 
{ 
    ... 
} 

しかし、単にelse if Sの束を使用して、私は列の多くのを持っている特別な場合は、多くの反復および非生産的なようですハンドル。

私が試した最初のことは、パラメータバインド-と$prep->bind_param('ss', $param, $search) - でしたが、機能しませんでした(と私はまだ分かりません)。

もっと知的なやり方でこれを行う方法はありますか?

+0

+1あなたの質問を整形するには –

+0

.... WHERE "。$ param。" LIKE ....私はSQL文で何をするのですか? – Adsy2010

+1

私が知る限り、列名にプレースホルダを使用することはできません。そのため、動作しませんでした。 –

答えて

3

あなただけの可能性のparamsのハッシュを作成し、すべてのPARAMに同じSQLコードを使用している場合:(CGI param name => table column name)

$params = array(
    'first_name' => 'first_name', 
    'last_name' => 'last_name', 
); 

それはあなたがSQLインジェクションから保護されているとして、セキュリティの観点から、はるかに良いです。

はその後、ハッシュから列名を取得し、クエリにそれを置く - あなたは、if-Sを取り除くでしょう:

$name = $params[$param]; 
$sql = "SELECT * FROM table 
WHERE 
$name LIKE ?"; 

if($prep = $link->prepare($sql)) 
{ 
    $prep->bind_param('s', "%$search%"); 
    ... 

@Akamが言ったように、CONCATする必要はありません( "%を"、?、"% ")を照会する必要があります。値を直前のパーセントとバインドする方がよいでしょう。むしろ、クエリよりも、例えば -

+1

代わりに、クエリでconcatする必要はありません: 'bind_param( 's'、"%$ search% ")' –

+1

@Akam Answer – user4035

+0

効果的でクリーンです。ありがとうございました! – Renato

2

は、PHPマニュアルでは、この例によれば

http://www.php.net/manual/en/mysqli-stmt.bind-param.php#108790

はあなたが結合されている文字列変数に「%」を追加することが最善であるように見えますあなたの例:

if($prep = $link->prepare('SELECT * FROM table 
          WHERE first_name 
          LIKE ?')) 
{ 
    $search='%'.$search.'%'; 
    $prep->bind_param('s', $search); 
    $prep->execute(); 
    $prep->bind_result($first_name, $last_name); 

    while($prep->fetch()) 
     echo $first_name . ' ' . $last_name; 

    $prep->close(); 
} 

これはテストされていませんが、分かりやすい解決策です。

+0

ダイナミックなフィールド名を使用するという彼の問題を解決することはできませんが、彼のソリューションの例を修正します。 –

+0

申し訳ありませんが、あなたが正しいです、私はポイントを逃した。私は単純に列名の代わりにクエリ文字列に$ param文字列を置き換えます。しかし、私はコンテンツにいくつかの深刻なフィルタリングを最初に適用する。 $ unsafe_col_name = "/ [^ a-zA-Z0-9 \\\ _] /"; $ param = preg_replace( "$ unsafe_col_name"、 ""、$ param); –

1

プレースホルダを列名に使用することはできないため、通常は列名を連結する必要があります。しかし、代わりにちょうどmysqliのでそれをエスケープする、あなたは列の限定セットを持っているので、私はしばらくのリストのアプローチをお勧めしたい:

$allowed_params = array('first_name', 'last_name', etc); 

$param = $_POST['param' ]; 
$search = $_POST['search']; 


if(!in_array($param, $allowed_params)) 
    die("Uh oh, the request seems to have an invalid param!"); 

if($prep = $link->prepare('SELECT * FROM table 
          WHERE ' . $param . ' 
          LIKE ?')) 
{ 
    $prep->bind_param('s', '%' . $search . '%'); 
    $prep->execute(); 
    $prep->bind_result($first_name, $last_name); 

    while($prep->fetch()) 
     echo $first_name . ' ' . $last_name; 

    $prep->close(); 
} 
else 
    echo 'Error while preparing statement.'; 

concat文の除去に注意して、代わりにPHPで連結します。これは準備されたステートメントにとって重要です。一度サーバーに到達すると、実際にそれらが結合されていないため(準備されたステートメントの保護)、ワイルドカードが$search文字列で送信されない限り正常に動作しません。

関連する問題