Collecting words from an input

Asked

Viewed 315 times

2

I am developing a page (study only) of a bookstore. The variable titulo_livro receives the data of a input type='text'.

What I need to do:

The title of the book will often contain more than one word. How do I collect these words, example ("O","Acopolato","Odysseus") and search them in the database?

The idea of the search is, when typing the full title of the book, the return of the comic can be for any of the words typed, since the words ("O","Acopolato","Odisseu") could, separately, be in the title of some other book.

  • WHERE COLUMN LIKE '%O%' OR COLUMN LIKE '%Acopolato%' OR .......

  • You will have to separate the words in PHP and make a query with BD criteria.

  • Okay, I get it. But for that, every word has to be saved in a separate column in the comic book, right? But it’s not so...?

  • Using LIKE '%palavra%' locates the word at the beginning, middle or end of the column value. Using LIKE 'palavra%' locates only at the beginning and LIKE '%palavra' locates only at the end. It is also possible to make combinations, for example find when you have two separate words LIKE '%palavra%outra%'.

2 answers

4


Can use LIKE and OR in the query and preg_split (equivalent to explode, but you can isolate more spaces without needing to filter) in PHP to split the string:

if (isset($_POST['busca']{0})) { //Tem que ter digita ao menos uma letra
    $buscas = preg_split('#\s+#', $_POST['busca']);

    ... aqui vai o código mysql, podendo usar a API PDO ou MSYQLI ...
}

If the form is POST use $_POST['busca'], if you don’t use $_GET['busca']

Note: if using UTF-8 read this post: Doubt with charset=iso-8859-1 and utf8


Using with MYSQLI

<?php

$mysqli = new mysqli('SERVIDOR', 'USUARIO', 'SENHA', 'BANCO');

if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit;
}

if (isset($_POST['busca']{0})) {

    $buscas = preg_split('#\s+#', $_POST['busca']);

    $qtdPalavras = count($buscas);

    //Gera os LIKEs
    $where = str_repeat('nome LIKE ? OR ', $qtdPalavras);
    $where = substr($where, 0, -4); // Remove o OR extra

    $query = 'SELECT id, nome, data FROM livros WHERE ' . $where . ' ORDER BY nome LIMIT 100';

    $stmt = $mysqli->prepare($query);

    if ($stmt) {

        //Adiciona os tipos de parâmetros
        array_unshift($buscas, str_repeat('s', $qtdPalavras));
        $qtdPalavras++;//Atualiza o total

        for ($i = 0; $i < $qtdPalavras; $i++) {

            //Evita adicionar o sinal de porcentagem no primeiro item, que são os tipos de parâmetros
            if ($i > 0) {

                //O sinal de porcentagem é necessário para busca em qualquer posição
                $buscas[$i] = '%' . $buscas[$i] . '%';
            }

            //Passa o valor como referencia (& - E comercial), pois bind_param não aceita variáveis normais
            $buscas[$i] = &$buscas[$i];
        }

        //Chava os valores da array como parametros
        call_user_func_array(array($stmt, 'bind_param'), $buscas);

        //Executa
        $stmt->execute();

        //Vá adicionando as colunas aqui que necessitar
        $stmt->bind_result($id, $nome, $ano);

        while ($stmt->fetch()) {
            echo 'Nome:', $nome, '<br>';
            echo 'Ano:', $ano, '<hr>';
        }

        $stmt->close();
    } else {
        die('Erro:' . $mysqli->error);
    }
}

The query as the search will generate in a POST like "O Acopolato Odisseu" something like:

SELECT id, nome, ano FROM livros WHERE nome LIKE ? OR nome LIKE ? OR nome LIKE ? ORDER BY nome LIMIT 100

Questions receive the values of bind_param and the bank will run something like:

SELECT id, nome, ano FROM livros WHERE nome LIKE '%O%' OR nome LIKE '%Acopolato%' OR nome LIKE '%Odisseu%' ORDER BY nome LIMIT 100

Using with PDO

If it’s PDO it should look something like this:

<?php
try {
    $pdo = new PDO('mysql:host=SERVIDOR;dbname=BANCO', 'USUARIO', 'SENHA');
} catch (PDOException $e) {
    die('Connection failed: ' . $e->getMessage());
}

