2013-07-24 23 views
8

Attualmente ho un piccolo modulo di ricerca con solo due elementi: un input di testo denominato search e una casella "seleziona" denominata param. L'opzione selezionata all'interno di quella casella dovrebbe essere usata come parametro per scegliere quale colonna della tabella nel mio DB sarebbe stata recuperata.Come posso passare una variabile ad una clausola WHERE usando mysqli?

Utilizzando mysql_ funzioni, qualcosa di simile potrebbe essere fatto:

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

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

ma non riesco a farlo funzionare con la sintassi mysqli_. Sto cercando di utilizzare le istruzioni preparate, ma la migliore che ho fatto finora è questo:

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

Ma solo con un po 'di else if s sembra molto ripetitivo e improduttivo, specialmente se ho un sacco di colonne alle maniglia.

La prima cosa che ho provato è stata il collegamento dei parametri - ... WHERE ? LIKE ... e $prep->bind_param('ss', $param, $search) -, ma non ha funzionato (e non so ancora perché).

C'è un modo per farlo in un modo più intelligente?

+0

+1 per una buona formattazione della domanda –

+0

.... DOVE ". $ Param." MI PIACE ....in generale quello che faccio con le istruzioni sql – Adsy2010

+1

Non è possibile utilizzare i segnaposti per i nomi delle colonne, per quanto ne so, è per questo che non ha funzionato. –

risposta

3

Se si utilizza lo stesso codice SQL per ogni param, basta creare un hash di eventuali parametri: (CGI param name => table column name)

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

E 'molto meglio da un punto di vista della sicurezza, come si sono protetti da SQL injection.

quindi ottenere il nome della colonna dal hash e metterlo nella query - e si otterrà liberarsi del se-s:

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

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

Come ha detto @Akam, non c'è bisogno di CONCAT ("% ",?,"% ") nella query: è meglio associare il valore con le percentuali in avanti.

+1

non c'è bisogno di concatenare nella query, invece: 'bind_param ('s',"% $ search% ")' –

+1

@Akam Risposta migliorata – user4035

+0

Efficace e pulito. Grazie! – Renato

2

Secondo questo esempio nel manuale PHP

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

ti sembra di essere meglio per aggiungere il '%' nella variabile di stringa si sono vincolanti - piuttosto che nella query per esempio nel tuo esempio:

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

Non l'ho provato ma sembra una soluzione ragionevole.

+0

Questo non risolverà il suo problema di usare un nome di campo dinamico, ma risolverà il suo esempio nella sua soluzione. –

+0

Scusa, hai ragione, ho perso il punto. Sostituirei semplicemente la stringa $ param nella stringa della query anziché il nome della colonna. Tuttavia, applicherei un filtro serio sul contenuto, ad es. $ Unsafe_col_name = "/ [^ a-zA-Z0-9 \\\ _] /"; $ Param = preg_replace ("$ unsafe_col_name", "", $ param); –

1

Non è possibile utilizzare i segnaposto per i nomi di colonna, quindi sarà necessario concatenare normalmente i nomi delle colonne. Tuttavia, invece di fuggire con mysqli, perché si ha un insieme limitato di colonne io suggerirei un approccio lista, mentre:

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

Da notare anche la rimozione della dichiarazione concat, e invece concatenando in PHP. Questo è importante per le istruzioni preparate come una volta che arriva al server in realtà non le combina (quindi la protezione delle istruzioni preparate), quindi non funzionerà correttamente a meno che i caratteri jolly non vengano inviati con la stringa $search.