Bonjour,

Voila je rencontre un petit problème avec mon code.

Ce que je fais

J'ai un système de recherche que j'essais de sécuriser en PDO avec prepare et execute mais voilà lorsqu'il doit aller chercher l'information, il n'en trouve aucunes alors qu'il devrait car elle existe !

<?php
      $q = htmlspecialchars($_GET['q']);
      $c = htmlspecialchars($_GET['type']);

      $q_S = explode('+', $q);

      $D_sql = 'SELECT * FROM search WHERE ';
      $S_sql = '';
      $E_sql = '';
      $q_F = '';

      foreach($q_S as &$search)
      {
        if(strlen($search) >= 3)
        {
            $search = '"%'.$search.'%"';
            $S_sql .= 'b_title LIKE ? OR b_resume LIKE ? OR u_name LIKE ? OR u_lastname LIKE ? OR u_firstname LIKE ? OR b_author LIKE ? OR ';
            $E_sql .= $search.', '.$search.', '.$search.', '.$search.', '.$search.', '.$search;
            $q_F .= $search.' ';
        } else { /*Recherche trop courte*/ }
      }
    }

    $q_F = substr($q_F, 2, -3);
    $S_sql = substr($S_sql, 0, -3);
    $sql = $D_sql;
    $sql .= $S_sql;
    $sql = substr($sql, 0, -1);

    $reqSearch = $bdd->prepare($sql);
    $reqSearch->execute(array($E_sql));
    $rowSearch = $reqSearch->rowCount();

    //...

    if($rowSearch == 0) {
       //Aucun résultat
        echo 'Aucun résultat pour : '.$q_F;
    }
    else {
        //Pagination
        if($rowSearch == 1) { echo $rowSearch.' résultat pour : '.$q_F; }
        else { echo $rowSearch.' résultats pour : '.$q_F; }
    }
?>

L'info que recherche est JeremieMeunier qui dans ma BDD est la valeur d'une colonne u_name malheureusement, mon système me donne un $row de 0. J'aurais aimer savoir si vous aviez une idée du problème !

Merci par avance de votre aide !

12 réponses


E-Bismuth
Réponse acceptée

@Huggy oui je pensais a un truc comme ca!
@JeremieMeunier voila ce que moi j'aurais ecrit, car je trouve ton code peut claire et facielement hors de controle en cas de mise a jour successive

<?php
      $q = htmlspecialchars($_GET['q']);
      $c = htmlspecialchars($_GET['type']); //pas utilise?

      $q_S = explode('+', $q);

      $searchingFields = ['b_title','b_resume','u_name','u_lastname','u_firstname','b_author'];//plus simple si tu veux pouvoir ajouter par la suite des champs de recherche

      $S_sql = [];
      $E_sql = [];
      $q_F = [];

      $i=0;

    foreach($q_S as $search)
      {
        if(strlen($search) >= 3)
        {
            $S_sql[] = implode(" LIKE :value_$i OR ",$searchingFields)." LIKE :value_$i"; //les :value_$i vont me permettre de pouvoir preparer ma requetes en evoyant une seul valeur dans mon execute
            $E_sql["value_$i"] = '%'.$search.'%';//je construit mon tableau associatif que j'enverais tel quel dans mon execute (comme j'ai utiliser l'ecriture avec les : je peux mettre qu'une seule valeur pour tous les prepare de la ligne d'au dessus)
            $q_F[] = $search;
            $i++;

        }
        else { /*Recherche trop courte*/ }
      }

    if((count($S_sql) != 0) && (count($E_sql) != 0) && (count($q_F) != 0)){ //je verifie que mes array ne sont pas vide, pourquoi les 3? et pourquoi pas, si demains les array ne sont pas construit enssemble...
        $reqSearch = $bdd->prepare('SELECT * FROM search WHERE '.implode(' OR ',$S_sql));//j'imjecte ma ligne prepare dans mon prepare en separant chaque recherche par un OR
        $reqSearch->execute($E_sql);//j'envoi mon array associatif a mon execute
        $rowSearch = $reqSearch->rowCount();

        if($rowSearch == 0) {
           //Aucun résultat
            $response =  'Aucun résultat pour : '.implode(' ',$q_F);
        }
        else {
            //Pagination
            $response =  $rowSearch . (($rowSearch == 1)? 'résultat' : 'résultats')  .' pour : '.implode(' ',$q_F);
        }
    }
    else{
        $response = "Vous n'avez pas effectu de recherche ou chacune de vos recherche avait une longeur inferieur a 3 charactere";
    }

    echo $response;
?>
E-Bismuth
Réponse acceptée

Tu as fait une petite erreur d'inattention

if(strlen($search >= 4))

Au lieu de:

If(strlen($search)>=4)

Essaye d'inverser simple / double quote
par exemple :

$search = " '%" . $search . "%' ";

car dans le SQL le séparateur de chaine c'est la simple quote

J'ai essayer comme ça :

$search = '\'%'.$search.'%\'';

Ça ne fonctionne pas et j'ai essayer comme tu le proposait :

$search = "'%".$search."%'";

Ça fonctionne pas non plus !

Fais un echo de ta requête et si tu as un doute, colle la dans phpmyadmin.

comme tu passes tes arguments lors du execute, ceux-ci sont considérés par défaut comme des caractères (varchar)
donc :

$search = "%" . $search . "%";
ou bien
$search = '%' . $search . '%';

les simple quotes sont rajoutées automatiquement

Huggy bien je essayer de voire ça !