if (isset($_POST['busca']{0})) {

    $buscas = preg_split('#\s+#', $_POST['busca']);

    $qtdPalavras = count($buscas);

    //Gera os LIKEs
    $where = str_repeat('nome LIKE ? OR ', $qtdPalavras);
    $where = substr($where, 0, -4); // Remove o OR extra

    $sth = $pdo->prepare('SELECT id, nome, data FROM livros WHERE ' . $where . ' ORDER BY nome LIMIT 100');

    if ($sth) {

        for ($i = 0; $i < $qtdPalavras; $i++) {
           $buscas[$i] = '%' . $buscas[$i] . '%';
        }

        $response = $sth->execute($buscas);

        if ($response) {
            while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
                echo 'Nome:', $row['nome'], '<br>';
                echo 'Ano:', $row['data'], '<hr>';
            }
        } else {
            echo 'Erro: ';
            var_dump($sth->errorInfo());
        }
    }
}
  • Excellent, I’m already trying here! Thank you very much. Soon less put the results.

  • @Lucasneves had some errors in mysqli, already corrected, I also added some explanations about utf-8 or iso-8859-1 and also fixed an issue in the example with PDO. Test them all, just adapt now to your.

  • Good afternoon! I adapted it to my code. Gave this error: Warning: preg_split(): Delimiter must not be alphanumeric or backslash in C: xampp htdocs dunevera visualizamprestimo2.php on line 10 Fatal error: Auguncht Error: Call to Undefined Function str_repeate() in C: xampp htdocs dunevera visualizaEmprestimo2.php:13 Stack trace: #0 {main} thrown in C: xampp htdocs dunevera visualizaEmprestimo2.php on line 13

  • FORM: <form method="post" action="visualizaEmprestimo2.php" class="form-group"> <div class="col-Md-3"> <select type="checkbox" class="form-control" name="active"> <option>Select...</option> <option value="1">Active</option> <option value="0">Inactive</option> </select> </div> <div class="col-Md-7"> <input type="text" class="form-control" placeholder="Book Title" name="title"> </div> <div class="col-Md-2"> <input type="Submit" class="btn btn-Primary" value="Query"> </div> </form>

  • @Lucas so I sent you the message, I already corrected it, it was 4 hours ago that I made the corrections, copy the codes again, I reviewed them and tested, now they are ok ;)

  • I just changed my brother! Unfortunately, the error persists: Warning: preg_split(): Delimiter must not be alphanumeric or backslash in C: xampp htdocs dunevera visualizaEmprestimo2.php on line 42

  • @Lucasneves looks at line 42, exactly like this preg_split('#\s+#',... ?

  • Now it is! And it worked! But a mistake still persists.. Can you decipher it? Fatal error: Uncaught Error: Call to Undefined Function str_repeate() in C: xampp htdocs dunevera visualizamprestimo2.php:45 Stack trace: #0 {main} thrown in C: xampp htdocdunes vera visualizaEmprestimo2.php on line 45

  • @Lucasneves this error is from the first version of the script I made, just copy the above code again, because the old code was in many problems. What are you using? With Pdo or mysqli?

  • My friend, thank you so much for your attention and patience. Everything is working perfectly now. Big hug and merry Christmas! OBS: since I’m new here, I didn’t first assume that I needed to click 'edited' to see the new edited text, kkkk. User error. kkkk

  • merry christmas @Lucasneves, and if you can mark the answer as you like I would be grateful if you do not know how to do it read: https://pt.meta.stackoverflow.com/a/1079/3635

Show 6 more comments

1

As stated in the commentary WHERE COLUNA LIKE '%O%' OR COLUNA LIKE '%Acopolato%' OR .......

With PDO

if (isset($_POST['nameInput'])){

  //verifica se só contém espaços
  if (trim($_POST['nameInput'])===''){

    echo "<span style=\"font-size: 24px; color: red\";>nananicanão, só espaço vazio não pode</span>";

  }else{

  $input = $_POST['nameInput'];

  //Substituindo vários espaços por um único espaço
  $titulo_livro= preg_replace('!\s+!', ' ', $input);

    $hostname="localhost";  
    $username="USUARIO";  
    $password="SENHA";  
    $db = "NOME_DB"; 

    $con = new PDO("mysql:host=$hostname;dbname=$db", $username, $password);

    $titulo_livro = strtoupper($titulo_livro);
    //Retira as tags HTML e PHP
    $titulo_livro = strip_tags($titulo_livro); 
    //Retira espaço no ínicio e final
    $titulo_livro = trim($titulo_livro);
    $words = explode(' ', $titulo_livro);

    $words_condition = array();
    $arguments = array();

    foreach ($words as $word) {
        $words_condition[] = 'nomeColuna LIKE ?';
        $arguments[] = '%'.$word.'%';
    }

    $query = $con->prepare('SELECT * FROM nomeTabela WHERE '.implode(' OR ', $words_condition));

    $query->execute($arguments);

    if ($query->rowCount() > 0) {

        while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
           //o que quer retornar relacione aqui
           echo 'Titulo:', $row['nomeColuna'], '<hr>';
        }
    }else{
       echo "<span style=\"font-size: 24px; color: red\";>Sua busca não retornou resultados</span>";
    }
  }
}   

with MYSQLI

We can build the statement as follows

//conexão
$servername = "localhost";
$username = "USUARIO";
$password = "SENHA";
$dbname = "NOME_DB";

$conn = new mysqli($servername, $username, $password, $dbname);
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}

//pego via POST
$titulo_livro = mysqli_real_escape_string($conn, Trim($_POST['nameInput']));

$palavras = explode(" ", $titulo_livro);

$clausulaWhere = '';
foreach( $palavras as $palavra) {
   $clausulaWhere .= ' nomeColuna LIKE "%' . $palavra . '%" OR';
}

// Remove ultimo 'OR'
$clausulaWhere = substr($clausulaWhere, 0, -2);

$sql = "SELECT * FROM nomeTabela WHERE" . $clausulaWhere;

//echo $sql; 
//para $titulo_livro = "O copolato Odisseu" resulta
// SELECT * FROM nomeTabela WHERE nomeColuna LIKE "%O%" OR nomeColuna LIKE "%copolato%" OR nomeColuna LIKE "%Odisseu%"


$result = $conn->query($sql);

while($row = mysqli_fetch_assoc($result)) {
    echo  $row["nomeColuna"]."<br>";
}
  • Thanks for the reply my friend. But I am using PDO.

  • @Lucasneves, is that in the question you did not specify this detail. I added PDO in my answer!

  • Curiosity, because you are editing all your answers in bulk like this?

  • @Articuno, I’m removing the functional examples

  • Why? Removing you does not mischaracterize the answers?

  • @Articuno, not mischaracterize, incidentally, some files no longer exist or were edited, same thing with those that depend on the database, some tables no longer exist. And for people to click on the functional examples and face error, I’m withdrawing.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.