[PDO][PHP[MySQL] Piccolo modulo di ricerca in un sito tramite l'operatore LIKE

MarcoGrazia

Utente Attivo
15 Dic 2009
853
21
28
63
Udine
www.stilisticamente.com
Ciao,
questa mattina stavo diventando matto intorno ad un mio problema, programmando un piccolo motore di ricerca all'interno di un mio sito mi sono imbattuto in un problema che all'inizio non riuscivo a risolvere ma che una volta risolto ho deciso di condividere il risultato con voi, perché credo che a molti serva. Quindi ecco a voi: Il motore di ricerca dei poveri :jolly:

Il perché "dei poveri" mi pare ovvio, un motore di ricerca è molto più complesso di così e anche un record di database può avere al suo interno tanti campi su cui estendere la ricerca, campi che a volte non sono affatto omogenei, quindi prendetelo così com'è e tengo a precisare, dei poveri o meno, per chi ha un sito assistito da un database, comunque è un buon motore di ricerca che assolve egregiamente i suoi compiti, quindi procediamo.

Prima il semplicissimo modulo di ricerca in html:
HTML:
<form method="post" action="search.php">
<p>
  <label for="search">Cerca nel sito 
  <input type="text" id="search" name="search" value=""></label>&nbsp;
  <input type="submit" name="invia" value="cerca">
</p>
</form>
Come si vede il modulo di ricerca è un semplice form con un campo di testo e un pulsante di invio, lascio a voi la formattazione tramite CSS se vi interessa e persino il metodo di invio; io ho usato il POST ma nessuno vieta di usare il GET.
Per mia semplicità la pagina a cui punta è search.php, ovviamente la potete chiamare come vi pare, il modulo stesso può stare in ogni pagina del vostro sito, compresa search.php.

Ora la parte complessa, il PHP!
Utilizzerò i filtri per filtrare i dati riportati dal modulo e il PDO per connettermi al database.
Pagina search.php questa è solo la parte PHP che cerca, lascio a voi l'implementazione tramite CSS e HTML di come organizzare i dati visivamente.
PHP:
<?php
try {

//  Qui c'è la connessione al database, ovviamente il nome del database, dell'account e la password, sono affari vostri :)
function connetti() {
  $database = 'database';  // Fantasioso vero?
  $dsn = 'mysql:dbname=' . $database . ';host=localhost;charset=UTF8';
  $password = 'password';
  $user = 'utente';
  // LE opzioni no ve le spiego, troppo lungo, prendete per buone.
  $option = array( 
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_PERSISTENT => false,
    PDO::ATTR_AUTOCOMMIT => false,
    PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
    PDO::ATTR_EMULATE_PREPARES => true
  );
  // Connessione al database
  return new \PDO($dsn, $utente, $password, $options);
}

$errore = ''; // Inizializzo il flag d'errore.
// Verifico se c'è qualche cosa in POST e se c'è proseguo nella ricerca
if ( filter_has_var( INPUT_POST, 'invia' ) && filter_has_var( INPUT_POST, 'invia' ) == 'cerca' ) {
  $option = array( 'flags' => array('FILTER_FLAG_STRIP_LOW', 'FILTER_REQUIRE_ARRAY' ));
  $cerca = filter_input( INPUT_POST, 'search', FILTER_SANITIZE_STRING, $options );
  // Se in cerca c'è qualcosa proseguo
  if ( $cerca ) {    // C'è qualcosa e ora la cerco nel database.
    // La mia query ( Ovviamente ogni record ha le sue impostazioni, questo è solo un esempio )
    $sql = 'SELECT a.* FROM agenda AS a WHERE a.nome LIKE :nome OR a.indirizzo LIKE :indirizzo ';
    // Mi connetto al database
    $conn = connetti();
    $handle = $conn->prepare( $sql );
    $cerca = "%$cerca%";    //  Questa è la query di ricerca con le wildcard aggiunte.
    //  Sostituisco i segnaposto con la query, questa operazione fa anche l'escaping dei dati. E' importantissima.
    $handle->bindParam( ':nome', $cerca, PDO::PARAM_STR );
    $handle->bindParam( ':indirizzo', $cerca, PDO::PARAM_STR );
    $handle->execute();
    //  In $risultato... certo c'è il risultato se la ricerca è fruttuosa.
    $risultato = $handle->fetchAll( PDO::FETCH_ASSOC );
    // Chiudo tutto! Fatelo sempre, non affidatevi al PHP, chiudete sempre le connessioni aperte.
    unset( $conn, $handle, $cerca, $sql );
    // Verifico se la ricerca ha prodotto frutti.
    if ( $risultato ) {
      // Qui può esserci un ciclo che manda a video i risultati
      foreach ( $risultato as $r ) {
        echo "Nome: {$r['nome']} - indirizzo: {$r['indirizzo']}<br>";
      }
      //  LAscio a voi la formattazione tramite CSS e HTML
    } else {    //  Nessun dato trovato nel database.
      echo '<p>Non c'è nessun risultato per la parola cercata, mi spiace!</p>';
    }
  } else {    // Variabile vuota quindi c'è un errore e lo dico all'utente.
    $errore = '<p>Attento! Hai cercata una stringa vuota, riprova.</p>';
} else {
  $errore = '<p>Ci spiace ma nessun parametro soddisfa la ricerca! Nel database non c\'è nulla di quanto cercato!</p>';
}
//  Se si è verificato un errore lo mostro.
if ( $errrore != '' ) echo $errore;
}
catch ( PDOException $e ) { echo 'PDO:<br>' . $e->getMEssage(); }
catch ( Exception $e ) { echo 'Eccezione:<br>' . $e->getMEssage(); }
?>
Ho cercato di commentare il più possibile, ovviamente le domande già lo so sono tante, a iniziare dal database usato; ovvio, nessuno :) non ho immaginato un vero database, ognuno usa il suo, sì certo nella query ho dovuto immaginare un database agenda perché qualche cosa dovevo scrivere, ma non voglio condizionarvi.
Ho solo tenuto a farvi vedere che si può mettere la ricerca su più campi del record.
Il motore funziona, l'ho messo in molti miei siti e funziona, ovviamente qui ho dovuto fare un po' di modifiche per renderlo anonimo, semplice e astratto ma so già che ci sarà da lavorarci su.
Buon divertimento, Marco.
 
  • Like
Reactions: Alex_70
Piccola ma sostanziale modifica alla query! Utilizzo di CONCAT
SQL:
SELECT a.* FROM agenda AS a WHERE a.nome LIKE CONCAT('%', :nome '%') OR a.indirizzo LIKE :indirizzo
Che vuole dire all'atto pratico?
Semplice non si devono fare altre operazioni in PHP per inserire davanti e dietro la stringa gli opertori di ricerca, in questo caso %
Quindi si pò tranquillamente togliere la stringa $cerca
PHP:
$cerca = "%$cerca%";    //  Questa è la query di ricerca con le wildcard aggiunte.
dato che ora fa tutto l'SQL con CONCAT.
 

Discussioni simili