Wiki Tuto - Chercher présence d'une sous chaîne dans une chaîne avec MySQL grâce à LIKE

1
25
fév.
2017

Introduction

Admettons que nous possédions une table "articles" contenant une cellule "quelleCategorie". Dans cette cellule nous indiquons une ou plusieurs catégories pour chaque articles comme dans l'exemple suivant :

    id | nomArticle | quelleCategorie | dateCreation
    1 | banane | fruits | 5
    2 | jus d'orange | jus de fruits | 9
    3 | tomate | fruits ; legumes | 22
    4 | maison | immobilier | 42

Admettons que nous désirons récupérer tout les articles ayant "fruit" dans "quelleCategorie". Avec l'option LIKE nous allons pouvoir spécifier un filtrage par motif (ou "pattern matching") afin de récupérer banane, jus d'orange et tomate et ce même si chacun possède une version légèrement différente de la catégorie.
À noter que vous pouvez aussi utiliser NOT LIKE qui vous permet de faire exactement l'inverse : demander à MySQL de ne retourner que les chaînes où n'est PAS présent le pattern.
Attention : une mauvaise utilisation de LIKE peut engendrer une chute des performances et une augmentation du travail pour le CPU du serveur MariaDB/MySQL.

L'exemple suivant va sélectionner dans la table "articles" tout les éléments ayant dans leur cellule "quelleCategorie" la sous-chaîne contenue dans la variable $categorieChoisie, classés du plus récent aux plus anciens.

<?php
$bdd_hostname = "localhost";
$bdd_name = "nomDeMaBase";
$bdd_login = "loginDeMaBase";
$bdd_password = "passowrdDeMaBase";
try {
    $bdd = new PDO('mysql:host='.$bdd_hostname.';dbname='.$bdd_name.';charset=utf8', $bdd_login, $bdd_password);
} catch( Exception $e){
    error_log("Error BDD connexion from ".$_SERVER["PHP_SELF"]);
}

$categorieChoisie = "fruit";

$requestSQL = $bdd->prepare('SELECT `*` FROM articles WHERE `quelleCategorie` LIKE %{:categorieChoisie}%  ORDER BY `dateCreation`');
$requestSQL->bindParam(':categorieChoisie', strval($categorieChoisie), PDO::PARAM_STR);
$requestSQL->execute();
$myArticles = $requestSomeArticles->fetchAll(PDO::FETCH_CLASS);
print_r($myArticles);
?>

Explication en détails :

  1. On tente de connecter PDO à la base de données, si on réussi on obtient l'objet $bdd si non on retourne une erreur dans les logs (/var/log/apache2/error.log pour apache2)
try {
    $bdd = new PDO('mysql:host='.$bdd_hostname.';dbname='.$bdd_name.';charset=utf8', $bdd_login, $bdd_password);
} catch( Exception $e){
    error_log("Error BDD connexion from ".$_SERVER["PHP_SELF"]);
}
  1. On défini notre sous chaîne à rechercher : fruit
$categorieChoisie = "fruit";
  1. On demande a PDO de préparer notre requête à partir de l'objet $bdd
$requestSQL = $bdd->prepare('SELECT `*` FROM articles WHERE `quelleCategorie` LIKE %{:categorieChoisie}%  ORDER BY `dateCreation`');
  • Ici on lui demande de tout (*) récupérer dans "articles" où "quelleCategorie" ressemble à la chaîne injectée, ordonnée (ORDER BY) par leur date de création.
  1. On injecte le paramètre de recherche (fruit)
$requestSQL->bindParam(':categorieChoisie', strval($categorieChoisie), PDO::PARAM_STR);
  1. On exécute la requête SQL
$requestSQL->execute();
  1. On récupère le résultat de la requête SQL sous forme d'objet
$myArticles = $requestSomeArticles->fetchAll(PDO::FETCH_CLASS);
  1. Si vous préférez récupérer sous forme de tableau, remplacez la précédente ligne par les suivantes
$myArticles = array();
while($tmpArticle = $requestSomeArticles->fetch(PDO::FETCH_ASSOC)){
    $myArticles[] = $tmpArticle;
}
  1. On affiche le résultat
print_r($myArticles);
  • # Autre façon

    Posté par . Évalué à 1 (+0/-0).

    Bonjour,

    Tout d'abord merci d'avoir partagé ces sympathiques tutos :)

    Je commente celui-ci car, sans être un spécialiste du php, il m'arrive de programmer des requêtes de ce type, mais dans un style assez différent du tien. En particulier, je n'utilise pas de connexion PDO (que je ne connaissais d'ailleurs pas), et donc l'injection de paramètre est superflue. Voilà comment je fais, en reprenant ton exemple :

    <?php
    $bdd_hostname = "localhost";
    $bdd_name = "Banana";
    $bdd_login = "pierre";
    $bdd_password = "";
    
    $bdd= mysqli_connect($bdd_hostname,$bdd_login,$bdd_password,$bdd_name)
    or error_log("Error BDD connexion from ".$_SERVER["PHP_SELF"]);
    
    $categorieChoisie = "fruit";
    
    $requestSQL = "SELECT * FROM articles WHERE quelleCategorie LIKE '%".$categorieChoisie."%' ORDER BY dateCreation";
    $result = mysqli_query($bdd,$requestSQL) or die(mysqli_error($bdd));
    $myArticles=mysqli_fetch_all($result);
    print_r($myArticles);
    ?>

    Maintenant je ne sais pas s'il y a un avantage à l'une ou l'autre méthode.

    • [^] # Re: Autre façon

      Posté par . Évalué à 2 (+0/-0). Dernière modification le 04/03/17 à 01:53.

      Le but des requêtes préparées (et donc de "l'injection" que j'utilise) c'est de lutter contre les failles SQL.
      En gros si je me rappel bien, avec les requêtes préparées si un utilisateur envoie du SQL dans une variable : se sera traité comme une chaîne de caractère ou tout autre type que l'on peut forcé dans la requête. (notons que je n'ai pas encore vérifié tient)

      PS: merci pour ton partage ;)

      Donation Bitcoin : 1N8QGrhJGWdZNQNSspm3rSGjtXaXv9Ngat

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.