2013-07-24 4 views
8

Ich habe derzeit ein kleines Suchformular mit nur zwei Elementen: eine Texteingabe mit dem Namen search und ein "Select" -Box mit dem Namen param. Die in diesem Feld ausgewählte Option sollte als Parameter verwendet werden, um auszuwählen, welche Tabellenspalte in meiner DB abgerufen werden soll.Wie kann ich eine Variable mit mysqli an eine WHERE-Klausel übergeben?

Mit mysql_ Funktionen, so etwas wie dies geschehen könnte:

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

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

Aber ich kann es nicht mit der mysqli_ Syntax zu arbeiten. Ich versuche, vorbereitete Anweisungen zu verwenden, aber das Beste, was ich bisher gemacht habe, ist dies:

$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') 
{ 
    ... 
} 

Aber nur ein Bündel von else if s mit viel sich wiederholende und unproduktiv scheint, besonders, wenn ich viele Spalten müssen Griff.

Das erste, was ich versuchte, war Parameter verbindlich - ... WHERE ? LIKE ... und $prep->bind_param('ss', $param, $search) -, aber es hat nicht funktioniert (und ich weiß immer noch nicht warum).

Gibt es eine Möglichkeit, es intelligenter zu machen?

+0

+1 für nette Formatierung Ihrer Frage –

+0

.... WHERE ". $ Param." LIKE ....Generell was ich mit SQL-Anweisungen tun – Adsy2010

+1

Sie können Platzhalter für Spaltennamen nicht verwenden, soweit ich weiß, deshalb hat es nicht funktioniert. –

Antwort

3

Wenn Sie den gleichen SQL-Code für jeden param verwenden, nur einen Hash von möglichen params erstellen: (CGI param name => table column name)

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

Es ist viel besser von einem Gesichtspunkt der Sicherheit, wie Sie von SQL-Injection-geschützt sind.

erhalten dann die Spaltennamen aus dem Hash und in die Abfrage gestellt - und Sie werden von dem if-s los:

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

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

Wie @Akam sagte, keine Notwendigkeit zu CONCAT ("% ",?,"% ") in der Abfrage - es ist besser, den Wert mit Prozenten gleich rechts zu binden.

+1

keine Notwendigkeit, in der Abfrage zu concat, stattdessen: 'Bind_param ('s',"% $ Suche% ")' –

+1

@Akam Antwort verbessert – user4035

+0

Wirksam und sauber. Vielen Dank! – Renato

2

Gemäß diesem Beispiel in dem PHP-Handbuch

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

Sie scheinen am besten zu sein, das ‚%‘ auf das String-Variable hinzufügen Sie bindend sind - und nicht in der Abfrage z.B. In Ihrem Beispiel:

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(); 
} 

Haben Sie es nicht getestet, aber es scheint wie eine sinnvolle Lösung.

+0

Das wird sein Problem nicht lösen, einen dynamischen Feldnamen zu verwenden, aber es wird sein Beispiel in seiner Lösung darauf fixieren. –

+0

Sorry, du hast Recht, ich habe den Punkt verpasst. Ich würde einfach die Zeichenfolge $ param anstelle des Spaltennamens in die Abfragezeichenfolge einfügen. Ich würde jedoch einige ernsthafte Filterung auf den Inhalt zuerst z. $ unsafe_col_name = "/ [^ a-zA-Z0-9 \\\ _] /"; $ param = preg_replace ("$ unsafe_col_name", "", $ param); –

1

Sie können keine Platzhalter für Spaltennamen verwenden, daher müssen Sie die Spaltennamen normal verketten. Doch statt nur davon mit mysqli zu entkommen, da Sie eine begrenzte Anzahl von Spalten haben ich eine Weile Liste Ansatz würde vorschlagen:

$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.'; 

Beachten Sie auch die Entfernung der concat Anweisung, und statt in PHP verketten. Dies ist wichtig für vorbereitete Anweisungen, da es, sobald es den Server erreicht, es nicht wirklich kombiniert (also den Schutz vorbereiteter Anweisungen), so dass es nicht richtig funktioniert, wenn die Platzhalter nicht mit der Zeichenkette $search gesendet werden.