Je ne connais pas bien cette notation avec des ? Moi je met des :mavaleur et dans le execute un tableau associatif, je vois que tu envoies E_sql qui est un string. Ce serais pas ça le problème il faudrait pas envoyé un tableau de valeur

Après avoir regardé la doc http://php.net/manual/fr/pdo.prepared-statements.php
Je pense qu'il faut bien envoyé un tableau dans ton execute car dans l'exemple 2 il utilise deux Bindvalue (qui est la deuxième façon de faire pour passer les données)

@E-Bismuth Oui il faut passer un tableau mais ici la fonction array($E_sql) ne doit pas fonctionner, elle renvoie un tableau d'un seul élément !!!
il faudrait utiliser explode

$reqSearch->execute( explode(  ','   ,  $E_sql));

@E-Bismuth à la base $c, je m'en sert mais j'ai raccourcis le code pour le forum

if($c == 'all')
{
    foreach($q_S as &$search)
    {
        if(strlen($search) >= 3)
        {
            $search = '\'%'.$search.'%\'';
            $S_sql .= 'b_title LIKE ? OR b_resume LIKE ? OR u_name LIKE ? OR u_lastname LIKE ? OR u_firstname LIKE ? OR b_author LIKE ? OR ';
            $E_sql .= $search.', '.$search.', '.$search.', '.$search.', '.$search.', '.$search.', ';
            $q_F .= $search.' ';
        }
        else
        {
            //Recherche trop courte
        }
      }
}
elseif($c == 'book')
{
    foreach($q_S as &$search)
    {
            if(strlen($search) >= 3)
            {
              $search = '\'%'.$search.'%\'';

              $S_sql .= 'b_title LIKE ? OR b_resume LIKE ? OR b_author LIKE ? OR ';
              $E_sql .= $search.', '.$search.', '.$search;
              $q_F .= $search.' ';
            }
            else
            {
                //Recherche trop courte
            }
    }
}
elseif($c == 'author')
      {
        foreach($q_S as &$search)
        {
          if(strlen($search) >= 3)
          {
        $search = '\'%'.$search.'%\'';

        $S_sql .= 'u_name LIKE ? OR u_lastname LIKE ? OR u_firstname LIKE ? OR ';
        $E_sql .= $search.', '.$search.', '.$search;
        $q_F .= $search.' ';
          }
          else
          {
        //Recherche trop courte
          }
        }
      }

Voilà le bout de code qui utilise $c...

@Huggy et @E-Bismuth il faudrait que j'essaye de la façon dont vous me le proposer mais comme je bosse je ne peut m'y atteler que le dimanche et le mardi !

@E-Bismuth merci pour ton code, il fonctionne ! Voilà seulement j'ai un problème que je ne comprends pas !

<?php
      include('bdd.php');

      if(isset($test_1))
      {
    if(isset($_GET['q']) and !empty($_GET['q']))
    {
      $q = htmlspecialchars($_GET['q']);
      $c = htmlspecialchars($_GET['c']);

      $q_S = explode('-', $q);

      switch($c) {
        case 'all':
          $searchingFields = ['b_title','b_resume','u_name','u_lastname','u_firstname','b_author'];
          break;
        case 'author':
          $searchingFields = ['u_name','u_lastname','u_firstname'];
          break;
        case 'book':
          $searchingFields = ['b_title','b_resume','b_author'];
          break;
      }

      $S_sql = [];
      $E_sql = [];
      $q_F = [];

      $i = 0;

      foreach($q_S as $search)
      {
        if(strlen($search >= 4)) //Termes plus long que 3 lettres ou chiffre
        {
          $S_sql[] = implode(" LIKE :value_$i OR ",$searchingFields)." LIKE :value_$i";
          $E_sql["value_$i"] = '%'.$search.'%';
          $q_F[] = $search;
          $i++;
        }
        else
        {
          //Recherche trop courte
          echo '<b>'.$search.'</b> <em>['.strlen($search).']</em> est trop court ';
        }
      }

      if((count($S_sql) != 0) && (count($E_sql) != 0) && (count($q_F) != 0))
      {
        $reqSearch = $bdd->prepare('SELECT * FROM search WHERE '.implode(' OR ',$S_sql));
        $reqSearch->execute($E_sql);
        $rowSearch = $reqSearch->rowCount();

        if($rowSearch == 0)
        {
          //Aucun résultat
          echo 'Aucun résultat pour : '.implode(' ',$q_F);
        }
        else
        {
          //Pagination
          echo $rowSearch.(($rowSearch == 1)? ' résultat' : ' résultats').' pour : '.implode(' ',$q_F);
        }
      }
      else
      {
        http_response_code(400);
        echo 'Vous n\'avez fait aucune recherche';
      }
    }
    else
    {
      http_response_code(400);
      echo 'Les $_GET n\'existe pas !';
    }
      }
      else
      {
    http_response_code(400);
    echo 'Pas de BDD';
      }
?>

J'utilise strlen($search >= 4) il devrait lorsque je fait une recherche c=all&q=JeremieMeunier-cool, me trouver 2 chaîne suffisament longue pour faire fonctionner le système !

Lorsque j'echo la taille des chaine il me donne JeremieMeunier [14] et cool [4] donc jusque là c'est bon ! Sauf que avec le if il ne me prend pas les chaînes comme suffisament longue et passe directement à : C'est trop court !

Tester

J'ai essayer en changeant le >= en <= et la ça fonctionne il me fait la recherche et trouve 1 résultat comme c'est sensé faire !

Donc voilà, je n'y comprend plus rien !