Moteur de recherche PHP Objet (POO) complet (pagination, surlignage, fulltext…)

Mathieu Chartier Programmation 296 commentaires

Depuis plusieurs mois, je voulais prendre du temps pour créer mon propre moteur de recherche interne en PHP Objet (POO pour les intimes) afin de gagner du temps en cas de besoin dans des projets à venir. En effet, toute la force de la programmation orientée objet est de créer des « fonctions » prêtes à l’emploi qui demandent peu de lignes de code pour être utilisées (même si le développement procédural est tout aussi efficace en réalité, contrairement aux mythes faussement répandus). Dans le cas de mon moteur de recherche, je tenais absolument à avoir un résultat complet sur bien des points (qui seront cités par la suite) afin de répondre à un maximum d’éventualité. Après quelques heures de travail acharné, j’ai décidé de vous faire partager le code, en espérant qu’il fera le bonheur de pas mal d’entre vous (sachant que tout ce code peut encore être amélioré bien entendu)…

Edit (17/12/2018)

La page a été revue et corrigée pour correspondre par défaut à un usage classique du moteur de recherche pour PHP 5.5 et supérieurs (notamment PHP 7 et ses successeurs, bien plus performants). Le moteur fonctionne très bien jusqu'à PHP 7.3 actuellement, même si nul n'est parfait bien entendu.

Pour ceux qui veulent aller plus loin que les fonctionnalités présentes dans cet article, sachez que j'ai publié un autre article sur ce moteur pour proposer plusieurs types de pagination en Ajax (en infinite scroll ou par trigger). La dernière version publiée le 15 juillet 2015 fait également état d'une nouvelle fonctionnalité intéressante : la correction automatique des résultats.

N'hésitez pas à télécharger les packs du moteur de recherche car ils contiennent plusieurs cas d'usage détaillés, avec différentes options.

N.B. : il se peut que je supprime à terme la version pour PHP 4 et jusqu'à PHP 5.4 car ces versions de PHP sont obsolètes depuis quelques temps déjà. Je veux prendre le temps de réécrire l'ensemble du moteur de recherche mais cela dépend clairement de mon activité personnelle, qui ne me permet pas jusqu'à présent de pouvoir tout refaire comme je le souhaiterais. J'ai pas mal d'idées en tête donc je pense pouvoir faire bien mieux pour ce moteur dans les faits... ;-)

Les possibilités du moteur de recherche PHP

L’usage du moteur de recherche interne fonctionne parfaitement à partir du moment où vous disposez d’une base de données (bien construite si possible pour faciliter le traitement final), il ne s’agit pas ici d’un moteur comme Google ou Bing avec un robot d’indexation…

Voici une liste des possibilités offertes par les objets PHP (ou méthodes si vous préférez) qui concernent le traitement des requêtes, l’utilisation du code sera détaillée par la suite :

  • 3 méthodes de recherche : LIKE (approximatif), REGEXP (plus précis -> par défaut), FULLTEXT (l’idéal)
  • 2 types d’application de la recherche : exacte (tous les mots -> par défaut) ou non (un ou plusieurs mots justes)
  • Recherche précise (expression entre guillemets) ou non (mot à mot), quel que soit la méthode de recherche utilisée (normalement, cela ne fonctionne qu’avec FULLTEXT...)
  • Exclusion de mots (avec un tableau PHP de « stop words » -> un exemple fourni en téléchargement avec le code du moteur) et/ou de mots en dessous d’une certaine taille
  • Choix de l’encodage pour le traitement (UTF-8 par défaut et très fortement conseillé…)
  • Possibilité de rechercher sans accent après nettoyage de la requête (si la base de données n’a que des contenus sans accent bien entendu, sinon c’est inutile -> désactivé par défaut)

N.B. : si vous souhaitez utiliser la méthode FULLTEXT, il faut absolument ajouter des index FULLTEXT dans les colonnes de la base de données à partir desquelles vous souhaitez effectuer une recherche. J’ai pensé à vous en créant la class PHP « alterTableFullText » pour générer les index sans passer par PhpMyAdmin ou autre SGBD… C’est pour cette raison que je n’ai pas mis FULLTEXT par défaut…

Le moteur de recherche PHP dispose aussi d’un objet spécifique à l’affichage des résultats qui offre également plein de possibilités :

  • Appel d’une fonction d’affichage (« callback ») obligatoire
  • Choix des colonnes de sélections en SQL plutôt que de tout prendre (* -> par défaut)
  • Ajout ou non d’une clause LIMIT en SQL (tableau avec trois arguments)
  • Ajout ou non d’une clause ORDER BY en SQL (tableau avec trois arguments)
  • Utilisation ou non de mon algorithme de pertinence (simple) personnalisé (tableau à 4 arguments), sachant qu’il peut être couplé avec l’ORDER BY précédent si besoin
  • Personnalisation ou non de la fin de requête (ajout de vos propres clauses après le WHERE telles que AND…, AS…, ORDER BY…, LIMIT…)

Comme tout ne serait pas assez complet ainsi, j’ai également créé une class PHP pour afficher une pagination. Tout est à paramétrer pour que le résultat soit parfait mais cela fonctionne bien, la fonction a été reprise sur le site seebz.net mais je l’ai totalement réadaptée au moteur de recherche et je lui ai ajouté des options pour que chacun puisse faire ce qu’il souhaite…

Enfin, j’ai créé une class PHP à part pour permettre de surligner les mots et expressions recherchées si désiré, de manière exacte (juste la chaîne précise) ou complète (la chaîne + les lettres environnantes si elles existent). Dans tous mes tests, cela fonctionne parfaitement mais je reste prudent car la méthode est basée sur des expressions régulières (REGEX) et nous ne sommes jamais sûr de rien lorsqu’elles sont complexes… La class doit être utilisée au sein de la fonction « callback » d’affichage des résultats !

N.B. : Toutes les class et méthodes importantes sont détaillées à la fin et entièrement commentées dans les codes sources à télécharger

Télécharger “Pack complet - moteur de recherche PHP 5.5 - PHP 7”moteurPHP5.5.zip – Téléchargé 41747 fois – 171,49 Ko

Télécharger “Pack complet - moteur de recherche (PHP 4 - PHP 5)”moteurPHP4-PHP5.zip – Téléchargé 8466 fois – 142,47 Ko

Télécharger “Classe PHP 5.5 et PHP 7 du moteur de recherche”moteur-php5.5.class-inc.zip – Téléchargé 4767 fois – 13,47 Ko

Télécharger “BDD PHP 5.5 et PHP 7”BDD-PHP5.5.class-inc.zip – Téléchargé 3904 fois – 426,00 o

Télécharger “Liste et tableau des “stop words””stopwords.zip – Téléchargé 4907 fois – 2,32 Ko

Moteur de recherche PHP objet avec FullText, LIKE et Regexp, pagination, surlignage des mots clés...

Usage complet du moteur de recherche (codes à l’appui)

Tout est commenté dans le code source, mais pour plus de simplicité, je vous fournis quelques explications afin que vous puissiez tirer profit du moteur de recherche sans trop de complication. Je vais me baser sur un exemple totalement fictif pour vous montrer quoi faire...

1/ Inclusion des fichiers (Connexion BDD + Class du moteur de recherche + liste des « stop words »)

<?php
include_once("CHEMIN-URL/BDD.class-inc.php"); // Fichier de connexion à la base de données (optionnel)
include_once("CHEMIN-URL/stopwords.php"); // Fichier contenant un tableau $stopwords pour les "stop words" (optionnel)
include_once("CHEMIN-URL/moteur-php5.5.class-inc.php"); // Class du moteur de recherche PHP et autres
?>

 2/ Connexion BDD (avec ma méthode personnalisée, cela fonctionne avec PDO, etc.)

<?php
// Gestion de la connexion SQL (avec ma méthode personnalisée) --> Pour PHP 5.5 et PHP 7
$base    = "mabase"; // Nom de la base de données (BDD)
$serveur = "localhost"; // Nom du serveur de BDD
$login   = "root"; // Login de la BDD ("root" pour Wamp et Xampp)
$passe   = ""; // Mot de passe de la BDD (vide pour Wamp et Xamp, "root" pour Mamp)

$link = new mysqli($serveur, $login, $passe, $base); // Connexion
// En cas d'erreur
if (mysqli_connect_error()) {
	die('Connexion impossible à Mysql ('.mysqli_connect_errno().') : '.mysqli_connect_error());
}
?>

3/ Exemple de formulaire de recherche complet (avec "hidden" pour la pagination et le LIMIT)

<form id="searchForm" name="moteurSubmit" method="GET" action="">
        <label for="moteur">Rechercher :</label>
        <input type="text" value="<?php if(isset($_GET['moteur'])) { echo htmlspecialchars($_GET['moteur']); } ?>" name="moteur" id="moteur" />
        <input type="submit" value="Envoyer" />
</form>

 4/ En cas de soumission du formulaire de recherche (if...)

<?php
// Placez de préférence cette partie au-dessus du DOCTYPE sous les inclusions et la connexion BDD
if(isset($_GET) && !empty($_GET['moteur'])) {
/*
// Appel de la class moteurRecherche (9 pour PHP 5.5 et PHP 7, 8 pour les versions inférieures)
0. VERSION PHP inférieur à 5.5 : premier paramètre en moins ($link dans l'exemple commenté ci-dessous)
1. requête de recherche ($_GET['moteur'] avec stripslashes() par sécurité) -> OBLIGATOIRE
2. table de la base de données dans laquelle chercher -> OBLIGATOIRE
3. mode de recherche (like, regexp ou fulltext) -> REGEXP par défaut
4. tableau contenant des stop words ($stopwords ici)
5. nombre entier pour exclure les mots plus petits ou égaux que cette taille (si vide, aucune exclusion -> par défaut)
6. encodage souhaité (utf8, utf-8, iso-8859-1, latin1...) -> UTF-8 par défaut
7. booléen (true/false) pour choisir entre la recherche exacte (tous les mots) ou non (un mot juste ou plusieurs) -> TRUE par défaut
8. booléen (true/false) pour faire des recherches sans accent (si les contenus sont entrés sans accent dans la BDD) -> FALSE par défaut
*/
    $moteur = new moteurRecherche($link, stripslashes($_GET['moteur']), 'TABLE_SQL', 'regexp', $stopwords);
    // PHP 4 et PHP 5.5- : $moteur = new moteurRecherche(stripslashes($_GET['moteur']), 'TABLE_SQL', 'regexp', $stopwords);

    // tableau des colonnes dans lesquelles effectuer une recherche
    $colonnesWhere = array('titre', 'description');

    // Lancement de la class moteurRequetes() pour générer les requêtes de recherche
    $moteur->moteurRequetes($colonnesWhere);
}
?>

5/ Affichage des résultats (dans la même page ici !)

  • Fonction Callback d’affichage des résultats de recherche (appelée affichage() ici)
  • Lancement de l’objet faisant appel à la fonction Callback (avec plusieurs paramètres possibles)
  • Appel à l’objet de pagination (entièrement paramétrable)

Ce bloc doit être intégré à l'endroit où vous souhaitez afficher les résultats dans la page...

<?php
if(isset($moteur)) {
    // Affichage de la requête avec $moteur->requete
    echo '<h3>Résultats de la recherche : <em>'.$moteur->requete.'</em></h3>';

/*
Fonction "callback" pour l'affichage des résultats (3 arguments obligatoires)
1. Requête de recherche (variable au choix...)
2. Nombre total de résultats (variable au choix...)
3. Liste des mots et expressions de la requête (variable au choix...)
*/
    function affichage($requete, $nbResults, $mots) {
	if($nbResults == 0) { // Si aucun résultat n'est retourné
	    echo "<p>Aucun résultat, veuillez effectuer une autre recherche !</p>";	
	} else { // Sinon on affiche les résultats en boucle

            // Afficher le nombre de résultats
	    $affichageResultats = new affichageResultats();
	    echo $affichageResultats->nbResultats(true);

            // Comptage dynamique du nombre de résultats
	    if(isset($_GET['p'])) {
		$nb = $nb + (10 * ($_GET['p'] - 1));
	    }

	    while($key = mysqli_fetch_assoc($link, $requete)) {
                // On encode chaque clé/valeur de résultats en UTF-8
                foreach($key as $k => $v) {
                     $key[$k] = utf8_encode($v);
                }

                // Résultats de recherche à afficher (à personnaliser)
                $texte  = "<br/>".$key['titre']."<br/>";
                $texte .= $key['contenu']."<br/>";

                /*
                Objet pour surligner les mots recherchés si nécessaire
                => 3 arguments (les deux premiers sont obligatoires)
                1. variable contenant les mots ($mots ici)
                2. variable contenant le texte ($texte ici)
                3. "exact" (la chaîne précise mise en gras) ou "total" (la chaîne précise + environnante en gras) -> "exact" par défaut
                */
                $surlignage = new surlignageMot($mots, $texte);
                echo $surlignage->contenu; // Affichage du contenu après surlignage
                // N.B. : echo $texte; si vous ne voulez pas de surlignage...
	    } // Fin de la boucle while
	}
    }

// Nombre de résultats par "tranche d'affichage"
$limit = 10;

// Numéro de page récupéré dynamiquement
if(isset($_GET['p'])) {
	$page = htmlspecialchars($_GET['p']);
} else {
	$page = 0;
}

/*
Lancement de la class moteurAffichage
1. appel à la fonction callback d'affichage entre guillemets (obligatoire)
2. colonnes à sélectionner dans la base (toutes s'il est laissé "vide")
3. LIMIT en SQL -> tableau avec 4 valeurs : true/false, numDépart ($_GET['page'] ici pour la pagination dynamique), nbResultatsParPage (4 ici), true/false (true pour pagination classique, false pour autre) -> Par défaut array(false, 0, 10, false)
4. ORDER BY : tableau avec 3 valeurs : true/false, colonne d'ordre, ASC/DESC -> par défaut array(false, 'id', 'DESC')
5. ORDER BY avec algorithme de pertinence -> tableau avec 4 valeurs : true/false, colonne de classement (inédite !), ASC/DESC, colonne de l'ID -> Par défaut array(false,'algo','DESC','id')
N.B. : la fonction ajoute la colonne de classement si elle n'existe pas !
6. Fin de requête personnalisable (après le WHERE) : avec ORDER BY, LIMIT, AND
*/
$moteur->moteurAffichage('affichage', '', array(true, $page, $limit, true));

/*
Lancement de la méthode de pagination
1. OBLIGATOIRE : variable de récupération de la page ($page pour $_GET['p'] ici)
2. OBLIGATOIRE : nom du paramètre GET pour la page (situé dans l'input "hidden") -> 'page' ('p' dans l'exemple)
3. nombre de pages affichées autour de la page courante -> 2 par défaut
4. nombre de liens (premières et dernières pages) à afficher (0 pour annuler l'option) -> 0 par défaut
5. booléen (true/false) pour afficher ou non "page suivante" et "page précédente" -> true par défaut
6. booléen (true/false) pour afficher ou non "première page" et "dernière page" -> true par défaut
7. tableau qui contient les éléments de mise en forme (8 args)
=> textePrécédent, texteSuivant, textePremierePage, texteDernierePage, classPrecSuiv, classPage, classBloc, classInactif
-> défaut : array('&laquo; Précédent', 'Suivant &raquo;', 'Première page', 'Dernière page', 'precsuiv', 'current', 'pagination', 'inactif')
8. tableau qui contient les séparateur (5 args) 
=> pointSuspension, sepPremiereDernierePage, $sepNumPage, sepSuivPrec, sepDebutFin
-> Défaut : array('&hellip;', ' ', ' ', ' ', ' ')
*/
$moteur->moteurPagination($page, 'p');
}
?>

Vous devriez avoir un moteur de recherche fonctionnel avec tous ces codes, je vais tout de même terminer cet article en détaillant un peu plus quelques fonctionnalités du moteur et en proposant des pistes d'évolutions. Pour ceux qui sont déjà satisfaits, merci pour votre lecture.

N.B. : depuis la version 1.5 du moteur, il est possible d'afficher le nombre de résultats total et le nombre par page à l'aide de la class fille en PHP Objet appelée affichageResultats(). Il suffit d'appeler la méthode nbResultats() de la class au sein de la fonction Callback d'affichage (comme dans l'exemple ci-dessus).

Algorithme de pertinence (simple)

L'algorithme de pertinence que j'ai créé est tout simple, mais il donne des idées d'évolution pour la suite. Pour être tout à fait franc, c'est l'algorithmie qui m'a donné envie de développer ce moteur de recherche en PHP objet, je voulais trouver un moyen de classer les résultats différemment d'un ORDER BY classique en SQL.

L'algorithme est activé lorsque le 5e argument de la class moteurAffichage() est présent. Il s'agit d'un tableau contenant 4 paramètres obligatoires :

  • booléen (true/false) pour activer ou non l'algorithme
  • nom d'une colonne SQL pour accueillir les valeurs de classement ('algo' par défaut). Cette colonne est créée dans la table si elle n'existe pas...
  • type de classement : ASC (ascendant) ou DESC (descendant)
  • intitulé de la colonne d'identifiant ('id' en général, mais attention à la casse ou à un nom différent...)

La pertinence se fait ici de manière simple. Le moteur analyse la requête de l'utilisateur puis compte dans les contenus le nombre d'occurrences des mots et expressions. Une fois les comptes réalisés, l'option met à jour la colonne de la base de données ('algo' par défaut) puis classe les résultats en fonction de la valeur attribuée. En d'autres termes, il s'agit d'une partie du tri par pertinence très connu des référenceurs.

J'ai ajouté deux possibilités en cas d'activation de l'algorithme :

  • le classement se fait uniquement par pertinence
  • le classement se fait par pertinence mais aussi avec un autre ORDER BY si le 4e argument de la class (tableau) est activé (true). Dans ce cas, cela permet par exemple de classer par pertinence puis par ID ou autre...

Détail de la class « alterTableFullText »

Si vous voulez utiliser le moteur FULLTEXT, il est impératif que les colonnes dans lesquelles nous voulons chercher ait des index FULLTEXT dans la base de données. Comme tout le monde n'est pas "expert" en SQL, j'ai créé une class spécifique pour ajouter un index FULLTEXT aux colonnes. Il faut aussi que la table utilise "l'engine" MyISAM et non INNOdb comme cela est parfois le cas dans le monde du web, la class convertit en MyISAM automatiquement...

En réalité, l'index FULLTEXT est ajouté uniquement s'il n'existe pas déjà pour la (ou les) colonne(s) sélectionnées. La fonction peut donc être laissée dans le pire des cas, bien que l'idéal soit de la lancer la première fois pour ajouter les index FULLTEXT, puis ensuite de la retirer car elle deviendrait dès lors inutile (cela évite une surcharge de traitement pour rien).

L'idéal est de la lancer juste avant la class moteurRequetes() et juste après le tableau des colonnes de recherche (appelées $colonneWhere dans l'exemple précédent).

$colonnesWhere	= array('titre', 'contenu');
$alterTable = new alterTableFullText($link, 'mabase', 'matable', $colonnesWhere);
// PHP 4 et 5.5- : $alterTable = new alterTableFullText('mabase', 'matable', $colonnesWhere);
$moteur->moteurRequetes($colonnesWhere);

Dans notre cas, nous avons utiliser un tableau contenu les colonnes mais nous pouvons aussi utiliser une chaîne de caractères avec les noms de colonne séparées par des virgules. Ainsi, nous aurions très bien pu avoir $colonneWhere = "titre, contenu"; mais malheureusement la variable ne fonctionnerait plus pour la class moteurRequetes ici (car elle attend un tableau).

Détail de la class « surlignageMot »

La class surlignageMot permet de mettre en gras les mots rechercher. Elle prend cinq paramètres (seuls les deux premiers sont obligatoires). Pour ceux qui avaient déjà téléchargé le moteur de recherche, sachez que l'ancienne version de la class ne prenait que trois paramètres et manquait de précision... Voici donc les cinq arguments de la class surlignageMot :

  • Les chaînes de caractère (mots et/ou expressions) à mettre en gras
  • Le texte dans lequel mettre en gras les chaînes de caractères
  • la méthode de mise en gras (voir en dessous pour les précisions)
  • le degré d'exactitude de la recherche (comme pour le moteur de recherche) : "true" pour la recherche des mots complets correspondant à la requête, "false" pour trouver les mots contenant les chaînes de caractères de la requête (exemple : les mots comme "mode", "demain" ou "céder" contiennent tous la chaîne "de")
  • le type de recherche (le même que pour la class moteurRecherche) : "FULLTEXT", "REGEXP" ou "LIKE"

N.B. : les deux derniers paramètres doivent reprendre ceux fixés dans la class moteurRecherche, ils ont été ajoutés pour obtenir de bien meilleurs résultats en matière de mise en gras des mots clés recherchés. Ainsi, la mise en gras est idéale selon le type de recherche, l'exactitude souhaité et la méthode choisie (voir ci-dessous).

Volontairement, j'ai créé deux méthodes de mise en gras :

  • "exact" (par défaut) permet de mettre en gras la chaîne de caractère précise sans tenir compte de ce qui l'entoure (par exemple, si nous cherchons la chaîne "mot" avec la méthode LIKE, le moteur afficherait "moteur de recherche", "motoculteur"... selon les mots trouvés)
  • "total" (ou "complet") permet de mettre en gras la chaîne précise et son environnement proche (pour reprendre notre exemple, la recherche de la chaîne "mot" avec la méthode LIKE afficherait "moteur de recherche" et "motoculteur"). La différence ici est de mettre en gras les mots qui contiennent la chaîne recherchée (utile pour la méthode LIKE notamment).
// Surlignage exact (par défaut)
$surlignage = new surlignageMot($mots, $texte, "exact", true, "REGEXP");

// Surlignage total ("total" ou "complet") --> surtout utile pour la recherche LIKE (ou avec false et "REGEXP") !
$surlignage = new surlignageMot($mots, $texte, "total", true, "LIKE");

// N.B. : attention à la casse pour le type de recherche choisie, cela peut causer des erreurs !!

Détail de l’objet « moteurPagination »

L'objet moteurPagination() permet d'utiliser un système de pagination sans avoir à tout coder à la main et à adapter. La méthode a totalement été mise en place pour fonctionner avec le moteur de recherche PHP sans problème. Elle ne fonctionne qu'avec la méthode GET et utilise 7 arguments :

  • Le nom du paramètre GET de la page ('page' par défaut) qui a été intégré dans l'input type "hidden" du formulaire.
  • Le nombre de pages affichées autour de la page courante en surbrillance (2 par défaut). Par exemple, si nous voulons afficher "... 1 2 3 ...", il faut mettre 1 en valeur, tandis que 2 permet de faire quelque chose comme "... 3 4 5 6 7 ...".
  • L'affichage de liens pour les premières et dernières pages (0 pour aucun lien, par défaut). Par exemple, une valeur de 1 permet de faire quelque chose du type "1 ... 4 5 6 7 8 ... 17" et une valeur de 2 "1 2 ... 4 5 6 7 8 ... 16 17".
  • Un booléen (true/false) pour afficher ou non "page suivante" et "page précédente"
  • Un booléen (true/false) pour afficher ou non "première page" et "dernière page"
  • Un tableau qui contient les éléments de mise en forme (8 args) dans l'ordre : texte "Précédent", texte "Suivant", texte "Première page", texte "Dernière page", class CSS des liens, class CSS du lien actif (page courante), class CSS du bloc de pagination, class CSS quand le lien est inactif.
  • Un tableau qui contient les séparateur (5 args) dans l'ordre : points de suspension, après "première page" et avant "dernière page", entre les numéros de page, après "précédent" et avant "suivant", après lien(s) de début et avant lien(s) de fin. Hormis les points de suspension qui ont un intérêt, les autres séparateurs ont peu de rôle si vous utilisez du style CSS, c'est pourquoi ils sont laissés vides par défaut.

Voici quelques exemples d'usage de l'objet moteurPagination() selon des réglages différents :

Class PHP (POO) de pagination pour moteur de recherche PHP

N.B. : la dernière page n'affiche pas uniquement les dernières résultats, elle "remplie" l'espace avec des résultats déjà cités dans la page précédente si nécessaire (en d'autres termes, si on paramètre à 10 résultats par page, la dernière page affichera 10 résultats, quitte à en reprendre quelques-uns de la page précédente !).

Voici le style CSS utilisé dans les exemples :

.pagination {margin:1.5em 0 0 0; line-height:2em;}
.pagination a, .pagination span {padding:0.2em 0.5em 0.3em;}
.pagination a {border:1px solid #108c98; border-radius:5px; color:#108c98; text-decoration:none;}
.pagination a:hover {border:1px solid #108c98; background:#108c98; color:#fff;}
.pagination .precsuiv {font-weight:bold;}
.pagination span.inactif {border:1px solid #ccc; border-radius:5px; color:#ccc;}
.pagination span.current {border:1px solid #108c98; background:#108c98; border-radius:5px; color:#ffffff; font-weight:bold;}

Détail de la class « autoCompletion »

La version 2.0 de la class du moteur de recherche PHP apporte une nouvelle fonctionnalité intéressante. Outre les quelques nettoyages du code, cette version a mis au jour la possibilité d'ajouter un système d’auto-complétion (comme sur Google). Voici les possibilités autorisées :

  • Possibilité de créer une table d'index inversé pour le moteur de recherche (l'index inversé contient les mots clés et les expressions qui serviront à l'auto-complétion).
  • Possibilité d'ajouter automatiquement les mots recherchés dans l'index inversé au fur et à mesure des recherches des internautes. En effet, sauf si vous avez déjà créé une table rempli de mots et expressions, il faudra opter pour cette option afin que la table se génère de manière autonome et permette d'afficher des résultats lors de l'auto-complétion.
  • Possibilité de suggérer des mots seulement pour le premier mot tapé ($multiple = false) ou pour tous les mots ($multiple = true).
  • Possibilité de modifier le nombre de résultats affichés dans la zone d'autocomplétion.
  • Possibilité de choisir le type d'autocomplétion dans le moteur de recherche ($type = 0 pour démarrer en début de mot ou $type = 1 pour suggérer des mots contenant les lettres tapées).
  • Possibilité d'utiliser un système d'autofocus qui surligne directement la première proposition (déconseillé toutefois...).
  • Possibilité de choisir à partir de combien de caractères les mots seront ajoutés dans l'index inversé (si l'index est généré automatiquement !)

Voici mon conseil pour ceux qui n'auraient pas créé une table d'index inversé :

  • Créez dans un premier temps l'index inversé du moteur de recherche PHP avec l'option $create = true; puis passez l'option sur "false" ensuite.
  • Optez pour la génération automatique de l'index (même si vous avez déjà rempli des mots dans une table à vous) en utilisant la méthode PHP autoComplete().
  • Mettez le paramètre $minLength à 2 au moins pour éviter que des mots courts soient ajoutés dans l'index inversé (peu de pertinence dans ce cas !).

N.B. : la méthode d'ajout automatique des mots dans le système d'auto-complétion ne rajoute pas tous les mots, elle vérifie d'abord s'il existe déjà dans la table de l'index inversé et si ce n'est pas le cas, le terme est rajouté (de même pour les expressions entre guillemets).

Moteur de recherche PHP objet (POO) - Auto-complétion

1/ Ajout des scripts jquery.js et jquery.autocomplete.js dans le HEAD

<script src="CHEMIN/jquery.js"></script>
<script src="CHEMIN/jquery.autocomplete.js"></script>

2/ Ajout du style CSS (avec le fichier jquery.autocomplete.css ou non)

<link rel="stylesheet" href="CHEMIN/jquery.autocomplete.css" />

3/ Mise en place de l'auto-complétion pour le moteur de recherche PHP

Sachez qu'il est nécessaire d'ajouter les identifiants de connexion également dans le fichier autocompletion.php (ou de refaire une connexion à la base avec votre propre système si vous préférez).

// PLACER CE MORCEAU DE CODE APRES $connect = new ConnexionBDD($base, $serveur, $login, $passe); ABSOLUMENT !
// 4 paramètres obligatoires sur 10 disponibles
// N.B. : tous les paramètres sont décrits dans les fichiers de la class
$autocompletion = new autoCompletion($link, "CHEMIN/autocompletion.php", "#moteur", "NOM_DE_LA_TABLE", "NOM_DE_LA_COLONNE");
// Sans "$link" pour PHP 4 et PHP 5.5-

4/ Utilisation (optionnelle) de l'outil d'ajout automatique des nouveaux mots clés et des expressions

if(isset($moteur)) {
    /* ... CODE ... */
    // Juste au dessus : $moteur->moteurAffichage('affichage', '', array(true, $page, 10, true));
    // Juste au dessus : $moteur->moteurPagination($page, 'p');
    $autocompletion->autoComplete(stripslashes($_GET['moteur']));
}

Débogages et évolutions possibles

Il ne faut pas se le cacher, un tel moteur de recherche fourmille de petites options qui paraissent invisibles pour ceux qui ne plongeraient pas dans le code. En réalité, il faut penser à plein de points importants pour que l’ensemble de la machine soit fonctionnel et ne soit pas (trop) bogué.

Globalement, j’ai corrigé tous les principaux bugs que j’ai pu rencontrer :

  • Problème d’encodage, que ce soit en UTF-8 ou ISO-8859-1, car nous devons bien construire nos base de données (en MySQL notamment) et parfois traiter les informations dans la fonction d’affichage avec la fonction utf8_encode().
  • Problème avec la clause LIMIT pour la pagination car cette dernière part à la page 1 alors que le point de départ normal est 0. Etant donné que mon système permet d’utiliser ou non la pagination, je devais trouver un remède miracle et c’est en place.
  • Problème des index FULLTEXT pour les colonnes sélectionnées pour la recherche résolu grâce à la class « alterTableFullText ».
  • Gestion des échappements de caractères spéciaux (guillemets, apostrophes, slashs…) et de quelques signes (« + », « * »).
  • Problème des mots composés. En effet, un mot comme « faux-plafond » correspond à deux mots pour un moteur classique, soit « faux » et « plafond ». J’ai fait en sorte que les mots composés soient traités comme une expression exacte.
  • Possibilité d’ajouter les colonnes SELECT de son choix plutôt que de faire systématiquement un « * » qui abaisse parfois les performances.
  • Débogage des problèmes d’attributs HTML lorsqu’un mot cherché est présent dans la chaîne et que le surlignage est utilisé. Par exemple, si je cherche le mot « google » et que ce dernier est contenu dans une URL (href ou src), il se met en gras (<strong>…</strong>) et bloque donc le fonctionnement. Désormais, la mise en gras est supprimée dans plusieurs attributs HTML pour éviter tout risque…
  • Quelques bugs avec la mise en gras lorsqu'un mot était accolé à une virgule, à un point ou à une parenthèse par exemple.
  • Résolution de problèmes avec la recherche PHP en REGEXP (certains signes bloquaient les expressions régulières).
  • Débogage des recherches en lettres capitales accentuées.

Moteur de recherche PHP objet avec FullText, LIKE et Regexp, pagination, surlignage des mots clés...

Toutefois, quelques points peuvent encore être plus poussés, je vous laisse coder un peu même si je mettrais peut-être (sûrement) à jour les fichiers présents dans cet article lorsque j’aurais des idées :

  • Amélioration possible de la recherche FULLTEXT à cause du paramètre ft_min_word_len de my.ini (MySQL) qui ignore les mots de 1 à 3 caractères automatiquement (paramétrable sur un serveur dédié mais pas sur un hébergement mutualisé...).
  • Algorithme de pertinence à faire évoluer pour plus de précision dans les résultats et dans l’ORDER BY associé…
  • Gestion des requêtes qui peut être améliorée. Actuellement, cela prend en compte les expressions entre guillemets et les mots seuls, je n’ai pas envisagé de gérer les « + » et les « - » ni les « AND » et « OR » par exemple, mais cela pourrait se faire (le problème étant que ce système ne fonctionne qu’avec la recherche FULLTEXT et pas les autres…).
  • Gestion de la sécurité, bien que les données doivent être traitées en amont pour plus de confort. Le minimum a été fait pour protéger l'ensemble, mais ce point peut être amélioré…

La capture ci-dessous montre un problème (désormais résolu) qui avait lieu avec l'ancienne version de la class du moteur de recherche lorsque nous cherchions des chaînes courtes telles que "le", "de" (...). En fait, il s'agissait essentiellement d'un problème de surbrillance, ce dernier est résolu grâce aux nouvelles expressions régulières en PHP et à l'amélioration de la fonction de surlignage.

Dans le fond, le moteur de recherche PHP fonctionnait très bien mais l'affichage n'était pas transcendant... Voilà un premier problème résolu... :D

Bug moteur de recherche PHP Objet - POO

 

296 commentaires

  • Mike dit :

    Bonjour, je trouve votre article très complet, vous ajoutez beaucoup d'information très technique. C'est rare de voir autant de détails. Ça ne doit pas être évident à rédiger.

    • Bonjour.
      Pour être tout à fait honnête avec vous, ce n'est vraiment pas simple car j'ai encore plein de points de détails que j'aurais voulu expliquer mais à ce rythme, j'aurais écris un livre juste sur le code...
      Je pense d'ailleurs à une piste d'évolution à l'avenir mais qui peut me prendre du temps à mettre en place, c'est la recherche approximative (ou approchante) avec SOUNDEX et LEVENSHTEIN, mais cela peut prendre du temps car tout devrait être adapté et ce sera loin d'être simple...

  • Bonjour Mathieu, Mike est un spammeur, regardez son site. Votre site seebz est spammé aussi

  • 2BubbleBlog dit :

    Bonjour,
    le code à l'air plus simple que ceux que j'ai vu auparavant. Vais l'étudier d'un peu plus prêts voir si je peux l'intégrer à mon nouveau site ;)

  • Mohamed dit :

    Si le script est simple, en trois erreurs PHP(sic!) on trouve comment désactiver le stopwords (le moteur de recherche n'étant réservé qu'à un usage privé en local, aucun risque que je me sabote tout seul. J'ai essayé de modifier le script en ajoutant un champ de recherche supplémentaire, mais le résultat a été étrange, à suivre, je reviendrais vers vous quand j'aurais fini.
    En tout cas, merci infiniment!!! Je suis juriste de formation, je programme àtemps perdu, et il m'a fallu cinq minutes, clope et schweppes compris pour le mettre en oeuvre avec une mise en page associée à mon bootstrap.
    Royal, Bravo!

    • Dans la dernière version, j'ai corrigé quelques bugs que j'ai vu traîner par-ci par-là, je vous conseille de prendre la version 1.2 des class que vous utilisez, ce n'en sera que mieux tout en étant utilisé de la même manière.
      J'ai essayé de faire un script très complet tout en restant "simple" d'usage, mais bon, il y a tellement de paramètres que moi-même je m'y perds un peu au début, mais ça va vite, les commentaires aident à retomber sur nos pieds... :D

      En revanche, je vous avoue que j'avais pensé à faire un moteur multi-critères (plusieurs champs) au début, mais j'ai perdu tout mon code (un peu dégoûté sur le coup) à cause d'un plantage de Dreamweaver (merci Adobe !), il faudra donc que je teste ça avec plusieurs champs à l'occasion, mais dans la version actuelle, c'est vraiment pour un champ simple...

  • Mohamed dit :

    Pour l'instant, le script fait ce que j'attends de lui, une recherche.
    Pour vous en dire plus, j'ai téléchargé sur le site RIP-JUSTICE (c'est pas une blague) les données relatives aux lieux de la Justice en France (dixit le site open data du gouvernement).
    Après trois heures de reformatage des données(4365 lignes, le csv est imbuvable et truffé d'erreurs), vingt plantages Mysql, une bagarre entre Access et le pilote Oracle dont access est sorti vainqueur, et un retour à la case csv (généré par access), ma base était prête et j'ai trouvé votre script!
    Au final, mon application affiche, plus ou moins la même chose que le site service public, et j'en suis content. Pourquoi ne pas aller sur le site? Je vous le dirais en privé si le coeur vous en dit.
    Je travaille actuellement sur l'affichage du résultat, j'ai essayé une table, mais la pagination n'aime pas ça... Le problème doit venir de bootstrap car j'ai de gros problèmes avec les tables de manière générale.
    Merci pour votre conseille, je vais tester la version 1.2 sans tarder.
    De mon côté, si je trouve un moyen de faire une recherche multi-critères, je vous tiens au courant. J'en suis encore à essayer de shunter la requête (est-ce possible?) pour forcer un second critère. Comme l'indique mon vocabulaire, je ne suis pas un développeur, alors si je trouve une solution, elle sera fonctionnelle, mais certainement pas élégante.
    Quant au plantage, je connais bien... ma soeur, avocate de son état perd en moyenne un jeu de conclusion par mois (quatre à cinq heures de travail en moyenne...), je vous donnerais le même conseil que celui que je lui donne : évitez les usines à gaz. J'ai toujours utilisé Notepad++ qui intègre en plus un client ftp, idéal pour envoyer ses fichiers tout frais codés. J'ai vu sublime text qui a l'air pas mal, mais je reste fidèle à Notepad++ qui n'a jamais planté, en dix ans d'utilisation.
    Mon wysiwyg à moi, c'est mon imagination.

    Encore une fois, bravo, c'est un travail remarquable, j'ai testé deux scripts avant ça l'un affichait le php à l'écran, brut, une erreur dans l'echo et l'autre était tellement dépassé que l'utiliser revenait à le réécrire.

    Bien à vous.

    • Merci pour vos commentaires et bravo pour votre travail, vous êtes téméraire et cela va forcément payer, les codes ne vont pas lutter longtemps ! :D
      Si votre problème est persistant, c'est qu'il y a un problème en effet avec les tables, il faudrait voir ça...

      Pour les logiciels, j'utilise tantôt Dreamweaver (car j'ai la licence en tant que professionnel, donc autant en profiter) tantôt NotePad++ que j'aime beaucoup.

      En code, il ne faut pas grand chose pour faire planter. Je vous cite un exemple que j'ai résolu dans mon script pour la version 1.2 par exemple. Admettons que nos résultats de recherche contenaient des <h2> ou <h3> (...) en HTML, lorsque la mise en gras s'applique, cela lit tout le code source du contenu et donc les balises. Sauf que si je recherche "2" ou "3" dans ma requête, ça passait les chiffres des balises <h2> ou <h3> (...) en gras, et donc ça faisait planter les balises (exemple, au lieu de laisser <h2> ou <h3>, ça écrivait <h<b>2>... ou <h<b>3>...). J'ai corrigé tout ça ainsi que toutes les balises HTML notamment.
      J'ai également corrigé les requêtes "sans mot" car si j'active les stop words et que je cherche "le", "une" (...), ça fait comme si ma requête était vide, il fallait donc gérer les erreurs éventuelles...

      Je fais souvent dans l'exhaustif, et tant qu'à faire un moteur, je voulais qu'il soit puissant (j'aimerais faire évoluer l'algorithme de pertinence à terme). Je n'ai pas tenté de le faire fonctionner sur deux champs en parallèle, mais je ne pense pas que ça va fonctionner, il faudrait que j'implante la recherche multi-critère dedans, mais c'est très compliqué à mettre en place, d'autant plus que mes class contiennent trois méthodes de recherches, donc je dois répéter l'opération pour chacune... :(

  • Mohamed dit :

    Oui l'obstination paye toujours et je ne me décourage jamais, je suis un adepte des chemins de traverse, comme tous les juristes vous me direz...
    Pour l'annuaire, la recherche multicritères n'est pas essentielle, car au final, j'ai consulté quelques villes, et à part Paris qui renvoie quelques 35 pages de résultats, les autres ne renvoient jamais plus de cinq pages, pas de quoi s'énerver. En tout cas de mon point de vue. La programmation c'est aussi savoir être pertinent, et faire une réécriture du code pour un cas ou deux, ce n'est pas pertinent. Mais je ne garde ça dans un coin de la tête. Pour la mise en forme, en attendant de solutionner le problème des tables, j'ai ajouter des balises à droit à gauche et le rendu est plaisant à l’œil et lisible, c'est l'essentiel.
    La base de données va essentiellement me servir pour une autre partie de mon application, qui génère des actes à la volée. je voulais recycler le moteur pour ça, mais au final, je pense que je vais procéder autrement. A savoir que je vais créer une requête qui sera stockée dans un module et dont les éléments seront des variables (comme vous avez fait) dont la valeur sera renseignée au moment de la création du dossier. Grâce à un assistant (les avocats adorent les assistants) l'utilisateur (ma sœur et peut-être moi un jour et mon frère aussi!) pourra choisir la juridiction compétente, les informations seront automatiquement liées,grâce à une table de jonction (ça vous semble logique, si vous voyez ce que je veux dire évidemment). Les informations seront ensuite chargées automatiquement dans le formulaire de génération de l'acte (dont le script existe déjà), le tout étant envoyé dans un .docx basé sur un modèle stocké sur le serveur, l'utilisateur étant ensuite renvoyé vers un explorateur de dossier (qui existe déjà aussi) et qui représente les cotes du dossier (comme le dossier physique) dans lequel il peut renommer, supprimer, ajouter ou télécharger des éléments. En bref je fais un logiciel de gestion de cabinet d'avocat, mais pour un seul avocat...

    • L'application sera très intéressante et utile dans votre métier en tout cas, je vous souhaite de réussir.
      Pour le code, le mieux est toujours d'avoir des variables à part et dynamiques qui sont appelés dans un code (fonctions, etc.) générique.
      Pour les jonctions de tables, je ne sais pas si vous maîtrisez bien SQL mais ça se fait sans trop de problème. Bon courage en tout cas !

  • Mohamed dit :

    Bonjour!

    Quand je vous disais qu'il faut persévérer. Ce matin, j'étais chagriné, parce que j'avais trouvé mille usages pour votre moteur, mais pas la recherche multi-critères.
    Puis je me suis dit, au fond, une recherche avec les caractères +, "", and etc... c'est une recherche multi-critères. Si on a soif et qu'on est dans le désert, du pipi c'est de l'eau aussi, me suis-je dit.
    Ma recherche recherche s'étendait au départ à une colonne de ma base : la ville. J'ai donc ajouté le champ contenant les intitulés abrégés des juridictions.
    Au début ça me renvoyait toujours tous les résultats de la ville, comme si le deuxième terme était ignoré, puis je me suis dit, soyons méthodique.
    -Le moteur fonctionne et ne renvoie aucune erreur prévue.
    -Php ne fait pas la gueule et ne vomit pas en interprétant le code.
    -Les champs de recherche sont les bons (j'ai vérifié l'orthographe car comme tout le monde, il m'est arrivé de chercher cinq heures une erreur complexes alors qu'il me manquait un _ ou une lettre dans le nom d'une variable ou d'une fonction...).
    Le problème était donc ailleurs.

    J'enrageais car j'utilise un site pour mes recherches documentaires qui propose une recherche de ce type. Vous me direz, comparaison, n'est pas raison, je suis d'accord, mais je suis plein d'illusions... Et j'avais la certitude que j'allais trouvé ce que je cherchais par ce biais et que la réponse était à chercher du côté du sql.

    En désespoir de cause, je suis revenu sur cette pages et j'ai relu l'article. Mes espoirs allaient s'évanouir à la lecture de la section des TODO, puis en lisant la phrase suivante, le Ciel s'est éclairé :

    "Gestion des requêtes qui peut être améliorée. Actuellement, cela prend en compte les expressions entre guillemets et les mots seuls, je n’ai pas envisagé de gérer les « + » et les « - » ni les « AND » et « OR » par exemple, mais cela pourrait se faire (le problème étant que ce système ne fonctionne qu’avec la recherche FULLTEXT et pas les autres…)."

    Pourquoi ne pas essayer avec le fulltext?

    J'ai fait un fulltest de fulltext... Ben non, ça marchait pas. Au mieux le moteur me renvoyait tous les résultats de la ville passée en paramètre, mais jamais ce que je voulais. Un gros nuage noir survolait ma matinée

    Café en main et Chat en vadrouille dans mon deux pièces(il s'appelle le Débile, comme le bras robotisé de Tony Starck), je me suis dit, tant qu'à tester, testons tout. J'ai donc essayé avec regexp, vous me direz, c'est évident. Ben ça marche mon bon Monsieur.
    En renseignant dans mon champ le nom de la ville, ou son code postal (j'ai rajouté cette colonne en cours de route) et l'abréviation ou le titre complet de la juridiction, sans guillemets, ni +, ni rien... le moteur me renvoie un seul résultat : celui que je cherche. Un exemple : ti Marseille renvoie

    MARSEILLE
    Tribunal d'Instance de Marseille
    Palais de Justice Place Monthyon
    MARSEILLE 13006
    Tél : +33 4 91 15 50 50
    Fax: +33 4 91 15 56 80

    Youpi!!!!!

    Certes, ce n'est pas en soi une recherche multi-critères au sens traditionnel du terme, l'utilisateur n'ayant qu'un champ de recherche. Mais l'esprit, et ce qui compte le plus à mes yeux, le résultat est le même.

    Je dois vous paraître débile (sic!), mais je suis content d'avoir trouvé une solution à mon problème sans toucher au code. Du coup, je vais passer quelques jours à me former au sql en profondeur.
    Quand je vous disais que j'aimais les chemins de traverse...

    Bien à vous.

    Mohamed.

    • L'essentiel est acquis si vous avez trouvé un palliatif (qui marche) pour votre base. La recherche FULLTEXT impose que les tables soient en FULLTEXT, c'est un peu "chiant" mais cela reste la meilleure recherche du moteur. REGEXP est très très peu connue (recherchez sur Google, personne n'en parle quasiment...) mais plus puissante que le classique LIKE que tout le monde utilise à tout-va.

      LIKE vous permet de chercher des bouts de mot, comme "teur" pour trouver "moteur" ou "docteur" par exemple. REGEXP fait un mix entre le mot exact et l'expression et FULLTEXT cherche les mots exacts. Tout l'intérêt était de pouvoir prendre l'option la plus adaptée... :D

      J'ai bien aimé la partie où vous dites "il m’est arrivé de chercher cinq heures une erreur complexes alors qu’il me manquait un _", c'est du vécu et on en rigole après quand on trouve la solution, mais qu'est-ce que ça énerve quand ça arrive... :D

      Bravo en tout cas et je ne perds pas espoir de l'améliorer encore pour en faire un moteur de recherche interne ultime ! :D
      (pour l'anecdote, je suis en train de réfléchir à améliorer l'algorithme en prenant en compte la distance entre les mots recherchés si la requête contient plus d'un mot...)

  • Mohamed dit :

    Oui,c'est très énervant ce genre d'erreur, mais je préfère me concentrer sur le soulagement et le plaisir d'avoir un code qui fait ce qu'on attend de lui, et ça m'incite à la vigilance et ce n'est pas plus mal.
    En effet, regexp est très puissant pour peu qu'il soit utilisé convenablement. J'en teste actuellement les possibilités pour rédiger un texte d'aide (dans une fenêtre modal pour le look grâce à Jquery et boostrap...).
    J'ai une question, au cours de mes pérégrinations matinales, j'ai découvert un framework sur le site développez.net qui a l'air pas mal, il s'agit de MkFramework (http://mkdevs.com/accueil.html). Le connaissez vous?

    Autre question, pourquoi ne pas avoir fait un "include_once" pour les paramètres de connexion à la base de données? Bon je l'ai fait et je renvoie vers mon module de connexion personnalisé et ça marche pareil.

    Bon appétit si vous êtes à table.

    • Je n'utilise aucun framework pour être très honnête avec vous, je suis un "puriste" qui créé souvent tout à la main... :D
      En revanche, cela peut être pratique sur bien des points donc c'est utile pour beaucoup de cas, mais jusqu'à maintenant, je m'en suis passé. Je connais un peu Symfony ou Zend mais pas MkFramework... :(

      Pour la connexion à la base, j'ai écris le détail ici mais dans mon utilisation habituelle, je fais effectivement un include_once qui est plus "propre".

  • Luc dit :

    Bonjour Mathieu, je te remercie pour tes partages forts intéressants. Pour ton moteur de recherche, effectivement le REGEX reste la solution la plus intéressante si l'on souhaite des résultats précis. J'ai eu créé pour mes propres besoins (visible sur: Limonads.com) une recherche qui utilise les REGEX, mais j'ai aussi utilisé une requête en cascade pour arriver à des résultats à peu près corrects. j'éclate le texte recherché. Avec la prise en compte du Pluriel/singulier. Il faudra que je teste ta classe à l'occasion qui m'a l'air compléte. Bonne continuation et bon codage ! ;-)

  • jef dit :

    Bonjour Mathieu,
    Mise en place aisée et explications très intéressantes !
    Par contre, sais tu comment gérer les recherches "case sensitive" ?
    Merci de ta réponse

    • Le moteur n'a pas été entièrement pensé pour faire du "case sensitive" en toute honnêteté, mais les bases sont là...
      En fait, pour faire ça, il faut choisir un encodage qui est insensible à la casse (dont en gros, pas un utf8_general_ci --> pas "ci" en fait !). Dans ce cas, les recherches sont sensibles à la casse en théorie. Il peut être intéressant d'utiliser l'option "sans accents" également dans ce cas (sauf dans certaines langues). Normalement ça marche ainsi...

  • Patrice dit :

    Bonjour et merci pour ce script :) J'en ai utilisé qu'une partie mais ça m'a fait gagner beaucoup de temps !

  • Armel dit :

    Bonjour et merci beaucoup pour avoir partagé votre travail!

    J'ai donc intégré votre moteur à mon site en revanche est-ce normal si la recherche en lettre majuscule ou minuscule est différenciée.

    Par ailleurs, avec le paramétrage $exactmatch à false j'ai le message 'Erreur dans la requête, vérifiez bien votre paramétrage complet !'

    Merci encore

    • J'ai remis à jour le moteur (téléchargez la dernière version), elle corrige normalement le problème des majuscules...
      En revanche aucun de mes tests avec une seule lettre n'a entraîné votre problème, je suis bien embêté... :S

  • Armel dit :

    Par ailleurs, avec le paramétrage $exactmatch à false j’ai le message ‘Erreur dans la requête, vérifiez bien votre paramétrage complet !’ Lorsque je mets une seule lettre dans le champ de recherche (j'avais oublié de préciser!)

    • Bonjour,

      La recherche ne différencie pas la casse si vous choisissez le bon encodage dans le moteur mais aussi dans votre table MySQL. Si vous avez du utf8_general_ci, ça marchera car "ci" signifie que la casse n'est pas prise en compte. Dans ce cas, le réglage du charset du moteur doit être utf-8 aussi. Attention vraiment avec ceci car le problème peut se poser si vous n'avez pas un encodage parfait (le problème peut être résolu si vous savez coder en utilisant des fonctions comme strtolower en php pour la requête et LOWER en SQL pour les requêtes, mais normalement vous pouvez passer outre).

      En revanche pour exactmatch, c'est étonnant en effet et je n'ai pas fait le test (en général j'exclus les recherches d'un seul caractère donc je n'ai pas vérifié). Quel type de recherche utilisez-vous (regexp, like ou fulltext) ? Si le message apparait, ça veut dire qu'un paramètre fait "planter" la requête SQL...

  • LitoFix dit :

    Félicitations et merci pour tout ce travail !
    J'essaie d'inclure votre moteur de recherche dans mon site. Je rencontre néanmoins une difficulté : en mode FULLTEXT, n'est-il pas possible de décider que le moteur doit rechercher au moins un mot de la requête, mais que tous ceux précédés de "+" doivent au minimum s'y trouver ?
    C'est ce que j'ai tenté de faire en mettant "false" pour l'avant-dernier paramètre de la fonction __construct (c'est-à-dire $exact) ce qui doit permettre de choisir qu'un des termes AU MOINS de la recherche doit être inclus. Mais dans ce cas, le "+" devant un mot est sans aucun effet.
    J'en viens à me demander si c'est tout simplement possible...
    En espérant avoir été clair,
    Merci encore pour tout votre travail !

    • Bonjour,
      En effet, je n'utilise pas la méthode FULLTEXT dans sa totalité (j'ai dû détourner son usage à cause des deux autres modes de recherche). En fait, la recherche FULLTEXT (comme les autres) comprend les recherches d'expressions entre guillemets mais ajoute automatiquement un "+" devant chaque mot. Donc si vous tapez dans un champ "ma requête de recherche", c'est comme si vous aviez tapé "ma +requête +de + recherche", quel que soit la valeur de la variable $exact (celle-ci est justement utile pour les méthodes de recherche moins précises que sont LIKE et REGEXP). Par conséquent, si vous ajoutez vous-mêmes des "+" dans votre requête, ils sont "exclus" car déjà ajouté naturellement...

      De même, j'ai précisé dans l'article que je n'avais pas permis l'usage des "+" ni des "-" (pour exclure des termes de recherche), là encore à cause des autres méthodes de recherche en PHP. En fait je n'ai pas joué sur ces tableaux, voilà tout, mais je ne dis pas que je ne ferais pas un moteur 100% FULLTEXT à l'avenir (voire SOUNDEX)... :D

  • LitoFix dit :

    Merci pour cette réponse détaillée. Il devrait donc être possible de modifier assez simplement le code pour y parvenir, il me semble ?

    Je me pose une autre question : la même chose est-elle THÉORIQUEMENT possible avec regexp ? Je m'y essaie depuis un moment, en vain...

    • Je n'ai pas dit que c'était facile à coder, mais ce n'est pas impossible en effet.

      Pour votre autre question, ni LIKE ni REGEXP ne prend en compte les "+" et les "-", seul la méthode FULLTEXT le fait malheureusement.

  • LitoFix dit :

    Ne peut-on pas, néanmoins, simuler l'utilisation des "+" et des "-" en REGEXP avec des "OR" et des "AND" habilement placés ?

    • en fait, je fais automatiquement des "AND" avec REGEXP pour que chaque mot ou expression de la requête tapée soit recherchée, je n'utilise jamais les "OR" car c'est bien rare que quelqu'un qui tape une expression comme "moteur de recherche" veuille chercher soit "moteur", soit "de", soit "recherche", l'utilisateur veut un résultat qui répond aux trois mots (ou sinon, je ne comprends plus rien au monde de la recherche, ce qui serait le comble... :D). Je force donc les "AND" par défaut, mais à l'intérieur du code, vous verrez que j'ai nommé une variable qui s'appelle $operateur et qui est justement ce "AND" entre chaque mot, donc vous pouvez le mettre sur OR si nécessaire. ^^

  • LitoFix dit :

    C'est ce que j'avais fait, mais c'est loin d'être pleinement satisfaisant : on peut réellement parvenir, par ce moyen, à simuler l'emploi des "+" et des "-" en REGEXP ?

    • Non on ne pourra pas faire les "-" mais seulement des "+" (le cas de AND). Le cas de OR permet de faire une requête sans les "+" en quelque sorte.
      Ce qui pourrait se faire pour simuler un "-", c'est de récupérer les mots de la requête qui sont précédés d'un "-" et de rajouter une couche dans la requête avec une clause WHERE pour dire que le résultat recherché ne doit pas contenir ce mot précédé d'un "-". Je ne sais pas si c'est très clair expliqué comme ça, je détaille un peu plus...
      En gros, une requête classique fait ça (version "francisée") : RECHERCHE dans table WHERE colonne contient mot1 AND colonne contient mot2. Ceci est le cas du AND classique, mais nous pourrions continuer la requête en ajoutant AND colonne ne contient pas mot3 (équivalent du "-"). Je pense que c'est jouable...

  • LitoFix dit :

    Merci pour ces précisions.

    Une ou deux remarques, si je peux me permettre :

    - une erreur "Got error 'repetition-operator operand invalid' from regexp" est renvoyée en mode "REGEXP" si l'algorithme de pertinence est sur "true" et que l'un des termes de la recherche commence par un "+" ou un autre signe comme "$", "?", "*" etc. Ça bloque dans la fonction d'affichage à la ligne suivante :
    $requeteType = mysql_query("SELECT $algo[3], $colonnesStrSQL FROM $this->tableBDD WHERE $this->condition");

    - en mode "OR" et en REGEXP, l'algorithme de pertinence ne semble pas tenir compte de la présence de plusieurs des termes dans l'une ou l'autre des réponses. En fait, dans ce cas, l'algorithme de pertinence semble tout simplement ne pas fonctionner.

    • Décidément, je suis bien mal en point pour vous aider... ^^

      J'ai un moteur de test et j'ai effectué exactement les réglages que vous me proposez, mais je ne rencontre pas l'erreur "Got Error repetition-operator..." quand j'ajoute des "$", "?", "+", etc. En réalité, cette erreur peut se produire si les caractères spéciaux ne sont pas échappés avec un anti-slash. Hors, dans mes requêtes SQL, j'utilise justement la fonction addslashes() pour ajouter un antislashes automatiquement dans la requête, l'avez-vous enlever par inadvertance ? Au pire, tenter d'ajouter un addslashes à la requête envoyée ($_POST['marequete'])...

      Le moteur n'étant pas fait pour une recherche "OR" par défaut, l'algorithme a beaucoup moins d'intérêt dans ce cas, mais il fonctionne quand même. Actuellement, l'algorithme est bête et méchant, il fait exactement la même requête que celle de recherche (en gros) et comptabilise le nombre d'occurrences des mots recherchés. Si vous êtes dans le cas d'un "OR", il est donc fort probable que l'ordre final ne soit pas le meilleur à votre goût, c'est normal. En réalité, l'algorithme fonctionne bel et bien mais a beaucoup moins d'intérêt puisqu'un résultat ne contenant qu'un mot (à cause du "OR") beaucoup de fois peut être premier et un qui contient les deux mots seulement une fois sera derrière...

  • LitoFix dit :

    Non, je n'ai touché à rien dans votre code.

    En cherchant un peu plus, je me rends compte que ce message d'erreur n'est affiché que si le paramètre $exact de la fonction moteurRecherche est à "false".
    Voici mes réglages, à des fins de débogage :
    $moteur = new moteurRecherche(stripslashes($_GET['s']), 'ma_table', 'regexp', '', '', 'utf-8', false, false);
    ...
    $moteur->moteurAffichage("affichage", "ma_table", array(true, $_GET["page"], 1), array(true, "colonne_date", "DESC"), array(true, "algo", "DESC", "colonne_id"), "AND colonne_online=1");

    D'autre part, y aurait-il moyen d'afficher une phrase du genre :
    "Votre recherche de 'blabla' a donné 15 résultats. Voici les résultats 5 à 10." ? Auriez-vous juste un début de piste à me donner là-dessus ? Tous mes essais se soldent par un échec lamentable...

    • Je n'ai pas la même erreur que vous mais j'en rencontre bien une, elle peut se corriger en excluant les signes "génants" avec cette méthode :
      if(preg_match("/([+?$*§\|\[\]\)\(])+/i",$this->request[$val])) {
      $this->request[$val] = str_ireplace(array("+","?","$",'*','§','|','[',']','(',')'),array(""),$this->request[$val]);
      }
      N.B. : à placer dans 'case "regexp"' après $this->motsExpressions = $this->request; ! Il suffit de rajouter les signes qui posent problème ensuite si vous en trouvez d'autres. Je vais essayer de renvoyer une version "nettoyée" du moteur très bientôt pour que tout le monde puisse en profiter...

      Pour votre 2e suggestion, il est tout-à-fait possible d'afficher le nombre de résultats, mais cela se fait à l'intérieur de la fonction "callback" d'affichage grâce à la variable que j'ai appelée $nbResults. Faites un echo $nbResults; dans la fonction et ça affichera le nombre de résultats.
      Pour afficher "Voici les résultats 5 à 10" par exemple, il faut "jouer" avec le $_GET['page'] de l'URL.

      Voici un code complet qui fonctionne :
      $limit = 5; // Nombre de résultats par page
      if($_GET['page'] == 0) {
      $nbDebut = 0;
      $nbFin = ($_GET['page']+1) * $limit;
      } else {
      $nbDebut = ($_GET['page']-1) * $limit;
      $nbFin = $_GET['page'] * $limit;
      }
      echo $nbResults." résultats pour votre recherche. Voici les résultats ".$nbDebut." à ".$nbFin;

  • LitoFix dit :

    Merci de m'avoir mis sur la voie !

  • Legall dit :

    Bonjour,
    Tout d'abord, super CLASS !
    Dommage que je n'arrive pas à la faire marcher.
    Je suis en train de "construire" un site avec ce mini moteur de recherche.
    J'ai un fomulaire dans la page principale :

    <input class="champ" type="text" title="Rechercher..." placeholder="Rechercher..." value="" name="moteur" id="moteur" />

    Celui-ci passe pas un .htaccess qui retourne les résultats dans la page principale après traitement dans la page PHP où j'ai tout mis :

    moteurRequetes($colonnesWhere);
    }

    if(isset($moteur)) {
    // Affichage de la requête avec $moteur->requete
    echo 'Résultats de la recherche : '.$moteur->requete.'';

    function affichage($requete, $nbResults, $mots) {
    if($nbResults == 0) { // Si aucun résultat n'est retourné
    echo "Aucun résultat, veuillez effectuer une autre recherche !";
    } else { // Sinon on affiche les résultats en boucle

    // Afficher le nombre de résultats
    $affichageResultats = new affichageResultats();
    echo $affichageResultats->nbResultats();

    while($key = mysql_fetch_assoc($requete)) {
    // On encode chaque clé/valeur de résultats en UTF-8
    foreach($key as $k => $v) {
    $key[$k] = utf8_encode($v);
    }

    // Résultats de recherche à afficher (à personnaliser)
    $texte = "".$key['titre']."";
    $texte .= $key['contenu']."";

    $surlignage = new surlignageMot($mots, $texte);
    echo $surlignage->contenu; // Affichage du contenu après surlignage
    } // Fin de la boucle while
    }
    }

    $moteur->moteurAffichage('affichage', '', array(true, $_GET['page'], 4));

    $moteur->moteurPagination('page');
    }
    ?>

    Mais il me retourne :

    Résultats de la recherche : "LE MOT"
    Erreur dans la requête, vérifiez bien votre paramétrage complet !

    Je ne sais pas quoi faire !

    Merci de toute aide

    Legall

    • Bonjour,
      Dans ce que vous avez écrit ici, je ne vois pas de "fautes" particulières, mais avez-vous tout bien mis ?
      - Où est $moteur = new moteurRecherche(stripslashes($_GET['moteur']), 'matable', 'regexp', $stopwords); par exemple ?
      - Ensuite, il faut écrire $moteur->moteurRequetes($colonnesWhere); pour que ça marche ($colonnesWhere étant un tableau des colonnes de recherche)
      - Avez-vous télécharger la dernière version de la Class (elle date d'avant-hier...) car elle corrige les recherches en majuscules comme "LE MOT" par exemple... (Je viens d'effectuer un test de mon côté qui ne plante pas)
      - Avez-vous crée le champ ?

      Quel type de recherche utilisez-vous ? REGEXP, FULLTEXT ou LIKE ? Quels "mots" génèrent ces erreurs par exemple ?

  • Legall dit :

    Bonjour,

    Alors;

    "- Où est $moteur = new moteurRecherche(stripslashes($_GET['moteur']), ‘matable’, ‘regexp’, $stopwords); par exemple ?"

    Rép.: Il est en haut de la page principale INDEX (au-dessus du DOCTYPE) entre les balises ob_start(); et ob_end_clean(); et en dessous des :
    include_once 'scripts/BDD.class-inc.php';
    include_once 'scripts/stopwords.php';
    include_once 'scripts/moteur-php5.class-inc.php';

    "- Ensuite, il faut écrire $moteur->moteurRequetes($colonnesWhere); pour que ça marche ($colonnesWhere étant un tableau des colonnes de recherche)"

    Rép.: j'ai écris :

    if(isset($_GET) && !empty($_GET['moteur'])) {
    $moteur = new moteurRecherche(stripslashes($_GET['moteur']), 'ma_table', 'like', $stopwords);
    $colonnesWhere = array('titre', 'contenu');
    $moteur->moteurRequetes($colonnesWhere);
    }

    MA TABLE est composé de :

    CREATE TABLE IF NOT EXISTS news (
    id_news int(3) NOT NULL AUTO_INCREMENT,
    auteur varchar(30) NOT NULL DEFAULT '',
    titre text NOT NULL,
    contenu mediumtext NOT NULL,
    position int(11) NOT NULL,
    date_ajout timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    date_modif datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
    PRIMARY KEY (id_news)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

    "- Avez-vous télécharger la dernière version de la Class (elle date d’avant-hier…) car elle corrige les recherches en majuscules comme “LE MOT” par exemple… (Je viens d’effectuer un test de mon côté qui ne plante pas)"
    Rép.: Elle se trouve où car le lien en haut de la page me donne celui d'il y a quelques jours avec 35Ko !?

    "- Avez-vous crée le champ ?"
    Rép.: Quelle CHAMP ? Ceux de la table ?

    "Quel type de recherche utilisez-vous ? REGEXP, FULLTEXT ou LIKE ? Quels “mots” génèrent ces erreurs par exemple ?"
    Rép.: J'utilise LIKE mais le message s'affiche avec les deux autres également et tous les mots générent le même message.

    ON DIRAIT QU'IL NE TROUVE PAS LA TABLE !?

    Dernière info ! J'utilise un système de URLrewriting en .HTACCESS

    RewriteRule ^index.* /home.php [L]
    RewriteRule ^([^/]*)\.html$ /?pg=$1&title_pg=$2 [L,QSA]

    et dans la page principale :

    define("PATH", "./includes/");
    $tableau = glob(PATH . "*.inc");
    if (isset($_GET["pg"]) && in_array(PATH . $_GET["pg"] . ".inc", $tableau)) {
    $pageInclude = PATH . $_GET["pg"] . ".inc";
    }
    else {
    $pageInclude = PATH . "page_principale.inc";
    }
    include $pageInclude;

    Merci d'avance

    Legall

  • Legall dit :

    Re-bonjour,

    J'ai ré-crée une seule page de requête et un table "simple" MAIS RIEN N'Y FAIT !
    Le script ne marche pas !!!

    LA TABLE
    CREATE TABLE IF NOT EXISTS search (
    id int(3) NOT NULL AUTO_INCREMENT,
    titre varchar(255) NOT NULL,
    contenu mediumtext NOT NULL,
    PRIMARY KEY (id)
    ) ENGINE=MyISAM;

    LA PAGE :
    moteurRequetes($colonnesWhere);
    }

    ?>

    RECHERCHE

    Rechercher :
    <input type="text" name="moteur" id="moteur" value="" />

    requete
    echo 'Résultats de la recherche : '.$moteur->requete.'';

    function affichage($requete, $nbResults, $mots) {
    if($nbResults == 0) { // Si aucun résultat n'est retourné
    echo "Aucun résultat, veuillez effectuer une autre recherche !";
    } else { // Sinon on affiche les résultats en boucle

    // Afficher le nombre de résultats
    $affichageResultats = new affichageResultats();
    echo $affichageResultats->nbResultats();

    while($key = mysql_fetch_assoc($requete)) {
    // On encode chaque clé/valeur de résultats en UTF-8
    foreach($key as $k => $v) {
    $key[$k] = utf8_encode($v);
    }

    // Résultats de recherche à afficher (à personnaliser)
    $texte = "".$key['titre']."";
    $texte .= $key['contenu']."";

    $surlignage = new surlignageMot($mots, $texte);
    echo $surlignage->contenu; // Affichage du contenu après surlignage
    } // Fin de la boucle while
    }
    }
    $moteur->moteurAffichage('affichage', '', array(true, $_GET['page'], 4));
    $moteur->moteurPagination('page');
    }
    ?>

    J'ai comme résultat en mettant un mot de recherche du genre "Hollande" (il y a deux articles dans la table) :

    Résultats de la recherche : Hollande
    Erreur dans la requête, vérifiez bien votre paramétrage complet !

    Je ne sais plus quoi faire !?

    Merci encore,

    Legall

    • Bonjour,

      En effet c'est très étonnant, et si l'erreur se fait avec les trois méthodes de recherche, c'est donc qu'il ne trouve pas le champ je pense, ou la base, etc. Quoi qu'il en soit, le script fonctionne car l'erreur se passe au dernier moment (le message d'erreur intervient quand il ne peut pas envoyer la requête SQL), cela signifie donc que le problème se situe à trois endroits possibles :
      1. la table non trouvée
      2. les colonnes de recherche non trouvées (au vu de vos codes, cela semble bon)
      3. le type de requête effectuée (ce problème est normalement très rare...)

      Vous avez bien insérez le nom de votre table dans $moteur = new moteurRecherche(stripslashes($_GET['moteur']), ‘ma_table’, ‘like’, $stopwords); ou vous m'avez recopié ça pour l'exemple ? Car le 'ma_table' est le nom de votre à mettre ('search' dans l'exemple que vous donnez ici). C'était juste pour l'exemple ou vous avez mis "ma_table" ?

      Pour le lien de téléchargement de la dernière version, c'est celui placé au milieu de l'article, avec la v1.5 (c'est écrit dans le nom).

      Au pire, envoyez-moi votre fichier de test par email et j'essaierais de regarder ce qui "buggue".

  • Legall dit :

    Oups... J'avais mal lu ! C'est bien la V1.5 que j'ai ! Désolé !
    Mais cela ne change rien au problème qui reste entier !
    Cdt

    • Problème corrigé, il s'agissait d'un conflit entre votre code et la class. J'ai corrigé le paramétrage par défaut de la v1.5 et c'est bon maintenant, il suffit de rajouter un 4e paramètre à l'appel de la méthode moteurAffichage. Ainsi écrivez $moteur->moteurAffichage(‘affichage’, ”, array(true, $_GET['page'], 4), array(false, 'id', 'DESC')); plutôt que $moteur->moteurAffichage(‘affichage’, ”, array(true, $_GET['page'], 4));

  • Paul dit :

    Bonjour,

    Y aurait-il moyen de tenir compte de collations différentes ? Mes tables sont en utf8_unicode_ci, ce qui provoque des erreurs du type :
    Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation 'regexp''
    Merci de votre aide !

    • Bonjour,
      Vous pouvez toujours modifier en dur la collation dans la requête REGEXP ou autre par exemple, c'est jouable.
      En revanche, je suis surpris de ce problème puisque j'ai fait justement des tests en utf8_general_ci et en latin1. Je n'ai pas pu tester tous les encodages bien entendu mais dans les deux cas ça fonctionnait. Je ne peux que vous conseiller de tester une autre collation manuellement si le problème persiste, je n'ai malheureusement rien pour tester ça en détail... :(

  • Paul dit :

    Merci.

    J'ai procédé comme suit pour modifier la collation, au cas où le problème se pose à d'autres que moi : il faut modifier le tableau $colonnesWhere en précisant la collation :
    $colonnesWhere = array('colonne_1 COLLATE utf8_unicode_ci', 'colonne_2 COLLATE utf8_unicode_ci', 'colonne_3 COLLATE utf8_unicode_ci');

    C'est bien ça ?

    • Si cela fonctionne comme ça, c'est très bien, mais je ne vois pas de problèmes particuliers là dedans (au premier abord). L'essentiel est le résultat, et si ça marche, c'est parfait ! Merci !

  • Louis dit :

    Merci beaucoup pour ce travail vraiment complet !
    Malheureusement il ne fonctionne pas sur mon site, j'ai la v1.5.
    A chaque recherche c'est "Erreur dans la requête, vérifiez bien votre paramétrage complet !"
    Que le mot existe ou pas c'est la même erreur, en revanche la page fonctionne bien quand on n'a pas encore effectué de recherche.
    Pensez-vous pouvoir m'aider, j'ai cherché toute l'après midi et je peux vous envoyer mon code s'il faut ?

    • Bonjour,
      Pas mal de gens ont des problèmes avec l'installation, c'est pour cela que l'erreur que vous rencontrez s'affiche. Il suffit qu'un seul paramètre soit mis de "travers" pour que tout le moteur plante, cela peut être au niveau des tables, des colonnes, etc. Décrivez-moi votre problème par email si vous voulez et envoyez-moi vos fichiers d'installation du moteur si possible pour que je regarde. Je testerai avec une base de données "test" que je conserve exprès et je finirai bien par trouver ce qui cloche, c'est souvent devant nos yeux et on ne le voit pas...

  • Paul dit :

    Bonjour,
    Est-il possible d'afficher le numéro de la page de résultats dans la balise meta title ? Je ne parviens pas à récupérer ce numéro en dehors de la fonction "affichage"...
    Merci de votre aide !

    • En théorie, tout l'affichage est géré par la fonction Affichage() en effet, mais certains éléments peuvent être "attrapés" à l'extérieur. Si vous voulez le numéro de page, il faut faire $_GET['page'] pour le récupérer là où bon vous semble, vous pourriez donc avoir un "echo $_GET['page'];" dans des balises TITLE par exemple.

  • Paul dit :

    Oui, mais non ;) $_GET["page"] renvoie le contenu du paramètre "page" tel qu'il figure dans l'URL, c'est-à-dire AVANT d'avoir été filtré. On s'expose donc à afficher (même en échappant la variable) tout et n'importe quoi.
    D'autre part, ne serait-il pas possible d'ajouter une condition dans le moteur de recherche pour le cas où $_GET["page"] est supérieur au nombre de pages existantes ? Actuellement, le moteur de recherche ne renvoie rien (même pas un message indiquant l'absence de résultats pour cette recherche). L'idéal, me semble-t-il, serait de renvoyer le contenu de la dernière page de résultats existante.

    • Je ne comprends pas, si vous voulez afficher le numéro de page, c'est bien $_GET['page'] qui le donne. Après, je n'y peux rien si vous êtes accro aux injections ou si vous voulez trifouiller la valeur du paramètre "page"... :D
      En revanche, il est vrai que je n'avais pas prévu de limitation du nombre s'il est supérieur au nombre de résultat, ça doit pouvoir se rajouter sans trop de soucis, je vais essayer de faire ça le plus vite possible... ^^

    • Problème corrigée dans la version 1.5.5 en téléchargement dans l'article. Désormais, si la valeur de "page" (ou plutôt du paramètre correspondant) n'est pas un numérique ou dépasse le nombre total de pages, alors nous sommes redirigés vers la première page de résultats (ou celle qui affiche qu'il n'y a aucun résultat). C'est mieux comme ça, merci pour l'idée ! :D

  • Sylphie dit :

    Bonjour Mathieu!
    D'une part, merci beaucoup pour ce script qui m'aide beaucoup à mettre en place un moteur de recherche interne pour mon website ^^
    Le seul point sur lequel je coince sont les underscores. En effet, certaines des colonnes de ma table possèdent des entrées ayant des underscores (dans le style de "une_personne"), que j'ai voulu faire de cette manière car des données peuvent être incluses après dans des liens URL. Cependant, si je vais chercher en FULLTEXT "une_personne" j'obtiens des résultats, mais pas avec "une personne" (puisque l'underscore considère que deux mots avec l'underscore ne forment qu'un seul mot).
    Y-a-t-il, d'après vous, un moyen pour que je switche les underscores et les espaces pour lui faire rechercher des mots ou expressions possédant des underscores dans la table comme si c'était un espace à la place?

    Désolée si mes propos sont un peu confus ><

    Merci et bonne journée :)

    • Bonjour,
      Non ce n'est pas confus, mais il est vrai qu'un moteur de recherche est toujours "tout bête" et il ne cherche que les mots "tels quels", donc chaque caractère compte. J'ai peut-être une idée un peu technique pour votre base, je vais essayer de décrire les étapes pour vous guider, mais il faudra sûrement modifier un peu la class PHP du moteur. En gros, il faudra lancer un "script" avant que la recherche ne soit effectuée...

      - On lance la recherche pour que le moteur envoie la requête
      - On analyse la table et on vérifie toutes les entrées qui portent un underscore (avec une fonction comme stripos ou preg_match en PHP) pour les rendre "lisibles". L'objectif va être de faire un preg_replace pour qu'une expression comme une_personne devienne "une personne" (je pense que ce serait le plus précis). Mais on peut également découper bêtement en faisant un preg_replace qui "supprime" l'underscore (dans ce cas, ça deviendrait "une" et "personne" et non l'expression pure "une personne").
      - Une fois le découpage effectuée, on lance la requête de recherche classique qui va aller voir s'il y a une correspondance.

      N.B. : une autre méthode serait presque de dédoubler la table en la "réécrivant" sans underscore avec un autre script qui se lancerait au début de la recherche. Dans les deux cas, les deux techniques vont prendre de la ressource malheureusement, et ce n'est pas conseillé bien entendu. :(

  • Sylphie dit :

    Bonjour et merci de votre réponse =)
    Je vais plutôt tenter votre première méthode, la table MyIsam sur laquelle j'effectue la recherche étant déjà une copie (par triggers) d'une table InnoDB (ca serait assez lourd d'avoir une table en trois exemplaires du coup xD)
    Je reviendrais vers vous quand j'aurai trouvé le moyen (et le code) adéquat pour résoudre mon problème ^^
    Bonne journée! =)

  • Sylphie dit :

    Et après quelques heures de recherche intensive, j'ai pu finalement trouver une solution à mon problème d'underscore: tout simplement lui demander au niveau des triggers insert/update de la table mère (InnoDB) vers la table fille (MyISAM) de faire un:

    SET nom_produit=replace(NEW.nom_produit, '_', ' ')

    pour que la table innodb ajoute dans sa table l'entrée avec l'underscore (et donne "une_personne"), et que la table myisam purifie l'underscore et remplace par un espace (et donc donne "une personne"), ce qui me eprmet de pouvoir par la suite rechercher.

    Du coup le mode de recherche "regexp" me semble plus adapté que le fulltext pour ce que je veux faire :o

    Merci beaucoup en tous les cas de m'avoir éclairé pour ce problème, et merci encore pour votre script génial ^^

  • David dit :

    Bonjour,

    je suis tombé sur votre moteur à travers une recherche sur GG, je l'ai testé, et visiblement j'arrive à le faire tourner pour afficher mes résultats, cependant, j'ai quelques questions.

    Je souhaite pouvoir chercher sur plusieurs tables à la fois est ce possible facilement ? En effet en l'état le moteur va chercher un produit dans une table spécifique, mais dans mon cas, le produit a plusieurs tables dédiés du genre product_tags, product_lang, product_comments...

    Et enfin pour l'affichage des résultats, je cherchais un affichage plus pertinent qui permettait d'aller chercher dans la ou les colonnes les mots clés et affichait X mots du texte ou de la description trouvé mais uniquement l'extrait autour du mot clé trouvé comme peu le faire google et non pas afficher la description au total ou les x premiers mots. Est ce compliqué à afficher dans ce sens ?

    • Bonjour,
      Pour la recherche sur plusieurs tables, la question a déjà été posée et je vous avoue que cela casserait tout le système de ce moteur donc je n'ai pas trouvé de solutions fonctionnelles idéales à ce jour, je suis désolé... L'objectif serait de faire des jointures automatiques mais dans ce cas, seuls les résultats présents dans TOUTES les tables seraient bons, alors que l'idéal serait de faire une recherche dans une ou l'autre, etc. Si j'avais davantage de temps, je réfléchirais à un système pour faire une recherche dans une table, puis dans une autre, etc.

      Google ne procède pas comme vous le dites, sauf lorsqu'il n'existe pas de meta description, auquel cas il invente lui-même son extrait de texte en ayant effectivement la requête recherchée. Cela doit être faisable mais demanderait pas mal de ressources je pense. Il faudrait faire la recherche, détecter un passage qui contient la requête, découper le texte de "x" mots avant et après, et afficher ensuite le résultat. Mon moteur n'avait pas cet objectif, mais ça doit être jouable je pense...

  • David dit :

    Merci pour votre réactivité !

    "faire la recherche, détecter un passage qui contient la requête, découper le texte de “x” mots avant et après, et afficher ensuite le résultat"

    Comme ça finalement ça à l'air simple :) Bon je vais continuer à creuser car je souhaitais ainsi créer des pages comme peut le faire wordpress pour ses pages de tags, mais le fait que ça affiche des extraits identiques à chaque fois pour les produits, j'ai peur du duplicate content dont GG fait la chasse ! Si l'extrait affiché est à chaque fois un bout différent ça éviterait ce problème.

    Si je trouve une solution je vous fais signe !

    et merci encore pour votre réactivité...

    Bonne soirée

  • David dit :

    Me voilà de retour comme promis.

    Si ça peut en aider certains voici ce que j'ai trouvé après quelques heures de recherches :
    http://stackoverflow.com/questions/1148533/mysql-php-how-to-do-search-and-show-summary-rather-than-entire-result

    j'ai mis un certain temps à tomber la dessus car toutes mes recherches en sur les sites francophones n'ont rien donné.

    Bon je vais maintenant essayer de l'adapter à votre script...

    Bonne continuation.

  • Carde dit :

    Super JOB, excellent travail. Très simple à mettre en place, fiable : BRAVO !

  • carde dit :

    Petite remarque en passant : je suis peut être parano, mais pour celles et ceux qui voudraient tripatouiller l'url de la recherche, je ne vois pas de solution pour rediriger l'utilisateur "mal intentionné" vers une 404 ou autre. Une idée ?

    • Vous n'êtes pas parano, j'ai prévu quelque chose pour éviter les injections SQL ou autre dans la version WordPress (Plugin WP-Advanced-Search) mais pas dans celle-ci car au fond, c'est facilement possible en protégeant les variables GET notamment et en redirigeant en fonction, par exemple.

  • carde dit :

    Facilement possible : j'avoue que non en ce qui me concerne. J'ai beau placer un if(!isset($_GET['page'])) { redirection_vers(qqchose) } j'ai une vilaine page d'erreur (variable $urlPage non connue ) qui s'affiche.

    • Ah pardon, j'ai peut-être manqué de tact je l'avoue. ^^
      En fait, il ne faut pas vérifier si le $_GET['page'] existe mais plutôt si c'est bien un numérique. Il faudrait donc plutôt faire un if(!is_numeric($_GET['page'])) { ... }.
      Aussi, il peut être intéressant d'ajouter une autre condition lorsque le numéro de page dépasse le nombre de résultats. En effet, si je tape dans l'URL "page=30000" et qu'il n'y a en réalité que 20 pages réelles de résultats, je vais me retrouver avec une page en partie blanche. Certes, ce n'est pas un drame, mais il peut être intéressant de rediriger vers la première page dans ce cas.

      Ce qui m'étonne, c'est que je viens de vérifier et j'ai un code de ce type dans ma dernière version du moteur (celle en ligne). Avez-vous bien la dernière version du script ? Si non, alors prenez-le. En fait, cela redirige automatiquement vers la première page si la personne tape un numérique plus grand que le nombre réel de pages de résultats ou s'il tape n'importe quoi d'autres... Vous voyez, même moi je ne me rappelais plus l'avoir ajouté déjà dans le script, mais c'est le cas. :D

  • carde dit :

    Pas de problème :p
    Ok en fait j'ai un conflit avec une de mes fonctions ^^. Merci :p

  • Opanczuk dit :

    Rares sont les puristes aujourd'hui dans nos métiers, et je suis heureux de tomber sur l'un d'eux ! Merci pour cette fonctionnalité, je me pencherais dessus dès lors que j'aurais un peu plus de temps. :)

  • Romain dit :

    Merci, merci et merci. Des vacances dans le midi ? Tu es le bienvenu ;o) (PM)

  • carde dit :

    Merci derechef pour cette class d'un très haut niveau. Aussi comme j'aime les choses bien compliquées (et bien faites aussi :p), je me suis mis en tête de créer un genre de filtre supplémentaire avec des checkbox pour affiner la recherche.
    En gros le moteur irait s'assurer avant de donner un résultat que certains champs (INT(1)) sont à 1 (par exemple), avant de rendre un résultat.
    Est-ce compliqué à mettre en place de votre point de vue?
    Cordialement,
    Benoît

    • Oui je suis pareil que vous, j'aime bien compliquer les choses à force d'avancer... Mais parfois, j'avoue que je cherche trop les complications aussi. ^^
      Concernant le filtre, il faudrait en effet ajouter une méthode en POO qui contrôle les booléens des checkbox du filtre. Dans le cas où c'est "true" (ou 1), la recherche s'effectuerait selon le filtre choisi (cela pourrait ajouter une condition dans la requête SQL à la fin). C'est un peu de boulot quand même, mais ça me semble jouable à première vue (c'est toujours quand on a la tête dans le guidon qu'on se rend vraiment compte de l'ampleur de la tâche. :D).
      Courage !!! ^^

  • guy dit :

    Bonjour,

    Tout d'abord, super travail! Il fonctionne super bien mais j'aimerai tester ce que tu appelles :" L'algorithme est activé lorsque le 5e argument de la class moteurAffichage() est présent. Il s'agit d'un tableau contenant 4 paramètres obligatoires "

    Malheureusement je n'arrive pas à le faire fonctionner, pourrais tu me donner un exemple d'appel?

    moi je fais comme cela

    $moteur->moteurAffichage('affichage', '', array(true, $_GET['page'], 10),'',array(true,'','ASC', 'id'));

    et ça n'ajoute pas une colonne e^n plus.

    merci de ton aide

    • Bonjour et merci ! :D
      En fait, pour faire fonctionner l'algorithme, il s'agit du 5e paramètre de la class moteurAffichage (il n'est donc pas présent dans votre exemple).
      Voici ce qu'il faudrait plutôt (la partie en gras est à ajouter) : $moteur->moteurAffichage('affichage', '', array(true,$_GET['page'],10), '', array(true,'','ASC','id'), array(true,'algo','DESC','id'));
      Voilà ! :D

  • guy dit :

    J'utilise ton script pour interroger une bd qui est constituée par un spider web qui crawl internet ( oui, je fais mon petit Google à moi ).

    J'ai 9000 pages et ce que j'en retire c'est que la recherche fulltext est bien, rapide, mais ne tient pas compte du nombre d'occurrence ( du moins ce n'est pas trop pertient) des mots trouvé, par contre ton algo le fait bien mais c'est très lent pour la base.

    J'ai vu ici
    http://dev.mysql.com/doc/refman/5.0/fr/fulltext-search.html

    qu'il y a moyen de donner de la pertinence à la recherche fulltext

    par une requete du type
    mysql> SELECT id, body, MATCH (title,body) AGAINST
    -> ('Security implications of running MySQL as root') AS score
    -> FROM articles WHERE MATCH (title,body) AGAINST
    -> ('Security implications of running MySQL as root');

    je n'arrive pas à recoder cette partie là de la requete dans ta classe à savoir WHERE MATCH (title,body) AGAINST ('Security implications of running MySQL as root')

    Crois tu qu'il serait possible pour toi d'implanter cette modif?

    Merci

    Guy

    • Très sincèrement ça me semble compliqué à intégrer car la requête est déjà très approfondie une fois l'automatisation lancée (en réalité la requête est très longue avec de nombreuses conditions, ça me semble difficile d'ajouter cette particularité sachant que cela imposerait la création de nouvelles colonnes dans la base de données que mon moteur ne fait pas...).
      Mon algorithme peut être gourmand en ressource en effet sur de nombreux résultats. Je suis désolé de ne pas pouvoir tout faire, et je manque pas mal de temps pour me démultiplier entre l'écriture de mes livres, de ces codes et de mes articles de blog notamment (sans oublier les formations que je dispense, sinon je ne mangerais pas beaucoup... :D).

      Actuellement, je travaille sur un système d'autocomplétion pour le moteur généré au fur et à mesure des recherches. L'objectif étant d'avoir une "option" en plus pour améliorer les recherches qui s'adaptera à tous les sites web automatiquement... :D

  • carde dit :

    Bonjour (à nouveau),

    J'ai essayé d'afficher les résultats obtenus en utilisant un rand(); Ca fonctionne mais le rand() est appliqué à toutes les pages (sans toutefois modifier le nombre de résultats sur lequel est calculé le nombre de pages à afficher.)
    la fonction moteur-affichage :
    moteurAffichage('affichage','', array(true, $_GET['page'],20),array(true, 'rand()',''),array(false,'algo','DESC','id'));
    ?>
    Il est possible que quelque chose m'est totalement échappé :p

    • Bonjour,
      C'est tout-à-fait normal (mais ingénieux, bien vu !) que le rand(); s'applique page par page. Les requêtes sont relancées page par page, c'est la technique habituelle pour les recherches avec pagination.

      Voici mon idée, même si je ne sais pas si je vais vous aider :
      - il faudrait générer un rand(); dans une variable $hasard (un tableau de données) pour récupérer les valeurs prises au hasard.
      - ensuite il faudrait exclure les valeurs déjà existantes du tableau $hasard à chaque nouveau lancement de la fonction rand();

      Ce n'est qu'une idée, mais je ne vois que ça, ça ne me semble pas si simple que ça à réaliser mais pourquoi pas... ^^

  • sabra dit :

    comment pourrais je adapter ce code a mon site ???

    • Je suis en train de faire quelques modifications sur le code là (je corrige 2-3 trucs pour que ce soit plus "propre") mais sinon, il suffit de suivre la démarche expliquée dans l'article. C'est un peu complexe pour les débutants, j'en conviens, mais j'ai essayé de faire au mieux... :S

  • sabra dit :

    j ai realiser un moteur de recherche pareil a votre et une pagination mais mon probleme et lorsque je navigue dans les page je suis forcer a taper la meme recherche dans chaque page !!!!!! comment pourais je fixer ce probleme svp !!

    • Tout d'abord félicitations. Si mon moteur aide à ce que d'autres en créent, je suis preneur... J'ai fait ça surtout car je ne trouvais aucun moteur complet (ou plutôt assez complet pour mes besoins) mais si d'autres personnes génèrent des codes quelque peu différents, ça me va. :D
      Toute l'astuce de la pagination réside dans les URL qui sont écrites sur les liens "page 1", "page 2" (...). Si vous ne passez que le paramètre "page=n" ("n" étant le numéro de page), ça ne pourra pas fonctionner car le moteur "perdra" la requête de recherche voire d'autres informations. Il faut donc ajouter le paramètre de la recherche ("q" pour query sur Google par exemple) dans ces liens pour renvoyer toujours la requête d'une page à l'autre...
      J'espère vous avoir guidé un peu ! :D

  • slicinga dit :

    Dommage que les requêtes soient obsolètes avec les nouvelles DB MySQL

    • Comment ça ? Vous aussi vous faites partis des anti mysql_query() ? Dans ce cas il suffit d'adapter le moteur avec PDO (une de mes idées pour l'anecdote, mais il faut penser que je fais une version PHP 4 alors j'ai préféré faire quelque chose de plus généraliste) ou avec mysqli_query() au pire...

  • Olivier dit :

    Bonjour,

    Merci beaucoup pour ce beau moteur !
    J'ai réussi à l'installer, il fonctionne.
    Par contre, je souhaite l'utiliser pour une recherche sur des téléphones (champs numériques) et là ça marche plus...
    Je pense qu'il y a un regex quelque part qui supprime tout les chiffres ?

    Merci beaucoup,
    Olivier

    • Bonjour,
      Ah oui j'ai dû me planter un regex alors, il faudra que je fasse le test avec une liste de chiffres, c'est pas idiot, mais si vous trouvez avant, tant mieux après tout ! ^^
      Là je suis en train d'adapter mes deux nouveaux systèmes de "pagination" (scroll infini ou par trigger) dans mon extension WordPress basée sur ce moteur, mais après, je pourrais sûrement m'y atteler un peu ! :D

  • Anthony dit :

    Bonjour,

    Merci pour ce formidable moteur !
    Je viens vers vous car j'ai un petit soucis que je n'arrive pas à régler et que je souhaiterais vous exposer. Ma table autosuggest contient énormément de mot, et lorsque que je commence à taper quelque chose, l'autosuggestion se fait. Cependant après la deuxième lettre généralement, il ne me suggère plus rien, comme si il cherchait dans les résultats suggérés mais pas si on tape une troisième lettre qui n'était pas présente dans ces derniers.
    Je ne suis surement pas très clair voici donc un exemple : si je tape "CA" une liste d’autosuggestion s'affiche. Si je continu en rajoutant un "B" il n'y a pas de soucis car "CAB" est déjà dans la liste d'autosuggestion. En revanche si je met un "R" à la place du B, il n'y a plus aucune suggestion car il n'a pas déroulé la liste jusqu’à "CAR" (même en ayant augmenté le nombre d'autosuggestions affichées dans une limite raisonnable).

    Merci beaucoup, Anthony.

    • Bonjour,
      Je suis très étonné de ce problème en effet, c'est bizarre. Il n'y a aucune option qui permet de limiter l'auto-suggestion à un nombre de lettres tapées précis, je viens de vérifier sur tous les sites sur lequel j'ai installé mon plugin et je n'ai pas le problème. Je suis étonné également qu'un gros index en soit la cause puisque c'est un système bête et méchant au fond, ça va chercher les mots correspondants et ça les affiche. Le problème est systématique, même sur des lettres pour lesquels il y a moins de mots ?
      J'avoue que je ne vois pas, il faudrait que je vois sur votre site si possible, n'hésitez pas à me donner le lien pour voir ça.

  • petite fée dit :

    Bonjour,
    et merci pour ce superbe travail, ainsi que votre suivi.
    J'essaye d'installer votre code de façon basique, avant de l'intégrer à mon site. J'ai rencontré un problème :
    j'ai le message suivant :
    Compilation failed: unknown property name after \P or \p at offset 7 in ...
    qui me renvoie à cette ligne (706) dans "moteur-php5.class-inc.php"
    Je suis en php 4. à part ça les résultats s'affichent bien, masi cette ligne d'erreur est présente à chaque résultat.
    comment puis-je le solutionner ?
    en vous remerciant par avance,
    E.

    • Bonjour,
      Aucune inquiétude à avoir, le problème vient de PCRE et de la suite "\p{Xan}" placée dans l'expression régulière. Vous pouvez soit remplacer ça par une suite comme "[a-zàáâãäçèéêëìíîïñòóôõöùúûü]", soit tout simplement supprimer les lignes correspondantes dans la class PHP (car cela n'aide que si vous avez activé l'option de recherche sans accent). En revanche, si vous êtes en PHP 4, je vous conseille de prendre la class adaptée, sauf si l'autre fonctionne bien... :D

  • petite fée dit :

    Re-bonjour Mathieu,
    j'ai également une autre question :
    quelque soit la page que j'affiche (moteur-autocompletion.php, moteur-infinite-scroll.php, moteur-normal.php) j'ai toujours strictement la même chose : le champ texte et le bouton envoyer. Les résultats sont identiques aussi (avec mon erreur compilation failed). pas d'auto-completion ni de scroll...
    Est-ce à cause de l'erreur de compilation ?
    Avec mes remerciements

    • Bonjour, c'est normal que vous ayez la même chose, j'ai juste appliqué des options et des fonctionnalités différentes en fonction des besoins.
      Il faut également prendre garde à ce que les fichiers adaptés à l'autocomplétion ou au scroll infini soient paramétrés. Regardez mon autre article sur le moteur de recherche dans lequel j'explique comment installer le scroll infini ou le trigger, etc.

  • petite fée dit :

    Merci Mathieu pour votre rapidité !
    cette correction a réglé le problème :
    remplacement de la ligne 706 par :
    if(preg_match('#[a-zàáâãäçèéêëìíîïñòóôõöùúûü][^a-zA-Z]#iu', $mot)) {
    Par contre, je n'ai toujours pas de différences de fonctionnalités selon les fichiers lancés.
    Merci encore !

  • petite fée dit :

    Je vous remercie, je vais m'y pencher.
    Merci encore pour votre sérieux et votre travail, ainsi que votre altruisme.

  • Darwin dit :

    Bonjour, j'ai essayé le moteur de recherche avec moteur-normal.php pour tester en y mettant ma BDD mais il trouve toujours 0 résultats, les lignes que j'ai modifiés sont :

    moteur-normal.php :
    $moteur = new moteurRecherche(stripslashes($_GET['q']), 'annonce', 'regexp', $stopwords);
    $colonnesWhere = array('titre_a', 'description_a');

    $texte .= "\t".$nb." - ".$key['titre_a']."\n";
    $texte .= "\t".$key['description_a']."\n";

    BDD.inc :
    $base = "test";
    $serveur = "localhost";
    $login = "root";
    $passe = "";
    $connect = new ConnexionBDD($base, $serveur, $login, $passe);

    Ai-je oublié de modifié d'autre données?

    • Hum je ne vois pas de problème particulier dans ces lignes en tout cas. Avez-vous bien pensé à avoir un "name" qui est "q" dans votre champ de recherche ?
      Testez l'exemple avec la base de données exemple que j'ai fourni au pire et le moteur normal de base. Si cela ne marche pas, alors il y a un problème de configuration chez vous car tout est bon chez moi. Une fois le test effectué et fonctionnel, vous pouvez réadapter petit à petit vers vos besoins, vous trouverez peut-être ce qui cloche. C'est sûrement des détails...

  • Darwin dit :

    J'ai essayé avec votre bdd table_search et le moteur marche parfaitement, c'est pour cela que je ne comprends pas pourquoi lorsque je mets la mienne, cela ne marche plus.
    Dans ma table annonce: titre_a,description_a sont en varchar

  • Darwin dit :

    Problème trouvé, j'ai changé 'regexp' par 'like' et la recherche fonctionne, par contre pourquoi la méthode regexp ne fonctionne pas ca je ne sais pas, encore merci !

  • Darwin dit :

    (Navré pour les reposts) non le moteur marche parfaitement, je testais en regexp des mots comme "un" "de" et donc il ne m'affichait aucun résultat mais pour des mots longs comme "volcan" il marche très bien, merci pour tout !

  • ornel1234 dit :

    Merci pour ce riche tuto concernant la recherche multicritère!!

  • Chris dit :

    Bonjour Mathieu et un grand bravo pour ce partage énorme !

    Chez moi la classe ne fonctionne pas : j'obtiens cette erreur :
    Fatal error: Call to a member function query() on a non-object in /homepages/xx/xxxxxxxx/htdocs/blog/moteur-php5.class-inc.php on line 437

    J'ai testé ma variable $_GET['moteur'] avec un echo : c'est OK, mon terme de recherche (mot clef) est bien transmis
    J'ai aussi fait un print_r sur le contenu de la fonction query() qui pose pb à la ligne 437 :
    print_r("SELECT $selectColumn FROM $this->tableBDD WHERE $this->condition $this->orderBy $this->limitMinMax") or die("Erreur dans la requête finale, vérifiez bien votre paramétrage complet !");
    Et voilà ce que ça m'affiche :
    SELECT * FROM fulltext WHERE MATCH (titre_article, contenu_article) LIKE CONVERT(_utf8 '%_blog_articles%' USING utf8) LIMIT 0, 10
    Apparemment, les variables et paramètres de la requête sont dans le désordre : j'ai "fulltext" à la place de ma table "_blog_article", j'ai le nom ma table "_blog_articles" dans la claude WHERE, à la place de ma variable $_GET['moteur'], et puis la syntaxe même de la requête générée par cette classe PHP me paraît erronée : en fulltext, je devrais plutôt avoir : "SELECT * FROM ma_table WHERE MATCH (colonne1,colonne2) AGAINST ('motclef')" ???
    De toute façon, en réécrivant temporairement cette ligne 437 de la classe PHP, avec une requête sans variable et qui fonctionne pour avoir été préalablement testée dans PHPMyAdmin :
    $this->requeteTotale = $this->db->query(SELECT * FROM _blog_articles WHERE MATCH(titre_article,contenu_article) AGAINST ('mon_mot_clef') LIMIT 0, 10") or die("Erreur dans la requête finale, vérifiez bien votre paramétrage complet !");
    ...j'obtiens toujours la même erreur :
    Fatal error: Call to a member function query() on a non-object in /homepages/xx/xxxxxxxx/htdocs/blog/moteur-php5.class-inc.php on line 437

    Et pourtant, j'ai bien toutes les inclusions requises, et j'ai bien créé un objet $moteur comme indiqué :
    $moteur = new moteurRecherche(stripslashes($_GET['moteur']), '_blog_articles', 'fulltext', $stopWords);
    $colonnesWhere = array('titre_article', 'contenu_article');
    $moteur->moteurRequetes($colonnesWhere);
    if (isset($moteur)) {
    echo 'Résultats de la recherche : '.$moteur->requete.'';
    function affichage($requete, $nbResults, $mots) {
    .....
    }
    ...
    }
    où echo 'Résultats de la recherche : '.$moteur->requete.'' m'affiche :
    "Résultats de la recherche : _blog_articles" (_blog_articles étant le nom de ma table !)
    au lieu, je suppose, de m'afficher "Résultats de la recherche : mon mot clé"

    (j'ai un hébergement mutualisé chez 1and1 avec version PHP 5.5 et moteur mySQL 5)

    Je patauge complètement, alors si tu as déjà rencontré ce type de bizarrerie, je te remercie de bien vouloir m'en faire part, ou me donner qq pistes ???
    Merci et @+

    • Bonjour,
      En fait je pense que c'est une erreur dans le placement des paramètres de la fonction, d'où le décalage de "fulltext" en lieu et place du nom de table, etc.
      J'ai créé plusieurs versions du moteur de recherche mais malheureusement, la version PHP 5.5 (je suppose que tu utilises celle-là) demande un paramètre supplémentaire. C'est de ma faute car je ne l'ai pas précisé en commentaire, mea culpa ! :(
      En gros, le premier paramètre de l'objet MoteurRecherche est la connexion à la base de données (stockée dans une variable) car c'est un sécurité supplémentaire obligatoire en PHP 5.5. Je te conseille de télécharger le pack complet du moteur dans l'article et de bien regarder le lancement de l'exemple en PHP 5.5 par rapport à celui en PHP 5 classique, tu verras un $link en premier paramètre en plus, c'est la fameuse connexion...
      Je pense que ton problème bien de là ! ^^

  • louis dit :

    Bonjour

    Je ne parviens pas à saisir comment réaliser la table d'autocompletion, vous parler d'un argument $create = true à mettre où exactement?

    Merci

    • Bonjour,
      Il faut regarder au sein du fichier contenant la class PHP qui applique l'autocomplétion, elle est appelée autoCompletion() justement. J'ai mis des commentaires au-dessus qui précisent le rôle de chaque paramètre. Il y a 10 paramètres pour cette méthode, le $create étant le 9e (un booléen true/false pour activer ou non l'auto-génération de la table d'auto complétion du moteur de recherche).

  • traore dit :

    svp, j ai des difficultés avec ton code car je suis nouveau dans le développement php.
    $moteur = new moteurRecherche(stripslashes($_GET['q']), 'TABLE_SQL', 'regexp', $stopwords);
    // PHP 5.5. : $moteur = new moteurRecherche($link, stripslashes($_GET['q']), 'TABLE_SQL', 'regexp', $stopwords);
    on me dit undifined index "q" que dois je faire merci

    • Bonjour,
      Il faut bien commencer un jour, ne vous inquiétez pas, les erreurs sont humaines, surtout que le moteur n'est pas le moins complexe du marché ici...
      Concernant le paramètre "q", il correspond à l'attribut name="q" du champ de recherche en HTML. Si vous avez appelé ce dernier avec un autre name, il faut alors modifier le $_GET['q'] par votre propre valeur sous la forme $_GET['VOTRE-VALEUR']. En gros, votre moteur ne doit pas utiliser le paramètre "q" dont il vous dit qu'il ne le connait pas...

  • traore dit :

    si vous pouvez dans votre code indiquez les parties a personaliser avec ma base de donnee.
    NB : je faire des recherches dans ma table qui s'appel offre
    le champs est OfferName.
    merci de m'indiquer quoi faire ?
    BEST REGARDS!!!

    • Dans votre cas, voici les trois premières lignes de paramétrages (faites juste attention au paramètre "q" comme indiqué dans ma réponse précédente...
      if(isset($_GET) && !empty($_GET['moteur'])) {
      $moteur = new moteurRecherche($link, stripslashes($_GET['q']), 'offre', 'regexp', $stopwords);
      $colonnesWhere = array('OfferName');
      $moteur->moteurRequetes($colonnesWhere);
      }

  • traore dit :

    MERCI! CETTE ERREUR N AFFICHE PLUS .
    QUAND JE SUIS VOTRE INSTRUCTION IL N YA PLUS DE PROBLEME AVEC LE q/ MERCI
    MAIS QUAND JE FAIS UNE RECHERCHE RIEN AFFICHE.

    • Normalement, tout l'article est un tutoriel à suivre pas à pas. Les lignes que je vous ai indiquées sont les premières à entrer, il faut ensuite créer un formulaire de recherche (mais ça, vous l'avez fait puisque vous pouvez faire une recherche) et enfin, il faut créer la fonction que j'ai appelée "affichage" dans mon exemple, l'adapter à vos besoins puis l'afficher.
      Dans la fonction affichage(), faites juste attention à bien afficher le résultat de ce que vous voulez. Dans mon exemple, il y a ces deux lignes :
      $texte = "
      ".$key['titre']."
      ";
      $texte .= $key['contenu']."
      ";
      Cela ne veut pas dire que pour vous, vous voulez afficher le contenu des colonnes "titre" et "contenu" de votre table de base de données, il faut donc personnaliser les paramètres ici.
      Tout le reste est expliqué. Au pire, téléchargez le pack du moteur de recherche, copier un exemple et modifier uniquement les quelques paramètres dont vous avez besoin. Dans votre cas, si le moteur n'affiche rien (mais pas d'erreur !), cela signifie que le moteur fonctionne mais qu'il n'a aucune donnée à afficher, donc soit votre base manque de données, soit les paramètres d'affichage de la fonction affichage() ne sont pas bons.

  • Renaud dit :

    Bonjour et bravo pour cet énorme travail très méthodique et très documenté.
    J'ai toutefois un problème avec les accents :
    A noter : Mes champs SQL pour la recherche sont encodés utf8_bin. Du coup dans phpMyAdmin, on lit "Vésicule" au lieu de "Vésicule".
    Pour les réglages de ton script, j'ai mis accents à true et utilise regexp et UTF-8.
    Dans la classe php5, j'ai fait un affichage de requête.
    Si je recherche le mot "vesicule" :
    SELECT * FROM table WHERE (id REGEXP CONVERT(_utf8 'vesicule' USING utf8) OR nom REGEXP CONVERT(_utf8 'vesicule' USING utf8)) AND etat=1 LIMIT 0, 100

    Pas de résultat. Mais pas non plus pour "vésicule" ou "Vésicule" (ce dernier étant le mot figurant dans le champ "nom", sous la forme "Vésicule".
    Que dois-je modifier ?
    Merci d'avance pour ton aide.

    • Bonjour,
      Je ne crains que cela soit dû à ton encodage en effet. J'ai testé le moteur essentiellement avec les encodages "classiques", à savoir utf8_general_ci (bien différent de utf8_bin !) et latin1. Le problème doit se situer au niveau de mes requêtes qui sont adaptés à ces deux encodages essentiellement, il faudrait soit que je rajoute un paramètre pour que tu personnalises la collation (interclassement dans MySQL)...
      Il faudrait que tu essaies de modifier la variable $encode = "utf8"; dans la class PHP (méthode privée requestKey) par $encode = "utf8_bin";
      Je ne peux pas te garantir de résultat car tes données sont encodées en binaire contrairement à un interclassement classique, mais ça devrait apporter une bribe de solution...

      L'option "accents" du moteur est surtout destinée aux langues étrangères, ça supprime tout accent des requêtes pour chercher dans des bases de données de mots sans accents, ça ne peut donc pas t'aider ici. J'hésite même à supprimer cette option pour tout dire (je prévois de réécrire complètement le moteur quand j'aurais le temps, de manière plus "PHP objet" et avec de nouvelles idées)...

  • Renaud dit :

    Bonsoir Mathieu, merci d'avoir répondu si vite. En fait j'ai re-modifié le champ "nom" de ma table en utf8_general_ci et ça ne change rien. Pour tout te dire, il était encodé comme cela mais comme j'ai lu que dans ton article que _ci n'était pas bon pour la casse, je l'avais passé en bin.
    Je voudrais vraiment que le mot sorte, qu'il soit avec ou sans accent, avec ou sans majuscule. J'ai passé le champ en index fulltext et modifié ton script en conséquence. Mais la requête "SELECT * FROM table WHERE MATCH (nom) AGAINST(CONVERT(_utf8 'vesicule' USING utf8) IN BOOLEAN MODE) AND etat=1 LIMIT 0, 100" ne donne rien non plus.
    Pourtant je sens que c'est possible !

    • utf8_general_ci est insensible à la casse et passe parfaitement avec les accents, au contraire ! :D
      Il ne s'agit que d'un souci d'encodage dans notre cas, il faut que l'encodage côté PHP et celui côté MySQL cohabitent en gros.
      En théorie, tu devrais obtenir une requête du genre SELECT * FROM table WHERE MATCH (nom) AGAINST(CONVERT(_utf8 ‘vesicule’ USING utf8_bin) IN BOOLEAN MODE) AND etat=1 LIMIT 0, 100

      As-tu essayé également d'encoder ta requête avec utf8_encode() ou utf8_decode(), ça pourrait peut-être aider...

      Sinon, tu peux tenter une conversion "en dur" avec quelque chose comme ça : ALTER TABLE

      CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
  • Renaud dit :

    Bonjour Mathieu,

    Je viens de faire une série de tests :
    Mes champs sont maintenant tous en utf8_general_ci, comme auparavant.
    Les accents, côté PhpMyAdmin, sont toujours encodés.
    Dans ta fonction, le param "accent" est à false.
    Enfin, J'ai mis un utf8_encode sur le mot clé.
    En fulltext :
    Mot clé "vésicule" ou "Vésicule" : ça matche, insensible à la casse.
    Mot clé "vesicule" ou "Vesicule" : nada
    En regexp :
    Les deux exemples ci-dessous ne retournent rien.

    Sans l'encodage utf8 du mot-clé.
    En regexp : rien ne sort, ni "vésicule", ni "vesicule".
    En fulltext : rien non plus

    Conclusion, en fulltext et en encodant le mot-clé, j'obtiens les meilleurs résultats, à condition que le mot saisi soit accentué, sinon, que dalle.

    Autre test : le champs SQL est toujours en general_ci, mais j'ai modifié le mot et écrit manuellement "vésicule" à la place de "vésicule".

    En regexp et utf8_encode du mot : rien ne sort, avec ou sans accent, avec ou sans MAJ.
    En regexp sans encodage : "vésicule" sort, mais pas "vesicule"
    En fulltext sans encodage : "vésicule" sort et "vesicule" sort aussi, avec ou sans MAJ
    En fulltext avec encodage : "vésicule" ne sort pas et "vesicule" sort.

    Conclusion : le mieux est sans doute fulltext sans encodage, à condition que je modifie toute ma table pour le champ "nom" afin que les accents soient écrits en clair. Pas gagné...d'autant que les requêtes INSERT encodent automatiquement les entrées en caractères pourris sans que je ne donne d'instruction précise...

  • lezabour dit :

    Bonjour,

    Bravo pour cet article, tres precis.
    Par contre, je ne trouve pas le lien pour telecharger les sources, et je ne peux donc tester ;(
    il y a plusieurs erreurs sql qui s'affiche sur l'article, peut etre que quelque chose est mal placé
    pouvez vous fournir le lien?

    merci

    • Bonjour,
      J'ai ce problème récent sans rien avoir changé à mon blog, c'est à cause d'une mise à jour de l'extension Download Manager, j'ai donc remis l'ancienne pour résoudre le souci. :D

  • dembetta dit :

    merci pour cette article sa m'aide vraiment bcp :D

  • Gost dit :

    Bonjour, ce petit moteur de recherche est super c’est exactement ce que j’attendais, bravo !
    Mais petite question, pour l’intégré a un site intranet existant, peut ton paramétrer l’url de recherche, car quand on clique sur « rechercher » il efface toutes les variables pour y mettre la requête genre monsite/?q=query
    C’est paramétrable ?

    • Bonjour,
      Merci pour les compliments.
      Normalement, vous n'avez pas à perdre les autres paramètres de requêtes. Si tel est le cas, l'astuce est de passer ces paramètres complémentaires dans l'attribut "action" du formulaire de recherche ou dans des champs de type "hidden". Le moteur en lui-même n'a pas d'incidence là dessus, il faut juste paramétrer le reste en parallèle. :D

  • Gost dit :

    Bonjour,
    Et merci de m’avoir répondu aussi tôt, je n’ai pas précisé mais je parlais des variables de type GET contenue dans mon url, en modifiant cette balise : si je recherche « test », au moment d’appuyer sur le bouton rechercher rien n’y fait mon url est modifiée de http://monsite/?toto=c&roro=b est modifier en http://monsite/?q=test
    En effet toutes les pages de mon portail son appeler par l’index, si il n’y as pas de solution simplifier je vais faire une exception pour le moteur de recherche du genre http://monsite/search.php?q=test
    Ou passer mes variables GET en session si la variable $_GET[‘q’] est chargée.
    En tout cas je le redit encore très bon boulot et très intéressant à manipuler !

    • Bonjour,
      Donc si vous en dans le cas des variables GET, il faut modifier l'attribut "action" de votre formulaire de recherche. Pour se faire, il faudrait taper action="?toto=c&roro=b". Normalement, ça pourrait marcher, mais il est vrai qu'il y a de grandes chances que le "search.php" s'ajoute dans l'URL malheureusement, mais ceci est indépendant du moteur au fond car à aucun moment je ne fais appel à "search.php" dans le code, c'est le formulaire qui fait appel au fichier.

  • Gost dit :

    Re-bonjour,

    " Pour se faire, il faudrait taper action=”?toto=c&roro=b”. Normalement, ça pourrait marcher"

    Cela ne fonctionne pas, sans doute une limitation du jquery ?

    Ce n’est pas bien grave je vais trouver une solution de contournement :)
    Merci pour votre réponse en tout cas et bonne continuation je garde ce site dans mes favoris, @bientôt !

    • Hum bizarre là... Il est vrai qu'il y a l'ajax de jQuery si vous l'utilisez dans les paramètres profonds du moteur mais normalement, ça ne devrait pas impliquer ça.
      En tout cas merci et désolé de ne pas résoudre votre problème là. :S

  • Georges dit :

    Bonjour,

    Très bon travail ! Merci beaucoup pour le partage. J'ai fait quelques tests et apparemment c'est tout de même difficile de gérer une grosse base de données (>100 Mo) sans que le temps de chargement ne soit vraiment long (en utilisant votre algo de tris). Avez-vous des astuces pour y remédier ?

    Bonne soirée !

    • Bonjour,
      Non sincèrement je ne vois pas trop, il faudrait gérer les threads pour des grosses bases de données ou modifier le fonctionnement de l'algorithme (qui double la requête pour classer, tout bêtement). Je vais changer l'algorithme à terme mais je manque de temps pour tout réécrire, c'est très embêtant. Mon objectif est de réécrire tout le moteur plus proprement en PHP objet pour optimiser l'ensemble, j'avais fait ça "vite" à l'époque et il y a plein de points à booster.
      Dans votre cas, il y a effectivement beaucoup de données donc ça va forcément demander un traitement plus long, notamment si vous utilisez l'algorithme, ce n'est pas pour rien que les gros moteurs de recherche passent par des datacenters et non par un seul script comme le mien. Il faudrait vraiment trouver un moyen de "requêter" les recherches en gérant les threads (mise en attente au niveau du serveur), mais là, c'est coton car ce n'était pas prévu dans le script d'origine. :S
      Désolé de ne pas pouvoir vous aider beaucoup plus à court terme.

  • Georges dit :

    Merci pour la réponse rapide.

    Oui à moi aussi ça me semblait difficile. En tous cas merci pour les pistes que vous m'avez données, je vais travailler sur ce point de mon coté en essayant de vous tenir au courant ! :)

  • Gilles dit :

    Hello,
    je suis tombé ce matin sur ta classe de recherche et franchement super boulot.
    Le code est super bien documenté et je m'y suis retrouvé sans soucis.
    J'ai testé la recherche en regexp et like. Pas encore tester le fulltext.
    J'ai été surpris de voir que le surlignage ne fonctionnait pas... jusqu'à ce que je trouve que sur mon exemple pour test, les infos recherchées étaient systématiquement dans titre en qui était déjà en gras! En passant le surlignage en blue, tout de suite c'était mieux.

    J'ai juste un tout petit peu adapté pour mon besoin: quand un + est saisie dans la recherche, je force le $operateur en AND, sinon je le laisse en OR. Cela me permet rapidement de restreindre ou non la recherche.
    Je n'ai plus qu'à continuer à travailler dessus et intégrer cela à mon appli.

    Je n'ai pas encore regardé l'algo de pertinence.

    Un grand merci!
    Gilles

    • Merci pour vos douces remarques, c'est super sympa !
      Je prends note également pour l'idée restrictive que vous avez ajoutée, ça pourrait être pertinent que je rajoute ça à l'occasion.
      Bon courage en tout cas et encore merci.

  • Romain dit :

    Bonjour,

    Je suis débutant en PHP et j'aimerais poser une question bête : les fichiers proposés ici je dois les insérer quelques part dans mon code ou simplement les mettre dans le même dossier ?

    Merci d'avance

    • Bonjour,
      Il faut toujours "inclure" (ou importer si vous préférez) les fichiers dans le code qui l'utilise. C'est pourquoi il y a des "include" dans le code d'exemple, ils permettent d'aller chercher les méthodes de Class nécessaires dans les fichiers utiles. ;-)

  • Romain dit :

    Merci beaucoup :)

    Et j'ai vu que ça enregistrait les recherches effectués ? c'est bien ça ?
    Son utilité est que si on revient ça se souvient ?

    • De rien ! ;-)
      Alors oui et non pour les recherches, ça enregistre les requêtes pour le système d'autocomplétion si ce dernier est activé (ainsi, les recherches sont sauvegardées et proposées lors de la saisie), mais ça ne fait pas encore de statistiques, etc. (mais j'avoue que l'idée est bonne maintenant que vous le dîtes ! :D).

  • Bouffard dit :

    Bonjour,

    J'ai l'ajout d'une toute petite chose à ta class de recherche.
    Je cherchais le moyen de retirer des enregistrements de la requête.
    J'ai une BD qui contient un champs état. Mon but était de retirer de la requête les éléments "désactivés". Pour rechercher et afficher uniquement les éléments actifs.

    J'ai fait l'ajout d'un paramètre à la fonction moteurRequestes
    /*---------------------------------------------------------------------------*/
    /*-- Méthode de conception de la requête de recherche avec 2 paramètre ------*/
    /*-- 1. Tableau des colonnes dans lesquelles chercher (condition WHERE...) --*/
    /*-- 2. Condition WHERE de recherche personnalisée --*/
    /*---------------------------------------------------------------------------*/
    public function moteurRequetes($colonnesWhere = array(), $whereperso) {
    le code standard de la fonction.... bla bla bla
    Code perso ajouté à la fin de la fonction

    if ($whereperso!="") $query .= $whereperso; // Ajouter une requête perso.
    // récupération de la requête de recherche du moteur
    $this->condition = $query;

    }

    Dans le code de la page web je peux alors passer un paramètre qui contient du code dans la fonction exemple: $moteur->moteurRequetes($colonnesWhere,'AND etat=1'); // si l'état est = à 1 (actif).

    Je ne sais pas si cet ajout aura une incidence sur l'ensemble de la class et de toutes ces options. J'utilise les paramètres par défaut. Mais pour ma part ça fonctionne bien et j'obtiens que les résultats souhaités.

    Cordialement

    • Tu peux très bien faire cet ajout en effet. En ce qui me concerne, j'ai ajouté un équivalent dans ma Class pour mon plugin de recherche sur WordPress (car WordPress nécessitait ce paramètre supplémentaire), mais pas au même endroit. L'essentiel est que ça marche, et de la façon dont tu concatènes, ça me semble très bien ! :D

  • lerry dit :

    bonjour!j'arive pas à faire fonctionner votre moteur avec ma base de données,on m'affiche "Erreur dans la requête finale, vérifiez bien votre paramétrage complet !".
    Hors quant j'utilise la base de donnée fournie en exemple "table_search.sql"ca marche.merci de m'aider!

    • Bonjour,
      Avez-vous bien fait attention, à l'ordre des champs, à bien modifier le nom des champs dans lesquels vous recherchez, etc. C'est un problème de requête de recherche donc un paramètre doit générer l'erreur, et cela peut-être un problème de champs ou de réglages de la première méthode du moteur.

    • Matxi dit :

      iep,
      j'ai le même soucis… impossible de parvenir à le surmonter…

      $moteur = new moteurRecherche($_MA_CONNECTION, stripslashes($_POST['moteur']), 'LE_NOM_DE_MA_TABLE', 'regexp', $stopwords, 3);
      // tableau des colonnes dans lesquelles effectuer une recherche
      $colonnesWhere = array('LE_NOM DE_MA_COLONNE_1', ''LE_NOM DE_MA_COLONNE_2', ''LE_NOM DE_MA_COLONNE_3', ''LE_NOM DE_MA_COLONNE_4');

      et il m'affiche toujours "Erreur dans la requête finale, vérifiez bien votre paramétrage complet !"… je ne vois pas quel paramètre lui manque ou le gène…

      merci d'avance pour votre aide

      • Hormis le problème des guillemets simples et doubles dans le tableau de $colonnesWhere, rien ne me choque ici.

      • Matxi dit :

        ah tiens! non, je n'ai pas d'alternance de guillemets simples-doubles…
        au cas où je viens de passer tous les appels mysqli en PDO mais c'est pareil…

      • Dans l'exemple donné, il y avait le problème entre les guillemets, c'est pour ça que je disais cela, mais dans votre code peut-être pas. En général, il s'agit d'une erreur d'un paramètre (souvent un décalage d'un paramètre par exemple) qui provoque ce type d'erreur. Dites-vous qu'entre la version PHP 5.5 du moteur et les autres, un paramètre change parfois, donc un décalage est vite arrivé. Il s'agit souvent d'une erreur toute bête comme ça, mais comme on a le nez dedans, on ne la voit pas. :D

  • P. Villain dit :

    Bonjour,
    je viens de découvrir votre moteur de rechercher et je souhaiterai le tester sur une base de données que j'alimente actuellement. Si j'ai bien saisi la méthode général, il y a un élément que je n'ai pas saisi : où se trouve les variables définissant le nom de la table et les noms des colonnes sur lesquelles doivent porter la recherche ?
    Avec mes plates excuses si cette question parait bête, mais je suis un simple amateur et non un spécialiste de la programmation.

    • Bonjour,
      Il n'y a pas de mal, c'est dans l'étape 4 présentée dans l'article que vous allez indiquer ces informations. J'ai mis "TABLE_SQL" en majuscules là où vous devez indiquez la table cible et en-dessous, il y a la variable $colonneWhere qui est un tableau (array) contenant la liste des colonnes ciblées.

  • popaul dit :

    Tutoriel parfait.

    Pour la fonction de pagination, et afin de coller au script de seebz pour les séparateurs, j'ai été obligé d'ajouter une span ayant la class "gap" à votre code comme suit :

    public function moteurPagination($instruction = 0, $param = "page", $NbVisible = 1, $debutFin = 1, $suivPrec = true, $firstLast = false, $arrayAff = array('', '', '', '', 'precsuiv', 'current', 'pagination', 'inactif'), $arraySeparateur = array('', ' ', ' ', ' ', ' ')) {

    Autrement, je ne voit pas de moyen pour afficher les séparateurs.
    Est-ce correct ?

    Encore merci pour ce tutoriel qui répond à un réel besoin.

  • Alain dit :

    Bonjour,

    Très bon moteur de recherche.

    J'ai un petit problème pour les "œ" dans la recherche cela fonctionne très bien ex : œuvre, il me retrouve bien tous les textes contenant la recherche, mais lors de la "Fonction d'affichage des résultats" il ne m'affiche que "uvre" et dans le code source de la page "œuvre".

    Toute mes tables sont codées en utf-8, j'ai cherché mais comme je suis débutant, pas trouvé.

    J'ai regardé aussi dans les commentaires pas vu non plus.

    Je vous remercie d'avance pour la réponse.

    Cordialement, Alain

    • Bonjour,
      De ce que je sais, les ligatures plantent assez souvent dans MySQL. Ici, cela ne semble pas être le cas puisque la recherche fonctionne, cela voudrait dire que c'est un souci de restitution plutôt, ce qui est surprenant puisqu'il n'y a que de l'UTF-8 sur WordPress. Je vais essayer de voir ça prochainement car ça m'intrigue ! :D

  • Alain dit :

    Merci de votre réponse rapide, c'est pas trop grave je vais changer “œ” en "oe" en attente d'une solution.

    Encore merci, Alain

  • Seb dit :

    Bonjour et un grand merci pour ce moteur de rechercher très puissant !

    Je suis en train de le tester pour un projet, tout fonctionne correctement. Je rencontre cependant un petit problème de caractères qui, je crois, vient de l'encodage.
    Un exemple : si j'effectue une recherche avec le mot "château", rien ne s'affiche alors que j'ai au moins 20 entrées dans la bdd. Le résultat et le même avec "chateau"... . En revanche, la recherche fonctionne avec "château", mais les résultats s'affichent également sous cette forme...plutôt difficile à lire :D !
    Ce qui m'étonne est que toute ma table est bien en utf8_general_ci... il y a un truc que je ne dois pas comprendre.
    Ça fait quelques jours que je planche dessus, mais je n'arrive pas à comprendre. Auriez-vous une idée salvatrice?

    Seb

    • Il s'agit effectivement d'un problème d'encodage, et pour tout dire, c'est certainement la pire chose qui puisse arriver. Si ça fonctionne avec “château”, c'est qu'il y a un problème car ce n'est ni de l'UTF-8, ni de l'ISO-8859-1. Je pense que votre problème est que les données sont rentrés dans un autre encodage au sein de tables en utf8. De fait, on peut croire qu'il s'agit d'UTF-8 mais en fait, non. J'ai eu de gros problèmes avec les encodages Macintosh notamment qui me provoquaient des problèmes similaires.
      Le souci également, c'est que PHP permet assez facilement d'osciller entre UTF-8 et ISO-8859-1, ce que fait mon moteur, mais pour les autres encodages, c'est beaucoup plus obscur voire impossible. :(

      • Seb dit :

        Merci beaucoup pour votre réponse.
        Je comprends que je suis face à un beau problème. J'ai modifié la base en remplaçant par exemple "é" par "é", du coup ça fonctionne... En revanche, après avoir saisie un mot avec "é", la table autosuggest affiche elle "é". Je ne vois pas comment faire pour alimenter la base correctement... je suis un peu perdu (et navré de poser ces questions sans doute de débutant).

      • Ce ne sont pas des questions de débutants car l'encodage est un vrai problème dans le web. Les choses se sont bien arrangées avec l'UTF-8 mais malheureusement, il traîne encore de nombreux encodages problématiques (MS-1252 sur Windows, Macintosh sur Mac, etc.), rien que pour des langues courantes...
        Normalement, mes paramètres de création de table sont par défaut en UTF-8, donc la table autosuggest aussi, sauf si vous avez modifié l'encodage. Je doute que ce soit le cas donc si les mots sont "mal" enregistrés, c'est bien qu'il y a un problème d'encodage au niveau de votre base de données MySQL. Peut-être pas au niveau des tables en elles-mêmes, mais peut-être au niveau de la base en général. Pour voir ça, il faut aller dans l'onglet "Opérations" de PhpMyAdmin, ça permet de voir l'encodage mis aux tables par défaut.
        Si ce n'est pas cela, j'ai une autre "idée" qui pourraient causer ce problème, et qui est probable. Il est possible que les fichiers sources dans lesquels le moteur est installé ne soit pas encodés en UTF-8, donc au moment de transférer les données, cela plante. Cela m'est déjà arrivé alors que tout était sensé être en UTF-8 (en apparence). Si vous utilisez un logiciel comme Notepad++ par exemple, l'encodage est écrit en bas à droite et ne doit pas être ANSI (ISO en général) ou autre, mais UTF-8 ou UTF-8 sans BOM.

      • Seb dit :

        merci pour ces pistes. En effet, je n'ai pas modifié l'encodage de la table autosuggest. Du coup, je viens de vérifier ma base de données dans PhpMyAdmin, elle est bien en utf8_general_ci. Mes fichiers sources sont en UTF-8 sans BOM...
        Je ne vois vraiment pas d'où peut venir ce problème.

      • Très étonnant en effet car ça ne devrait pas du tout faire ça. Dernière solution que j'ai en tête, avez-vous copié vos contenus d'un autre logiciel ? Par exemple, copier du contenu de Word vers un fichier HTML peut engendrer des problèmes d'encodage.
        Il y a une astuce pour tester, vous pouvez par exemple vous rendre dans votre fichier source, vous recopiez tout son contenu avec CTRL+A puis CTRL+C. Ensuite, vous créez un nouveau fichier en UTF-8 sans BOM et vous collez le contenu. Vous enregistrez ce fichier pour écrasez l'ancien (donc avec le même nom). J'ai eu ce problème avec mon annuaire web et en faisant ainsi, ça me "nettoyait" mes problèmes d'encodage, alors que tout semblait parfait en apparence. Le problème dans votre cas, ça que c'est la base de données qui est "infectée", il faudrait presque supprimer la table autosuggest et la recréer après avoir fait ça pour vérifier si les accents rentrent bien dedans.

    • Seb dit :

      A priori, je n'ai fait aucun copier-coller. Dans le doute, j'ai nettoyé mon code suivant la méthode que vous m'avez expliqué... rien n'a changé. J'ai donc repris tout depuis le début : j'ai télécharger à nouveau pack complet, j'ai crée un nouvelle base de données mysql et j'ai importé les table de table_search. Je n'ai ouvert aucun fichier source à l'exception de BDD-PHP5.5.class-inc.php pour faire la connexion vers la base. Autosuggest ne prend toujours pas les accents : effectuer un recherche sur "épée" enregistre "épée" dans la table (et s'affiche ainsi dans le menu des mots suggérés).

      • Alors là, j'avoue que je ne sais plus trop quoi conseiller. Je suis allé vérifier dans mes bases de données si j'avais un souci similaire partout où j'utilise le moteur, et ce n'est jamais le cas. Il est certain que le problème provient de votre base de données, mais quelle est la source du problème, je suis bien incapable de la donner. :(

      • Seb dit :

        merci pour votre aide. J'ai finalement dû reprendre une bonne partie de la base de données. Je pense que le problème vient d'un mauvais encodage lors de la création de la base et d'une mauvaise gestion de son alimentation ensuite... . Bref, tout semble être dans l'ordre maintenant. Ça m'aura permis de faire un peu de ménage et d'en apprendre plus sur l'encodage (et le vaste problème qu'il peut induire). Merci encore !

  • Renaud dit :

    Bonsoir Matthieu, bravo pour la nouvelle présentation et les explications fournies.
    Il y a un truc que je ne capte pas : des mots clefs ne retournent rien alors qu'ils sont présents dans la table. Ca concerne surtout des produits que j'ai ajoutés récemment. J'ai affiché la requête et l'ai balancée dans MyAdmin et ça matche.Les champs sont bien index fulltext, mais on dirait que toutes les dernières entrées des tables sont ignorées...je sais ça parait dingue. Déjà entendu parler de ça ?

    • Bonsoir,
      Seulement les nouveaux mots clés qui ne sont pas pris en compte ? Problème d'encodage sûrement, soit du fichier en lui-même, soit de la base de données, soit lors du transfert des données. Je ne vois que ça pour expliquer un tel souci. :(

  • Renaud dit :

    Bonjour, j'ai fait des tas de tests, c'est du délire. A partir d'un certain enregistrement de la table, ça ne retourne plus rien ! Et rien n'est différent dans la table. Avant cet enregistrement tout fonctionne bien. C'est dingue, on dirait que le moteur ne scrute pas toute la table...
    Cette requête ne retourne rien alors que le mot "jazz" est dans le champ "nom".
    SELECT id,TRIM(nom) AS nom FROM gamme WHERE MATCH (nom, descriptif) AGAINST(CONVERT(_utf8 'jazz*' USING utf8) IN BOOLEAN MODE) AND etat='1' AND on_site='1' ORDER BY algo DESC, nom ASC LIMIT 0, 50
    Celle-ci retourne 2 résultats, mot-clef également présents dans le champ "nom":
    SELECT id,TRIM(nom) AS nom FROM gamme WHERE MATCH (nom, descriptif) AGAINST(CONVERT(_utf8 'filtration*' USING utf8) IN BOOLEAN MODE) AND etat='1' AND on_site='1' ORDER BY algo DESC, nom ASC LIMIT 0, 50

    Les deux requêtes retournent correctement quand utilisées dans phpMyAdmin.
    Comprends rien.

    • Attention, je ne sais pas si c'est ça la différence, mais vous écrivez "jazz*" dans la requête alors que vous me dites que vous cherchez le mot "jazz", ce qui correspond alors à "jazz" dans la requête. Le FullText utilise l'étoile pour chercher tout ce qui commence par jazz dans votre cas, c'est différent du mot en lui-même. Je ne dis pas que le problème est ici, loin de là, mais effectivement il y a des différences.
      Qui plus est, mon moteur de recherche n'utilise pas le FULLTEXT au sens propre, mais seulement une partie des fonctionnalités, je tiens à le préciser. Au début, je n'avais pas implémenter la méthode, j'avais donc tout programmé pour LIKE et REGEXP. Quand j'ai rajouté FULLTEXT, qui est plus complet, cela a forcément fait perdre quelques valeurs. En revanche, pourquoi ça ne prend qu'une partie des résultats, c'est très très étonnant. :(

      • Renaud dit :

        Merci Matthieu, de te pencher sur mon souci. Sympa.
        En fait "jazz" est le terme saisi dans le champ de formulaire et le "jazz*" est celui qui est affiché dans la requête de ton script. Que j'ai simplement collé dans MyAdmin...qui retourne bien le résultat.

      • Ah, donc le problème est peut-être là. La question est de savoir pourquoi mon script te rajoute ce fameux "*". Je viens de scruter tout mon code dans l'ordre d'établissement de la requête SQL et à aucun moment j'ai quelque chose qui génère une étoile en fin de mot en FULLTEXT. Qui plus est, je ne comprends pas trop les "etat=1" et "on_site=1" dans la requête, c'est vous qui avez ajouté ça ?
        Je peux vous donner un conseil pour essayer de trouver éventuellement où le problème se produit. Allez dans la class PHP du moteur de recherche, à la ligne 444 (self::$nbResultsChiffre = $compteTotal[0];). Sous cette dernière, pour vous tenter d'afficher le nombre de résultats avant que ça passe par la fonction d'affichage (donc juste après le lancement de la requête SQL) avec echo $compteTotal[0]; pour voir s'il correspond bien avec le nombre visible dans PhpMyAdmin. Si tel est le cas, le problème se situe donc après, et si ce n'est pas le cas, alors le problème se posera donc bien avant la requête. Cela permettra déjà d'orienter le débogage. :D

  • Renaud dit :

    J'ai testé d'afficher le nb_result pour un mot-clé qui est bien dans le champ : 0
    J'ai fait un autre test : sur une autre page j'ai saisi la requête issue de ton script :

    $sql = mysql_query("SELECT id,TRIM(nom) AS nom FROM gamme WHERE MATCH (nom, descriptif) AGAINST(CONVERT(_utf8 'jazz*' USING utf8) IN BOOLEAN MODE) AND etat='1' AND on_site='1' ORDER BY algo DESC, nom ASC LIMIT 0, 50") or die(mysql_error());
    while($row = mysql_fetch_assoc($sql)){
    echo $row['nom']."";
    }
    Ben nada ! Pas de résultat ! Et MyAdmin qui continue de les retourner allègrement ! Un truc de dingue !

    • Je vais peut-être paraître "étonné" mais comment se fait-il que le début de la requête soit "SELECT id, TRIM(nom) AS nom..." alors que mon moteur de recherche n'ajoute aucun TRIM() en SQL ni d'alias (AS nom) ? Cette requête ne peut pas être construite naturellement par mon outil, c'est certain.
      Qui plus est, avec quelle version de PHP tournez-vous ? Les fonctions mysql_query() (et consorts) sont obsolètes depuis PHP 5.5, il faut les remplacer par mysqli_query (et consorts), voire avec PDO. J'ai justement développé mon moteur de recherche en PHP 5.5 en ce sens, pour éviter ce type de souci.

      Voici à quoi devrait ressembler la requête formatée par le moteur en théorie :
      mysql_query("SELECT nom, descriptif FROM gamme WHERE MATCH (nom, descriptif) AGAINST(CONVERT(_utf8 '+jazz' USING utf8) IN BOOLEAN MODE) ORDER BY algo DESC, nom ASC LIMIT 0, 50")

      Je viens de faire le test de mon côté en formatant la requête avec tous les paramètres et cela ressemble bien à ça. Il est possible en modifiant un peu le code de réussir à insérer "etat='1' AND on_site='1'", mais ce n'est pas possible par défaut, tout comme le début de requête. Il se peut que des modifications entraînent ces problèmes, notamment avec des guillemets mal placées, etc.

  • Renaud dit :

    J'ai ajouté l'id et le trim(nom) parce que j'en ai besoin dans les résultats mais je ne crois pas que ce soit gênant puisque ça fonctionne pour plein de mots-clefs avant un certain enregistrement de ma table. La requête que tu as collée ici ne retourne rien non plus avec ma page test. Mais tu as raison pour le 5.5, je vais l'installer. Tout mon site tourne en PDO, sauf ton script puisque j'ai la version 5. Je reviens te dire ce qu'il en est. Merci encore.

  • Renaud dit :

    J'ai installé 5.5. Ca fonctionne en local avec la table fraichement de mon serveur...mais ça ne retourne rien sur le serveur.
    Un truc de fou !

    • C'est juste incompréhensible.^^ Si cela fonctionne en local avec exactement la même table, ça devrait effectivement fonctionner côté serveur, juste en changeant les identifiants de connexion bien entendu. Vous avez un serveur dédié ou mutualisé ? Est-ce la même version d'Apache et de MySQL entre le serveur et le WAMP ? Est-ce que les deux sont paramétrés de la même manière pour le FULLTEXT ? C'est un peu particulier à régler le fulltext donc il se peut que des différences soient faites à cause de ça.

  • Renaud dit :

    Distant :
    Version du serveur : 5.5.46-0+deb7u1-log - (Debian)
    Version du protocole : 10
    Jeu de caractères du serveur : UTF-8 Unicode (utf8)
    Apache/2.2.22
    Version du client de base de données : libmysql - mysqlnd 5.0.10

    Local - Easy PHP
    Version du serveur : 5.6.15-log - MySQL Community Server (GPL)
    Version du protocole : 10
    Jeu de caractères du serveur : UTF-8 Unicode (utf8)
    Apache/2.4.7 (Win32) PHP/5.5.8
    Version du client de base de données : libmysql - mysqlnd 5.0.11-dev

  • Renaud dit :

    Mais attends le plus dingue : voici ta requête issue de 5.5 :
    SELECT * FROM gamme WHERE MATCH (nom, descriptif) AGAINST(CONVERT(_utf8 '+jazz)' USING utf8) IN BOOLEAN MODE) LIMIT 0, 10
    Elle fonctionne très bien dans le phpMyAdmin du serveur distant !!!
    Donc c'est PHP, me dis-je...
    Distant : 5.5.30
    Local : 5.5.8

  • Renaud dit :

    Miracle ! ce code fonctionne en distant :
    $sql = $pdo->query("SELECT * FROM gamme WHERE MATCH (nom, descriptif) AGAINST(CONVERT(_utf8 '+jazz)' USING utf8) IN BOOLEAN MODE) LIMIT 0, 10");
    while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
    echo $row['nom']."";
    }
    ceci avec la connexion pdo de mon site.
    J'ai donc tenté de remplacer ton $link par le $pdo de ma connexion dans l'appel de la classe, mais ça plante de partout...

    • Alors dans ce cas, vu les différences de version d'Apache, il faudrait voir si les extensions MySQLi sont installées sur ton serveur puisque cela fonctionne avec PDO.
      Concernant les requêtes, c'est logique que le moteur plante car j'utilise certaines fonctions de MySQLi et non de PDO, même si certaines sont communes entre les deux.

  • Renaud dit :

    Oui, je pense qu'elles sont installées sur le distant car : Extension PHP : mysqli
    Et puis je pense que ça planterait ou mettrait des warnings. Là ça dit juste "Pas de résultat pour jazz".
    Je vais tenter de modifier ta classe pour PDO et plonger dans la doc, sourire. Merci pour ta patience et bonne soirée.

  • Stéphane Liger dit :

    Bonjour Mathieu,
    D'abord un grand merci pour mettre ce code en libre accès. J'ai juste une petite question, je suis sous PHP Version 5.4.45-0 avec un linux debian 7. Le “Pack complet - moteur de recherche (PHP 4 - PHP 5)" marche bien mais pas le “Pack complet - moteur de recherche PHP 5.5”, est ce du à mon php ou est ce moi qui ne sait pas l'installer. Lorsque je l'installe, je suis obliger de mettre en commentaire la ligne 474 et le foreach de la ligne 488, je ne sais pas quoi faire, soit prendre le premiers pack ou mettre le second avec les modifications. Pouvez vous m'aider?
    Merci d'avance.
    Stéphane

    • Bonjour,
      Il y a quelques différences entre la version PHP 5.5 et les anciennes. Normalement, les deux devraient fonctionner mais certains paramètres moins gourmands sont intégrés dans la dernière version, et il faut parfois que le serveur soit paramétré pour que toutes les spécificités fonctionnent parfaitement. Pour tout dire, j'ai un ordinateur encore en PHP 5.3 qui fonctionne avec la dernière version sur Wamp. Après, peu importe le pack que vous prenez, les grandes lignes restent les mêmes, il manque juste la correction automatique dans les vieilles versions.

  • Antoine dit :

    Bonjour, tout d'abord, je tenais à vous féliciter pour votre excellent travail mais je n'arrive pas à le faire fonctionner. En effet le script fonctionne, il indique :
    Résultat de la Recherche : Test
    1 résultat pour votre recherche (1 à 1)

    Warning: mysql_fetch_assoc() expects parameter 1 to be resource, object given in /home/u549978418/public_html/recherche.php on line 57

    • Bonjour,
      Quelle version avez-vous utilisé ? Si vous avez une erreur avec mysql_fetch_assoc(), cela signifie que vous utilisez l'ancienne version (avant PHP 5.5), qui est déconseillée. Tentez peut-être en vous calquant sur le pack PHP 5.5 et les exemples fournis, ça devrait mieux fonctionner, vous verrez. :D
      P.S. : je ne maintiens plus les anciennes versions depuis quelques mois déjà.

  • Antoine dit :

    Merci beaucoup pour votre réponse rapide. En effet je n'avais pas installé la bonne version. Cependant j'obtiens toujours une erreur
    Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in /home/u549978418/public_html/Plugin/moteurPHP5.5/class.inc/moteur-php5.5.class-inc.php on line 1176
    Erreur : Key column 'titre' doesn't exist in table

    • De rien. Je crois que vous venez vous-même de trouver votre erreur, vous avez écrit le message avec "Erreur : Key column ‘titre’ doesn’t exist in table". Cela signifie que vous devez avoir un "title" qui traîne quelque part et qui ne devrait pas être là. :D

      • Antoine dit :

        J'ai trouvé mon problème mais j'ai besoin de votre aide pour le résoudre. Il se trouve la
        if($moteur->isIndex("correctindex", "table_search") == false)
        mais je ne c'est pas ce qu'il faut remplacer. Merci de votre aide

      • Quel est votre message d'erreur exactement maintenant ? Si vous avez une erreur ici c'est très étonnant car ça ne fait que créer une table dans la base de données ça si l'index n'existe pas. Est-ce que ça marche sans la correction orthographique au moins (lignes 36 à 51 dans le moteur-normal-php-5.5) ?

  • Antoine dit :

    Mon erreur est Fatal error: Call to undefined function mysqli_fetch_all() in /home/u549978418/public_html/Plugin/moteurPHP5.5/class.inc/moteur-php5.5.class-inc.php on line 474 et sa marche sans la correction orthographique

    • Bon c'est déjà ça si ça marche sans la correction orthographique, tout n'est pas perdu ! ^^
      Votre erreur est certainement dû à une extension Mysqli qui vous manque sur le serveur (ou en local). De mémoire, il faut ça "mysqlnd" d'installé pour que mysqli_fetch_all() fonctionne, mais sans certitude. En tout cas, je pense que l'erreur est là. C'est ce qui est écrit dans la doc de PHP http://php.net/manual/fr/mysqli-result.fetch-all.php.

      • Antoine dit :

        Seulement mySQLInd est installé...

      • Alors là je ne sais pas quoi dire, je suis perplexe. :S
        Je ne vois que ça comme erreur possible car si c'était une erreur de base de données, vous l'auriez sûrement déjà trouvé (un mauvais nom de base, de table, etc.). Je suis désolé mais là, vous me posez une colle. :(

  • Antoine dit :

    Ça y est ! Après une heure de recherche j'ai trouvé une solution simple. Je tiens à vous remercier pour votre patience et votre aide. Il suffisait de remplacer
    $words = mysqli_fetch_all($indexinverse);
    Par
    $words = [];
    while ($row = $indexinverse->fetch_assoc()) {
    $words[] = $row;
    }
    En tout cas merci beaucoup et félicitations pour votre puissant moteur de recherche

    • Pas bête, vous avez contourné la limitation de mysqli_fetch_all() en reconstituant un tableau de mots avec la version objet de la méthode. Au final, c'est la même chose, en quelques lignes de plus. Parfait ! ^^

  • Romain dit :

    bonjour, merci bcp tout d'abord!

    petite question, je suis sous codeigniter avec mon script en URL/site/search/recherche or la pagination me renvoie vers index.php?q=xxxxx

    avez-vous une idée ?

    également, je cherche dans ma requête à insérer des conditions (WHERE status="Active") dans mysql, y a t il une possibilité ?

    MERCI beaucoup pour ce super boulot!

    • Bonjour,
      Normalement, la recherche vous renvoie dans la page courante du script, mais je n'utilise pas CodeIgniter, donc sur ce point, je ne peux pas vous dire si c'est "normal" ou pas dans votre cas. :(
      Pour personnaliser vos conditions WHERE, vous pouvez utilisez le dernier paramètre de la méthode moteurAffichage($callback = '', $colonnesSelect = '', $limit = array(false, 0, 10, false), $ordre = array(false, "id", "DESC"), $algo = array(false,'algo','DESC','id'), $orderLimitPerso = ''). La variable $orderLimitPerso se cale juste après le WHERE en cours, donc il suffit de faire un "AND status='active' par exemple et ça devrait le fait. :D

      • Kimson dit :

        Salut, super bon tuto , mais j'ai un probleme pour lajout de la condition personnalisé ça ne marche pas pour moi lorque j'ajoute $orderLimitPerso ='AND stat_article=1'.

        J'ai essayé d’ajouter la condition whereperso mais de mon coté sa ne fonctionne pas jai une erreur Missing argument 2 moteurRecherche::moteurRequetes()

      • Si vous avez l'erreur "Missing argument 2", je crains que l'erreur ne soit autre. Peut-être faut-il un espace avant le AND (normalement non vu le code) ? Voyez aussi en ajoutant la colonne stat_article dans la variable $colonneWhere, c'est peut-être ça qui manque.

      • Kimson dit :

        Merci ça marche impeccable !

  • Rey dit :

    Bonjour, Superbe travail, bien détaillé, je fais aussi des tutoriels que je développe un maximum, c'est énormément de travail, et je viens de tomber sur votre site, étant à la recherche d'un moteur avec pagination, cependant vous utilisez mysqli et suis pas fan, mais bon chacun son choix, pour ma part je préfère PDO, que j'ai appris seul, et j'utilise aussi Dreamweaver, que certains codeur n'aime pas, mais je l'utilise qu'en mode code simplement et notepad++, donc je suis entrain de lire chaque fichier, et je vais tenter de les convertir en PDO.Sinon en local cela fonctionne très bien, une fois convertir je l'intégrerais à mon site dans une modale. Cordialement.

    • Bonjour,
      Merci. En effet j'ai choisi MySQLi par habitude, mais j'ai prévu de tout réécrire quand j'aurai le temps (sauf que je n'en trouve pas ^^). Je passerai à PDO à l'avenir car je l'aime bien aussi et c'est un standard avec plusieurs SGBD. Et pour ce qui est de Dreamweaver, j'ai commencé avec ça aussi (en mode code aussi, ça n'est qu'un éditeur dans ce cas, pas pire que les autres...), et ça n'a rien changé à ma vie. Vous savez, si on suivait les tendances et les modes qui "font bien", on coderait tous en Javascript avec des serveurs NodeJS et des bases en NoSQL, et pourtant, les parts de marché sont loin de prouver que ça cartonne... :D

  • Jean dit :

    Bonjour, d'abord un grand merci et un grand bravo de partager avec la communauté votre moteur de recherche, j'essaye de le mettre en place sur mon serveur web, mais je n'arrive pas à le faire fonctionner, j'ai téléchargé le pack avec le moteur normal en essayant de le faire simplement fonctionner avec ma BDD, je rentre mes paramètres de connexion dans BDD.class-inc.php, jusque là tout va bien, il ne me met plus l'erreur de connexion à la BDD, je vais ensuite compléter les paramètres pour lui montrer les tables comme suit:

    if(isset($_GET) && !empty($_GET['q'])) {
    $moteur = new moteurRecherche(stripslashes($_GET['q']), 'tbl_info', 'like', $stopwords);
    $colonnesWhere = array('field1', 'description');
    $moteur->moteurRequetes($colonnesWhere);
    }

    avec le nom de mes tables field1 et description, je ne modifie rien dans le reste du fichier et lorsque je lance la recherche, il ne se passe rien, il ne rentre même pas dans la boucle suivante à savoir :

    if(isset($moteur)) {
    // Affichage de la requête avec $moteur->requete
    echo 'Résultats de la recherche : '.$moteur->requete.'';

    puisque je n'ai même pas Résultat de recherche qui s'affiche, j'ai vérifié si il récupérait bien le $_GET['q'] lorsque je fais un echo avant
    if(isset($_GET) && !empty($_GET['q']))
    il m'affiche bien, mais par contre après il sort de la boucle, donc je n'ai pas un message d'erreur
    Est-ce que le moteur à du mal à s'y retrouver avec les variables de session dans l'adresse que je fais passer (exemple pour la recherche sur le mot vis :
    http://www.monsite.be/obj/searchtest/moteur-normal.php?GLBSESSID=2c48bcbbb60b42665674d4a04519ae48&q=vis
    Un grand merci pour la suite que vous pourrez donner à ma question,

    • Normalement les URL de sessions ne devraient pas l'embêter, j'avais fait des tests de ce type, sans problème. En revanche, n'y a-t-il pas un problème au niveau de la méthode moteurAffichage() plutôt ? C'est elle qui régit l'affichage des contenus, et même de "Résultats de recherche". Si elle, elle plante, alors ça peut expliquer que rien ne s'affiche...

      • Jean dit :

        Merci de pour la rapidité de tes réponses, j'ai essayé avec la méthode de ton fichier sans la modifier dans un premier temps :

        $moteur->moteurAffichage('display', '', array(true, $page, $limit, true));
        Je suis encore en php4 sur mon serveur, donc j'ai bien modifié mon include pour :
        include_once("class.inc/moteur-php4.class-inc.php");

        Mais est-ce que la méthode d'utilisation de la fonction est pareil pour en php4 que php5 ?

      • Si tu es encore en PHP 4, alors le code affiché est théoriquement quelque peu différent. J'avais dû mettre à jour pour PHP 5.5 jadis. Il faut savoir qu'actuellement, PHP 5.4 est la dernière version maintenue (c'est toujours 3 versions avant la dernière, qui sont actuellement PHP 5.4, 5.5, 5.6 et donc la dernière PHP 7, PHP 6 ayant été "sauté" ^^). C'est pour cette raison que je ne mets plus du tout à jour la version PHP 4 ni même la 5, seule la 5.5 est en cours. Il se peut donc que tu rencontres quelques soucis. Dans ce cas, je te conseille de lire mes commentaires dans les fichiers PHP, ça te guidera mieux.

  • Timothee dit :

    merci bcp pour ce script
    chez moi ca marche tres bien, mais j ai un petit souci , je voudrais afficher une image dans le dossier images de mon site dou le nom est dans le champ nom_image de ma base de donnee
    j ai essaye avec comme suit (echo '';)ca ne marche pas, pourriez vous me venir en aide svp

  • Timothee dit :

    jai essaye ainsi
    // Résultats de recherche à afficher (à personnaliser)
    $texte = "\n";
    $texte .= "\t".$nb." - ".$key['id']."\n";
    $texte .= "\t".$key['product_desc']."\n";
    $texte .= "\t".$key['product_name']."\n";
    $texte .= "\t".$key['product_img_name']."\n";
    $texte .= "\n";
    echo '';
    l image ne s affiche pas ni pour l un ni pour l autre et aussi j ain esseye printf ca ne marche pas toujours

    • Bonjour,
      Cela me semble normal, aucune base de donnée n'enregistre d'image, mais seulement l'URL d'une image ou son nom. Il faut donc retracer le chemin jusqu'à l'image pour l'afficher. Dans votre cas, la ligne pourrait ressembler à ça alors (en modifiant les parties en majuscules) :
      $texte .= "\t".'‹img src="DOSSIER_DES_IMAGES/'.$key['product_img_name'].'" alt="'.$key['product_name'].'"/›'."\n";

  • Seb dit :

    Bonjour,
    Qu'un mot "génial", bravo...
    Par contre j'aimerai adapter votre code, pour qu'il recherche dans plusieurs tables, est-ce possible?

    Merci d'avance

    • Bonjour,
      Malheureusement il n'est pas prévu pour rechercher dans plusieurs tables. J'ai déjà fait des tests mais ça n'était pas probant du tout. Je suis censé le réécrire complètement et cela ferait partie des améliorations prévues, mais je manque de temps pour le faire. :(

      • Seb dit :

        Merci pour votre réponse,
        dans ce cas, comment puis-je faire pour sélectionner la table dans laquelle je souhaite faire une recherche?

        Je pense que cela est réalisable, avec quelles que pistes?

      • C'est indiqué dans mon article, cela se passe dans l'appel de la méthode moteurRecherche(). Si c'est en PHP 5.5 et supérieur (conseillé), c'est le 3e argument, sinon c'est le 2e. Tout est commenté pour que vous puissiez trouver. :D

  • Seb dit :

    Bonjour,

    comment faire pour afficher mes résultats de recherche sous forme de tableau?
    Et auriez-vous une piste afin recherche dans une table voulu, avec un sélecteur de type "select" qui répertorie toutes les tables présentes dans une BDD?

    Je suis débutant et c'est pas simple
    Merci d'avance
    Seb

    • Bonjour,
      Qu'entendez-vous par un affichage sous forme de tableau ? Vous voulez que la liste des résultats soit un tableau plutôt qu'une liste de résultat comme un moteur classique ? Si oui, tout se passe dans la fonction moteurAffichage(), c'est elle qui gère l'affichage des résultats. Il vous suffit de modifier la variable $texte présente dans mes exemples. L'affichage est tout simple ici mais vous pouvez très bien rajouter des "table", "tr" et "td" pour former un tableau par exemple. :D

      En revanche je ne comprends pas votre deuxième question. Le moteur fait exactement cela, il recherche dans une ou plusieurs tables voulus. En revanche, il ne répertorie par les tables bien entendu. Si votre objectif est de lister les tables existantes avant de lancer une recherche sur l'une d'entre elle, il faut faire une requête de type "SHOW TABLES FROM NOM_BDD" pour obtenir la liste puis effectuer la sélection.

  • Seb dit :

    Bonjour,
    J'ai un problème que je n'arrive pas à surmonter, voici, j'ai créé un CRUD (dossier CRUD),j'ai copier/coller votre dossier"moteurPHP5.5" dedans, j'ai insérer le champ recherche (autocompletion) à ma page, jusque là tout va bien, il effectue la recherche, le retour du résultat se fait bien dans une fenêtre "modal de bootstrap" hors j'ai une erreur dans le script :

    jQuery(document).ready(function() {
    jQuery('#moteur').autocomplete('autocompletion-PHP5.5.php?t=autosuggest&f=words&l=5&type=0&e=utf-8', { selectFirst:false, max:5, multiple:1, multipleSeparator:' ', delay:100, noRecord:'' });
    });

    le message de retour :
    liste_patho_he.php?q=he:88
    Uncaught TypeError: jQuery(...).autocomplete is not a function
    (anonymous function) @ liste_patho_he.php?q=he:88
    o @ jquery.js:2fire
    With @ jquery.js:2
    ready @ jquery.js:2
    B @ jquery.js:2

    Si je fais fonctionner votre code hors de mon dossier CRUD, je n'ai plus cette erreur...
    je sais que vue d'ici cela n'a pas l'air facile à comprendre

    Merci pour votre aide et bonne journée

    • Bonjour,
      J'avoue que vous me posez une colle car il s'agit certainement d'un rare cas difficilement identifiable. Selon la version de jQuery que vous utilisez (si ce sont les dernières versions), il y a fort à parier que le problème provienne de l'appel à jQuery. Il arrive fréquemment qu'il faille remplacer "jQuery(document).ready(function() {" par "(function() {". Dans ce cas, la fin du script devient "})(jQuery);" au lieu de "});". C'est la seule chose qui me semble plausible pour expliquer ce type de bug. :S

      • Kevin dit :

        Bonjour,
        J'utilise le frameWork Zend pour mon application.
        J'ai le même souci que Seb. J'ai essayé de remplacer ce que vous avez proposé, cela me donne les lignes suivantes :
        (function() {
        jQuery('#query').autocomplete('autocompletion.php?t=autosuggest&f=autosuggest_mot&l=5&type=1&e=utf-8', { selectFirst:false, max:5, multiple:1, multipleSeparator:' ', delay:100, noRecord:'' });
        })(jQuery);

        Mais j'ai toujours cette fameuse ligne :
        L’objet ne gère pas la propriété ou la méthode « autocomplete ».

        Je peux vous donner de plus amples informations si vous le désireé

      • Dans ce cas, tentez avec $("#query") plutôt qu'avec jQuery("#query") et préciser le "$" dans (function($) { ... } au début du code. Il s'agit très certainement d'un conflit de jQuery, c'est aussi bête que ça. Une autre possibilité serait de se tourner vers jQuery.noConflict(); pour trouver une solution.

  • Seb dit :

    Re et merci de vous intéresser à mon cas un dimanche,

    "Vous voulez que la liste des résultats soit un tableau plutôt qu'une liste de résultat comme un moteur classique ? Si oui, tout se passe dans la fonction moteurAffichage(), c'est elle qui gère l'affichage des résultats"
    - Oui c çà et je devrai m'en sortir là-dessus.

    "Le moteur fait exactement cela, il recherche dans une ou plusieurs tables voulus".
    - Certes, à condition que l' on rentre dans le code et que l'on change la table...en fait moi je souhaite faire un "select" afin de choisir dans quelle table chercher...vu que le moteur ne recherche pas dans plusieurs tables (même avec des JOIN, etc..)

    "Si votre objectif est de lister les tables existantes avant de lancer une recherche sur l'une d'entre elle, il faut faire une requête de type "SHOW TABLES FROM NOM_BDD" pour obtenir la liste puis effectuer la sélection."
    - C exactement ce type de chose qu'il me faut...maintenant il faut que je l'adapte...

    "Il arrive fréquemment qu'il faille remplacer "jQuery(document).ready(function() {" par "(function() {". Dans ce cas, la fin du script devient "})(jQuery);" au lieu de "});". C'est la seule chose qui me semble plausible pour expliquer ce type de bug. :S"
    - Bon euh, si c'est une colle pour vous alors pour moi......:(
    je vais essayer votre solution et reviendrai pour vous dire...
    ce qui est drôle là-dedans, c'est que cela arrive lorsque le dossier "moteurPHP5.5" est dans mon dossier "CRUD", mais je n'ai plus le problème lorsque je l'en sort....

    Merci encore

    • Pour ce qui est de la sélection des tables, le SHOW TABLES va fonctionner, mais après, je ne pense pas que vous pourrez effectuer une recherche multitables sans casser le code ou faire des JOIN. Même en bouclant sur la méthode moteurRecherche(), ça devrait engendrer des erreurs. :(
      En ce qui concerne le problème de jQuery, c'est peut-être un souci de chemin d'accès au fichier (fort probable, vérifiez bien que le chemin menant vers les fichiers de l'autocomplétion), de CHMOD du dossier CRUD ou ce que j'ai évoqué. :S

  • Seb dit :

    Bonjour,
    Donc pour la partie JQuery, c'était bien la 1ère solution
    ----> remplacer "jQuery(document).ready(function() {" par "(function() {". Dans ce cas, la fin du script devient "})(jQuery);" au lieu de "});".

    Et enfin la méthode SHOW TABLE, fonctionne mais je dois dorénavant adapter votre code selon le choix de la table sélectionnée.

    Merci encore

  • gillian dit :

    bonjour,
    merci pour ce super script ! tout fonctionne !!!
    juste une question... comment faire une redirection depuis un search form placé dans un menu à la page de résultats ?

    • Bonjour,
      Cela se fait naturellement en fonction de l'attribut "action" que l'on met dans le formulaire HTML (il faut juste penser à placer les scripts au bon endroit). Si vous regardez l'exemple placé dans les scripts, on part d'une page qui contient juste un formulaire (il pourrait donc être dans un search-form placé dans un menu par exemple) et qui redirige vers une page de résultats, c'est donc déjà un peu le cas. ;-)

  • eric dit :

    Bonjour,
    alors d'abord félicitation pour votre travail et pour le temps que vous dédiez aux réponses des utilisateurs ;-)
    Pour ma part, c'est la version "autocompletion" qui m'intéresse mais lorsque je commence à remplir le formulaire il ne me semble pas que le moteur aille chercher dans le base "search" des résultats proches de ma recherche. En lorsque "j'envoie", le script s'arrête après "résultats de recherche : ..."
    Je suis parti du fichier : moteur-autocompletion-PHP5.5.php
    Puis j'ai rajouté avant le DOCTYPE
    if(isset($_GET) && !empty($_GET['moteur'])) {
    $moteur = new moteurRecherche($link, stripslashes($_GET['moteur']), 'search', 'regexp', $stopwords);
    $colonnesWhere = array('titre', 'description');
    $moteur->moteurRequetes($colonnesWhere);
    }
    et la partie "affichage" -> 5 en bas de page
    Cela est il correct? Ou y a t il un fichier qui reprenne l'intégralité du code pour que je compare au mien ?
    Merci

    • Si vous téléchargez le pack complet, il y a un fichier pour chaque cas, avec un code sur lequel vous pouvez vous appuyez. À première vue, je pense que votre souci est sûrement dû à un mauvais pointage vers la base de données dans laquelle chercher, un truc comme ça. ;-)

  • grandoos dit :

    Bonjour monsieur , je tiens particulièrement a vous féliciter pour ce brillant travail.
    Ce pendant j'ai deux préoccupations:
    -j'aimerais tout d'abord personnaliser la requette en ajoutant au 6e argument de la fonction moteuraffichage un filtre order by qui affiche les résultats en fonction des paramètres Get (longitude et latitude) envoyées par le user.
    voici un peu ce que j'ai eu a faire sans resultat
    $orderby="order by (((acos(sin((?*pi()/180)) * sin((latitude*pi()/180)) + cos((?*pi()/180)) * cos((latitude*pi()/180)) * cos(((? - longitude)*pi()/180))))*180/pi())*60*2.133) DSC";
    $moteur->moteurAffichage('display', '', array(true, 0, $limit, false),array(false, 'algo','id_etablissement','DESC'),array(true,'algo','DESC','id_etablissement'),$orderby);
    je ne sais trop ou mettre les arguments vu qu'il s’agit d'une requette préparée
    -le 2eme problème est que j'aimerais faire fonctionner le moteur de correction automatique mais a chaque fois ma table CorrectIndex est vide et ne contient même pas les valeurs du tableaux .
    $motsCorrects = array("lorem", "ipsum", "dolor", "amet", "sit");

    • Bonjour,
      Comme vous tentez d'utiliser le moteur différemment de son usage initial, cela peut expliquer des bugs. Je réponds d'abord au 2nd problème. Il faut remplir la base de données avec des mots corrects en théorie, via la méthode setIndex() qui reprend le tableau des $motsCorrects que vous m'indiquez. Vérifiez d'abord que la table (que j'ai appelé "correctindex" pour l'exemple) existe, c'est peut-être là le souci, tout bêtement.

      Concernant votre 1er problème, il faut bien s'assurer que les paramètres 4 et 5 sont désactivés (la première valeur du tableau doit être sur "false"), c'est donc le 6e argument qui sera pris en compte dans ce cas. Je ne sais pas si c'est une faute ou non, mais il faut écrire "DESC" à la fin de votre ORDER BY, et non "DSC" comme dans votre commentaire. En théorie, cela devrait donc ressembler à ça :
      $moteur->moteurAffichage('display', '', array(true, 0, $limit, false), array(false,'id_etablissement','DESC'), array(false,'algo','DESC','id_etablissement'), $orderby);
      Après, je ne peux pas garantir que votre mode de calcul fonctionnera, mais en théorie oui.

      • grandoos dit :

        cela a fonctionner!! en fait j'ai laissé la recherche en fonction la pertinence a true, car si on n'arrive pas a recuperer sa position. on obtient des résultats en fonction de la pertinence.
        je vous remercie pour votre réponse. Monsieur

        $orderby= ' ';
        if(isset($_GET['lat']) and !empty($_GET['lat']) and is_numeric($_GET['lat']) and isset($_GET['lng']) and !empty($_GET['lng']) and is_numeric($_GET['lng']))
        {
        $lat=$_GET['lat'];
        $lng=$_GET['lng'];
        $orderby='order by (((acos(sin(('.$lng.'*pi()/180)) * sin((latitude*pi()/180)) + cos(('.$lng.'*pi()/180)) * cos((latitude*pi()/180)) * cos((('.$lat.' - longitude)*pi()/180))))*180/pi())*60*2.133)';

        }

        // Lancement de la fonction d'affichage avec paramètres
        $moteur->moteurAffichage('display', '', array(true, 0, $limit, false),array(false,'algo','id_etablissement','DESC'),array(true,'algo','DESC','id_etablissement'),$orderby);

      • Super, l'essentiel est sauf alors ! :D

  • grandoos dit :

    bonjour monsieur!
    je dois avouer que je suis un grand fan de vous car votre code j'essaie de l'utiliser et de le tester . bon j'ai deux preocupations ce matin :
    la premiere est que le lorqu'un utilisateur fait la recheche en saisissant uniquement un ou plusieurs mot qui sont dans la table stop word le script genere un erreur fatal.
    et deuxiement j'ai plusieurs table avec des jointures et j'aimerais effectuer la recherche en parcourant toutes ces tables de facon simple je dispose en BD une table etablissement et une table ville j'aimerais que: si un utilisateur saisie par exemple paris qu'il ait tous les etablissement de cette ville la.
    j'aimerais avoir juste des pistes de developpement .
    merci pour votre comprehension

    • Bonjour,
      Merci pour vos compliments, ça fait plaisir. Normalement vous ne devez pas chercher de stop words, donc c'est peut-être normal que cela génère une erreur fatale. Les stop words sont justement des mots exclus des recherches ("le", "la", "les", "un", "une"...).
      Concernant la recherche dans plusieurs tables, le moteur actuel ne vous permettra pas de le réaliser. Je n'avais pas pensé à ça quand je me suis lancé dans cette exercice et par conséquent, je n'avais pas prévu ce cas de figure. Je manque cruellement de temps mais je prévois toujours de recréer un moteur encore plus évolué qui permettrait éventuellement ce type de recherche multi-tables avec jointures, etc. Malheureusement, cela est impossible à ce jour, tous mes tests ont été infructueux... :(

  • guillaume dit :

    J'adore! merci pour ce code! prise en main (après réflexion et décodage) bien aisée (presque trop c'est magique). Découverte des fonctions (magique aussi ) soundex metaphone et levenstein ! je vais etudier tout cela de plus près prochainement. encore un grand merci pour tout.

    • Merci, ça fait plaisir à entendre. Je n'utilise plus levenshtein car cela revient à changer 1/2 lettres un peu au hasard, là où soundex et metaphone permettent d'aller plus loin dans la comparaison des syllabes, etc. Malheureusement il n'existe pas de systèmes équivalents pour la langue française, ce qui serait bien meilleur en termes de qualité...

  • Narragan dit :

    Bonjour!!!
    D'abord bravo pour ce travail accompli. J'ai appris pas mal de truques et astuces et c'est plus que bon pour un débutant d'en apprendre beaucoup pour ces quelques lignes.
    PDO, voilà dans quoi je me suis embarqué...
    Notice: Undefined variable: link. erreur lors du test. du coup j'ai changé la variable link par ma variable db qui sert de connexion à la base.
    essaie à nouveau, pas d'erreurs mais rien de se passe.
    Je suis passé alors par la connexion de votre choix mysqli en remettant ma variable link à sa place, toujours rien pas d'erreurs.
    Dans la table(myisam) mon champ correspondant à la rechercher est en fulltext.
    Je suis bien connecté à la base.
    Questions: Que faire? Ou est mon erreur?

    PS: j'ai essayé d'utiliser SolR d'apache ou encore ElasticSearch mais ça n'a rien donné. Trois jours de galère.

    • Narragan dit :

      J'ai apporté quelques modifications, et voici la nouvelle erreur: Erreur dans la requête finale, vérifiez bien votre paramétrage complet !

      • Le problème est qu'il peut y avoir plusieurs erreurs à la source. Souvent, c'est juste une question de paramètres PHP mis dans le désordre, etc. :(

      • Narragan dit :

        Je vais voir cela tout à l'heure. Dois-je toucher à la classe moteur(...)? Ou alors faire une requête du genre "ALTER TABLE ma_table FULLTEXT KEY `prenom` (`prenom`,`adresse`)" par exemple? Car pour les paramètres PHP je n'y me connais trop.

      • Dans la classe du moteur, il y a une méthode qui regroupe toutes les variantes de la requête SQL. L'erreur qui s'affiche provient de là, il faudrait surtout trouver le cas précis qui pose problème, cela peut aider à isoler la cause de l'erreur. Souvent, il s'agit d'un paramètre tout bête ou de l'usage de l'algorithme de pertinence. Tentez en activant ou non l'algorithme, etc.

  • jm dit :

    Bonjour,
    Recherchant des infos relatives à d'éventuels plugins WP pour un outil de recherche construit autour de l'association MySQL+FULLTEXT, je vais probablement tester votre solution...
    J'ai récemment implémenté sur notre Framework propriétaire ce type de recherche pour une cliente souhaitant une recherche plus pertinente sur son site...
    Ceci étant fait nous avons partagé la petite aventure sous la forme de deux articles traitant de la recherche FULLTEXT avec InnoDB en mode NATURAL ou BOOLEAN :
    http://blog.axe-net.fr/recherche-pertinence-mysql-fulltext/
    http://blog.axe-net.fr/tuto-mysql-fulltext-in-boolean-mode/

    Au vu votre expertise dans le domaine j'aimerai bien avoir votre retour (sur ce fil ou par mail) sur la partie technique (code).
    Merci d'avance,
    jm

    • Bonjour Jean-Marc,
      Je vois que tu écris pour Axe-net, c'est toujours un plaisir de partager avec l'agence de Sylvain Richard. ^^
      Je suis allé lire tes deux articles qui sont bons, j'ai même laissé une trace sur l'un d'entre eux, tu pourras voir cela. Globalement, tu as dit presque tout ce qu'il faut sur la recherche FULLTEXT. Elle a bien des qualités, mais paradoxalement, je préfère souvent la recherche REGEXP couplée à des algorithmes personnels, car cela est plus facilement adaptable partout (pas de serveur dédié recommandé, etc.).

  • Mathieu dit :

    Bonjour, bravo pour ce magnifique outil ! J’aimerais faire fonctionner la version PHP 5.5 mais je rencontre une erreur 500 sur Debian 7 avec PHP 5.6 alors que la version PHP4-5 fonctionne parfaitement. Peut-être avez-vous une idée du problème ?

  • 2FR3 dit :

    Bonjour,
    Pas encore essayé, mais je vais intégrer votre moteur sur mon nouveau site en BS4 car il m'a l'air très prometteur et adapté a mon projet.
    Merci pour votre travail et surtout pour le partage.

  • Mickael dit :

    Bonjour,
    Merci pour ce moteur de recherche riche en fonctionnalités.
    Je rencontre un petit problème (ce qui est normal pour un débutant comme moi) :

    Je n'arrive pas à afficher les textes de la table, même dans le mode le plus basique du moteur, sans aucune option, et avec la table par défaut.
    (j'utilise php 5.6 et mysql version 5.5).

    La connexion à la table est bonne, aucun message d'erreur.
    La pagination est bien affichée et fait son travail (nombre de pages relatif au mot-clé et à la limite). Ainsi que le nombre de résultats.

    Mais, ni titre ni description. Ce doit être vraiment tout bête. Dois-je modifier quelque chose sur le fichier inclus (moteur-php5.5.class-inc.php) ? Je pense que l'erreur ou l'élément manquant se trouve plutôt sur la page de recherche, mais après nombreux essais je ne comprend pas.

    Qu'en pensez-vous ?

    En vous remerciant.

    -------------------------------------------
    moteurRequetes($colonnesWhere);
    }
    ?>

    Rechercher :
    <input type="text" value="" name="moteur" id="moteur" />

    <?php
    if(isset($moteur)) {
    echo 'Résultats de la recherche : '.$moteur->requete.'';

    function affichage($requete, $nbResults, $mots) {
    if($nbResults == 0) {
    echo "Aucun résultat, veuillez effectuer une autre recherche !";
    } else {

    $affichageResultats = new affichageResultats();
    echo $affichageResultats->nbResultats();

    while($key = mysql_fetch_assoc($requete)) {

    foreach($key as $k => $v) {
    $key[$k] = utf8_encode($v);
    }
    $texte = "".$key['title']."";
    $texte .= $key['description']."";
    $surlignage = new surlignageMot($mots, $texte, "exact", true, "REGEXP");
    echo $surlignage->contenu;
    }
    }
    }
    $limit = 10;

    if(isset($_GET['p'])) {
    $page = htmlspecialchars($_GET['p']);
    } else {
    $page = 0;
    }
    $moteur->moteurAffichage('affichage', '', array(true, $page, $limit, true));
    $moteur->moteurPagination($page, 'p');
    }
    ?>

    • C'est très étonnant, n'hésitez pas à m'envoyer votre code par email si vraiment vous ne trouvez pas la solution. Normalement, si votre table a le bon nom et contient des entrées comme la mienne, ça devrait fonctionner (à condition que les réglages suivent bien entendu, mais cela semble être le cas dans votre code ici). Vous avez inséré ma table proposée ou vous en avez créé une sur le même modèle ? Si oui, il faut juste qu'elle soit pleine, et étant donné que le moteur ne retourne pas d'erreurs, c'est que vous arrivez à vous y connecter sans problème. Donc c'est sûrement un souci dans la table je pense... :S

      • Mickael dit :

        Bonjour Matthieu,

        Je m'y suis remis un peu ce soir et ai rapidement solutionné mon problème. C'était encore plus simple que je le pensais.

        Cela venait en fait de la boucle while, j'ai remplacé le code :

        while($key = mysql_fetch_assoc($requete)) {

        par :

        while($key = mysqli_fetch_assoc($requete)) {

        --------------------

        Cela ne m'avait pas sauté aux yeux mais était pourtant évident.

        Bonne continuation.

  • Mickael dit :

    Bonjour Mathieu,

    Merci pour la réponse rapide.

    Dans le doute, j'étais revenu à l'essentiel, avec la table que vous fournissez ainsi que les codes du tutoriel, sur une page vierge (seulement les balises élémentaires). Même problème d'affichage des textes.

    J'ai aussi essayé une copie de la table "search" sans le fulltext des champs tilte et description. J'ai même pensé jusqu'à vidé le fichier .htaccess, des fois qu'il y ait un conflit.

    Ce doit être vraiment tout simple, tout fonctionne parfaitement mais pas d'affichage des colonnes title et description. Je vais chercher encore un peu et trouverais bien la solution, avec de la persistance l'on y arrive toujours. Dès que j'ai trouvé je le notifierai ici, si cela peut aider d'autres personnes à l'avenir.

    Encore merci pour votre travail, j'ai essayé plusieurs moteurs, mais le votre est le seul que je retiens.

    ps : désolé pour le code tronqué.

    A bientôt.

  • Mickael dit :

    Bonjour,

    Je reviens vers vous pour un petit problème que je n'arrive pas à résoudre, malgré de multiples essais et recherches. C'est à propos du surlignage des résultats. J'utilise la méthode de recherche fulltext et le surlignage fulltext.

    La méthode de recherche fulltext me retourne idéalement le même nombre de résultats sans tenir compte des accents. Le mot "sphère" contenu dans la bdd, par exemple, est retourné avec ou sans accents. Mais seul le mot accentué est surligné.

    En cherchant "sphere", les résultats apparaissent, mais sans être mis en valeur. Ce qui est problématique pour moi, car les résultats se trouve toujours au sein de paragraphes, parfois longs.

    J'ai essayé toutes les solutions pour régler d'éventuels soucis d'encodage mais fut vite convaincu que ce n'était pas la source du problème. Puis les expressions régulières, sans succès. Pensant qu'il fallait faire quelques réglages dans la partie surlignage (moteur-php5.5.class-inc.php), puis me disant qu'il fallait faire ces réglages dès le départ au moment du traitement de la requête...

    Je tourne en rond, à vrai dire.

    Est-il possible de solutionner ce problème ?

    Merci pour votre réponse.

    • Bonjour,
      Si j'ai bien compris le cas que vous me décrivez, il est normal que le surlignage semble "déconner". J'ai moi-même codé la méthode de surlignage, et elle s'appuie strictement sur le mot recherché, donc avec ou sans accent précisément. En revanche, il peut arriver en effet que la recherche Fulltext ne dissocie pas les deux écritures, ce qui fait cette différence. Il faudrait sûrement modifier quelque peu la classe surlignageMot qui est dans le moteur en supprimant la fonction qui gère la suppression des accents par exemple (très reconnaissable au début de la classe).

      • Mickael dit :

        Bonjour Mathieu,

        Merci pour le temps que vous m'accordez.

        J'ai essayé pas mal de regex différentes dans la class surlignage.

        Je me rend compte que je n'ai pas été très clair dans ma demande. En fait, j'aimerais justement que le surlignage s'effectue sans distinction de l'accentuation.

        Pour reprendre l'exemple ci-dessus, la requête "sphere, sphére ou sphère" retournerait sans distinction le résultat "sphère" surligné (seule version existante dans la bdd).

        Il me faudrait trouver une solution pour remplacer le "e" par "e ou é ou è" au besoin, avant l'action du surlignage.

        Je vais chercher encore un peu.

        Merci, bonne journée.

      • D'accord, je comprends mieux, mais je vais peut-être vous décevoir alors...
        Il est possible techniquement de passer de "sphère" (ou "sphére", etc.) à "sphere", la classe surlignageMot contient justement une fonction de "suppression" des accents. En revanche, il est impossible de faire le chemin inverse sans un index de tous les mots nécessaires. En effet, comment passer de "sphere" à "sphère" ? Comment un programme pourrait-il deviner que le premier "e" est un "è" mais pas le second, etc. Il est donc possible de supprimer, mais pas d'ajouter, et pas conséquent, le surlignage ne peut pas fonctionner pour toutes les distinctions dans l'autre sens si on cherche un mot en particulier.

        Côté code, le regex fonctionne un peu sur ce schéma : plein de mots ou rien => "" => mot cherché => "" => plein de mots ou rien. Ce qui nous intéresse est donc "mot cherché", et c'est sur lui qu'il faut agir, non sur la regex en elle-même. Sauf que vous ne pourrez pas facilement ajouter artificiellement des accents pour chaque mot. :(

  • Stéphane dit :

    Bonjour Mathieu,
    Merci pour votre générosité.
    J'ai été confronté au problème évoqué par un autre Mathieu le 13 mai 2018 parmi ces commentaires : la ligne while($key = mysql_fetch_assoc($requete)), au lieu de mysqli_fetch_assoc (avec le i) est donnée dans votre exemple de script au paragraphe "5/ Affichage des résultats (dans la même page ici !)" de cette page web, à la ligne 21. Comme quasiment tout le monde, j'ai fait un copier/coller de cet exemple et cette minuscule erreur ne m'est pas sautée aux yeux (même avec le message d'erreur "Warning: mysql_fetch_assoc() expects parameter 1 to be resource, object given in C:\wamp\...").
    Merci donc de corriger cette coquille, pour les futurs visiteurs. Et encore merci pour ce bon boulot.

    • Bonjour,
      Ce n'est pas une coquille en réalité, c'est juste que l'article a été écrit pour la version PHP 5.3 et 5.4 à l'époque, qui acceptait bien mysql_fetch_assoc (sans le "i"). Je vais essayer de reprendre le code pour l'adapter à la nouvelle version en effet, vous avez raison ! ;-)

      • Stéphane dit :

        Merci pour la correction. Je comprends parfaitement que quand on fait évoluer un script, on ne pense pas nécessairement à mettre à jour tous les éléments de la page web qui en parle. Mais cela a pu en dérouter plus d'un.
        Après avoir corrigé cet oubli, j'ai eu quelques messages d'erreur qui tiennent du fait que vous vous adressez à des programmeurs qui peuvent les corriger aisément. Il s'agit des 2 lignes :
        $texte = "".$key['titre']."";
        $texte .= $key['contenu']."";
        Pour éviter ces messages d'erreur, j'ai ajouté dans la function affichage($requete, $nbResults, $mots) l'instruction :
        global $colonnesWhere; de façon à récupérer dans la fonction le tableau $colonnesWhere
        Puis j'ai remplacé les 2 lignes mentionnées plus haut par ces quelques lignes :
        $texte = "";
        if (isset($colonnesWhere))
        {
        for ($i=0, $count_colonnes=count($colonnesWhere); $i<$count_colonnes; $i++)
        {
        $texte .= $key[$colonnesWhere[$i]] . "";
        }
        $texte .= "";
        }

        C'est une modeste contribution à l'immense travail accompli. Mère Theresa, à côté de Mathieu, fait pâle figure.
        Je tiens aussi à corriger ma coquille a moi dans mon message initial : au lieu de "cette minuscule erreur ne m'est pas sautée aux yeux" il fallait lire "cette minuscule erreur ne m'a pas sauté aux yeux". Mais on a compris quand même. Malgré tout, je ne sais pas d'où cette incongruité a bien pu sortir...
        Stéphane

      • Et bien merci Stéphane. Toute contribution apporte son lot de bonnes surprises donc c'est parfait pour les lecteurs et utilisateurs. :-)
        Comme je l'ai noté dans mon "edit", j'aimerais refaire tout le moteur pour le rendre plus puissant, mieux écrit, et avec plus de possibilités. Je manque de temps car ça fait plus d'un an que j'ai ce projet en tête. J'espère pouvoir un jour le mettre en oeuvre. ;-)

  • Sébastien.R dit :

    Bonjour,
    Merci pour votre moteur de recherche, j'ai pu faire ce que je voulais avec des modifications pour l'adapter à mes recherches. Mais je recherche une chose, il me servira surtout pour rechercher des numéros ou en lien depuis un formulaire lors de l'inscription d'un licencier. Certain indique leur numéro exemple 4505 d'autre comme à notre fédération soit 004505 et donc le lien de recherche ne fonctionnera pas. Sur un ancien système de notre fédération il était possible d'avoir le lien q=4505 ou q=004505 les 2 fonctionner et me trouver le licencier en question est-ce possible de faire cela ?
    On doit changer cela ici ? $moteur = new moteurRecherche($link, stripslashes($_GET['q']), 'race_licences_ffvrc', 'regexp', $stopwords);
    Remplacer regexp en like ?
    Merci de la réponse.

    • Bonjour,
      Pas la peine de changer la méthode de recherche en "LIKE", cela peut fonctionner avec "REGEXP". En fait, il faut modifier un paramètre dans la fonction moteurRecherche(). Si vous passez le paramètre $exact en false (8e paramètre de la fonction), ça fonctionne pour rechercher les chaînes contenus dans un mot, et non les mots exacts.
      Si vous utilisez aussi la mise en gras des mots recherchés, vous devez aussi modifier le 3e paramètre de la fonction surlignageMot() et le passez sur "total" (il est sur "exact" par défaut).
      Normalement ce sera parfait ainsi. ;-)

      • Sébastien.R dit :

        J'ai fais la modif et ça fonctionne merci beaucoup pour ce magnifique système que vous avez développé. N'étant pas codeur beau travail.

  • Sébastien.R dit :

    Re bonjour,
    Je vous recontact pour une aide, j'ai fais toutes mes modifs et personnalisation depuis mon Nas Synology sous PHP 5.6.
    Tout est parfait est fonctionne, je décide de le mettre en ligne sur mon hébergement OVH mais quand je fais une recherche J'ai juste "Résultats de la recherche : 064512" et rien en dessous aucun résultat, je ne comprends pas sachant que ça fonctionne parfaitement sur mon Nas et je n'ai aucune erreur. Auriez-vous une piste ? Merci

    • Euh, c'est étonnant là... ^^
      C'est exactement le même code que vous avez intégré ? Il ne manque pas la fonction d'affichage des résultats ou tout bêtement l'appel de la fonction ? En théorie, une erreur devrait s'afficher si c'était problématique. L'autre possibilité est que vous n'avez peut-être pas bien intégré la base de données et mis les bons identifiants MySQL pour vous y connecter, donc ça ne cherche pas au bon endroit. Je ne vois que ça... :-$

      • Sébastien.R dit :

        J'ai mis votre script sans aucune modification c'est pareil, les infos de la BDD sont bon, je ne comprends pas.

  • Bonjour Monsieur,
    Vous faites un travail superbe.
    La requête fonctionne 1 - Title 1
    Lorem ipsum dolor sit amet, ...
    2 - Title 2
    Lorem ipsum ...
    Mais j'ai ce message d'erreur sur lequel je n'arrive pas à agir
    Notice: Trying to get property 'num_rows' of non-object in \class.inc\moteur-php5.5.class-inc.php on line 662
    Pouvez vous m'indiquer ce que je dois faire ?
    Je vous remercie par avance
    Cordialement
    Vincent

    • Bonjour,
      Je pense avoir la réponse... Vous avez paramétré le moteur pour qu'il utilise la correction orthographique (vous avez quelque part un code comme $moteur->getCorrection(), etc.) mais vous n'avez pas inséré l'index inversé (la base de données) des mots corrigés. Donc le moteur cherche cette base qu'il ne trouve pas. Vous pouvez lire mon second article sur le sujet dans lequel je décris cette fonctionnalité.

  • Florian Gerbe dit :

    Bonjour , votre script est super ;
    par contre j'ai une petite question j'aimerais bien que les liens soient cliquables vers une redirection de page web mais je ne sais pas comment faire

    Sur le script je pense que la manipulation pour rediriger le titre et le contenu sur une page web se trouve ici ?
    // Résultats de recherche à afficher (à personnaliser)

    $texte = "\n";
    $texte .= "\t".$nb." - ".$key['title']."\n";
    $texte .= "\t".$key['content']."\n";
    $texte .= "\n";

    Par ex :
    $texte .= "\t".$key['title']."\n";

    mais j'ai beau tout tenter ça fonctionne pas .
    pouvez-vous m'aider ?

    • Bonjour,
      Ce que vous avez fait part dans le bon sens en effet, il faut juste que vous possédiez une "colonne" de base de données qui contienne les liens qui vous intéressent. Si tel est le cas, vous pourriez avoir quelque chose comme $key['URL'] par exemple (cela dépend du nom que vous avez voulu lui attribuer, etc.), et donc écrire ceci :
      $texte.= '\t‹a href="'.$key['URL'].'" rel="nofollow"›'.$key['title'].'‹/a›'."\n";
      Ce qu'il vous faut, c'est absolument quelque chose à afficher dans l'attribut href de votre balise de lien, et en général, cela provient aussi de la base de données qui contient le titre, le contenu, etc.

      • Gerbe Florian dit :

        Parfait , je vous remercie de votre aide par contre une chose .
        Voici comment le lien est affiché :

        1 – Coucou la Chouette
        La chouette cool.
        ‹a href="https://mesamis.fr/page/lachouette21rel="nofollow"›la Chouette‹/a›

        Cela s'affiche bien correctement il recherche bien le contenu dans la base de données avec mon URL sauf qu'il n'est pas cliquable.

      • Dans ce cas c'est que la balise HTML est mal fermée, tout simplement. Dans votre exemple, on voit que le href n'est pas bien fermé (il manque les guillemets de fin) et il faut un espace avec le rel="nofollow". Je pense que c'est ça. ;-)

      • Florian dit :

        Voilà ça fonctionne correctement !
        Merci votre soutien.
        Florian

        Je le partage pour la communauté :

        $texte = "\n";

        $texte .= "\t".$key['title']."\n";
        $texte .= "\t".$key['content']."\n";

        $texte .= "\n";

  • Pierre J. dit :

    Salut,
    Merci pour ce script complet.
    j'ai un petit souci que je n'arrive pas à résoudre.
    les apostrophes sont supprimées dans mes résultats, je ne vois pas d'où vient le problème. Les apostrophes sont bien dans la base de données.
    Je te remercie par avance, et encore bravo pour ton script.

    • Bonjour, et de rien ! ^^
      Bizarre que les apostrophes sautent des résultats, mais pas ailleurs, c'est sûrement dû à une fonction PHP ou à un problème d'encodage.
      Si vous retirez la portion de code suivante dans la fonction d'affichage des résultats, est-ce mieux ?
      foreach($key as $k => $v) { $key[$k] = utf8_encode($v); }
      Si les apostrophes sont supprimées lors de l'affichage, c'est sûrement un stripslashes() en PHP ou ce type d'erreur qui peut se produire. Je n'ai jamais eu ce genre de retour mais c'est tout ce qui me vient. En quoi est encodé votre BDD ?

    • Pierre J. dit :

      Bonjour,
      Merci pour votre réponse, je tenais tout d'abord à m'excuser de vous avoir tutoyé mais c'est qu'à force de visiter votre site je vous ai pris en sympathie.
      sinon, en supprimant la fonction j'obtient des losanges avec un point d'interrogation.
      La base est en MyISAM utf8_general_ci
      j'ai alors regardé plus en détail les données de la base et je m'aperçois que j'ai 2 sortes d'apostrophe:
      l'apostrophe "qu'il" s'affiche normalement dans les résultats.
      alors que l'apostrophe "qu’il" ne s'affiche pas dans les résultats.
      Bizarre non? ou alors un des 2 est un guillemet qu'il va falloir remplacer directement dans ma base?

      • Ne vous inquiétez pas, vous pouvez me tutoyer sans aucun problème, j'ai juste pris l'habitude de vouvoyer au maximum dans mes réponses. ^^
        Concernant l'encodage de la BDD, c'est bon en utf8_general_ci. En fait, le problème provient bien du second "type" d'apostrophe. En fait, ces dernières sont sûrement issues de copier/coller (venant de Word, etc.) et viennent se mélanger aux autres.
        L'idéal serait peut-être d'essayer de les remplacer automatiquement par les bons caractères. Soit vous le faites en amont directement dans la BDD, pour rendre tout bien propre de votre côté. Soit il faut ajouter une ligne de code quelque part pour "corriger" ce problème.
        Par exemple, on pourrait tester ça dans la fonction d'affichage (sans garantie que ça fonctionne car ce sera déjà peut-être trop tard...) :
        foreach($key as $k => $v) {
        $v = str_ireplace("’", "'", $v); // Nouvelle ligne à rajouter
        $key[$k] = utf8_encode($v);
        }

        En gros, il faudrait remplacer l'apostrophe en mauvaise forme pour la remplacer par la bonne forme.
        Bon courage ! ^^

      • Pierre J. dit :

        Merci l'ami,
        Je viens de tester avec "str_ireplace" mais comme vous dite "c'est déjà trop tard", à ce niveau elles doivent déjà être supprimé.
        Merci, en tout cas on sait d'où vient le souci, je vais m'y mettre pour remplacer les mauvais apostrophes.
        Merci encore l'ami et continuez comme ça.

      • Ah mince, c'est ce que je craignais. Le plus simple pour est certainement de passer par PhpMyAdmin pour administrer la base de données et faire une requête de modification automatique, ce sera bien plus rapide. ;-)
        Bon courage !

      • Pierre J. dit :

        Merci,
        finalement j'ai exporté ma table qui contient ces apostrophes et j'ai fais la modification directement sur le fichier sql avec notepad++.
        Remarque: dans le fichier sql les mauvais apostrophes ne sont pas échappés donc j'ai remplacé "’" par "\'".
        Une fois réimportés, les résultats sont bon.
        Merci, au plaisir et bonne continuation.

  • Pierre J dit :

    Salut, tout d'abord j'espère que vous vous portez bien malgré la crise sanitaire.
    Je reviens vers vous parce je suis confronté à un nouveau "petit" souci:
    alors j'ai dans ma table plusieurs colonnes, des colonnes avec des textes en langues non latines tel que le chinois, l'arabe....
    donc le souci c'est qu'à la place des lettres j'ai des "?" avec le "moteur de recherche", alors qu'avec une requête de recherche simple l'affichage est correct.
    Une idée de l'origine du souci?
    Merci.

    • Bonjour,
      Je pense que le souci est clairement l'encodage ici, et ça va être très compliqué de tout bien gérer. En gros, chaque langue peut avoir un encodage spécifique pour ses caractères. Dans le moteur, je préconise (et met par défaut) UTF-8, car ça supporte la majorité des caractères internationaux, mais cela dépend aussi de l'encodage de votre base de données, de votre page web, etc. Je pense qu'il faudrait déjà regarder dans la base de données à quoi ressemble les fameux caractères, et en fonction, adapter l'encodage dans la fonction d'affichage des résultats du moteur. Ce ne sera pas simple mais ça peut se faire je pense.
      Cordialement

      • Pierre J dit :

        Salut,
        La base est en MyISAM utf8_general_ci.
        Oui j'ai bien vue que dans les scripts du fichier "moteur-php5.5.class-inc.php" l'encodage est en utf-8 et ma page web à un charset en utf-8 aussi ().
        Lorsque j'exécute une requête simple d'affichage de données sur cette même page pour afficher les données de ces colonnes, les résultats sont affichés correctement, ce qui m'amène à penser que l'encodage de la base est bonne ainsi que celle de la page web puisque la requête m'affiche les différentes langues correctement. mais lorsque je fais la même chose avec le "moteur de recherche", je n'obtient que des ligne de "?", aucun caractère de ces langues non latine n'est affiché.
        Je peux peut-être supprimer l'encodage qui se fait au niveau du script, si c'est faisable que dois-je supprimer et modifier?
        Si vous pouvez bien sûr, je ne veux pas abuser de votre temps.
        Merci à nouveau pour votre présence et du temps que vous prenez pour aider.

      • Bonjour,
        Comme je vous le disais, l'encodage intervient à plusieurs endroits, il faut donc repérer où ça cloche. Déjà, la table est en UTF-8 et votre page aussi, ce sont deux bonnes choses. Ensuite, il faut espérer (ça doit être le cas) que les données soient bien transférées dans le bon encodage vers la base de données. Normalement, là encore, ça doit le faire...
        Il nous reste donc un problème de restitution des résultats dans le moteur de recherche, c'est donc ici que semble se présenter le problème. Dans ce cas, il faut regarder dans la fonction d'affichage pour gérer les encodages. Dans mon code, on retrouve ça par défaut :
        // On encode chaque clé/valeur de résultats en UTF-8
        foreach($key as $k => $v) {
        $key[$k] = utf8_encode($v);
        }

        C'est sûrement là qu'il faut intervenir. Essayez en enlevant la fonction utf8_encode(), ou en tentant utf8_decode() par exemple, etc.

      • Pierre J. dit :

        Bonjour,
        après avoir testé en modifiant et supprimant l'utf8_encode(), cela n'a rien changé. Par contre j'ai testé en modifiant la connection à la bdd en me connectant en PDO evec PDO::MYSQL_INIT_COMMAND=>'SET NAME UTF8', en exécutant la requête de recherche sql en PDO ainsi que l'affichage, et je n'ai rien modifié d'autre. Et là magie, ça fonctionne correctement, je peux même faire des recherche en langue non latine, seulement dans les résultats tout le texte est mis en gras et non juste les mots recherchés (un autre petit souci à régler ;) ).
        Voilà, je vais continuer.
        PS: je n'est pas supprimé la connexion mysqli mais j'ai ajouté une connexion en PDO que j'utilise pour l'exécution de la requête de recherche totale et d'affichage.

      • Bonjour,
        Normalement on peut ajouter un set name via PHP aussi si vous le voulez, vous auriez obtenu le même résultat. Et peut-être que ça limiterait les problèmes de gras ? ;-)

  • Pierre J. dit :

    Merci,
    où puis-je ajouter le set name et de quelle manière?

    • Il faut ajouter cela avant que les requêtes ne s'exécutent en général (donc dans la classe PHP). Soit vous utilisez mysqli_query pour effectuer une requête SET NAMES, un peu comme ceci mysqli_query($link, "SET NAMES 'utf8'");, soit vous utilisez la fonction dédiée mysqli_set_charset($link, 'utf8');

      • Pierre J. dit :

        Salut,
        Je vous remercie, je l'ai ajouté juste après la connexion à la bdd, effectivement ça fonctionne correctement mais la mise en gras se fait sur tout le résultat, j'ai aussi enlevé la fonction utf8_encode() qui affiche des résultats avec des caractères bizarres.,
        Je vous remercie encore et vous souhaite une bonne journée.

      • Bonjour,
        C'est logique que le utf8_encode() déconne puisque vous gérer tout en utf-8 justement en ayant ajouté l'autre fonction. Donc ça créé un double encodage qui génère ces résultats dégueulasses. Pour le problème du gras, cela signifie encore que l'encodage dérange dans la fonction de surlignage de la classe du moteur PHP. Soit vous esquivez la fonction de surlignage, soit vous la modifiez pour l'adapter, ça ne doit pas être grand chose, c'est juste qu'il a du mal à cerner le mot clé recherché à cause de l'encodage, et donc qu'il ne sait pas où mettre le gras...
        Bonne journée

  • Bonsoir Mathieu,
    Je vous contact après avoir passé en revu toute les solutions possible mais sans succès.
    Je ne suis pas un expert, mais comprend le fondement.
    Je suis dans le même cas de figure que le dernier message avec un problème d'encodage sur les résultats.
    Quel ligne supprimé pour annuler l'encodage utf8 ? ou peut être une explication plus approfondi de SETNAMES
    Je laisse une adresse pour plus explicite.
    https://french-interface.com/wp-content/themes/FI/moviesearch.php
    on constate avec un autre petit moteur qu'il n'y a aucun problème.
    https://french-interface.com/add/test/moteur/index.php
    J'ai ajouter un bout de code confirmant être sous utf8mb4 qui passe a utf8 sur la connexion a la base.
    J'ai fait des modif aussi de bdd, rien
    J'ai testé setnames mais je ne suis pas sur d'avoir bien réalisé.
    Mon problème est sur le é et apostrophe principalement.
    Merci beaucoup de votre conseils

  • Bonsoir Mathieu,
    Je viens de poster un commentaire que je viens de résoudre à l'instant en supprimant une portion de code qui posait problème:
    // On encode chaque clé/valeur de résultats en UTF-8
    foreach($key as $k => $v) {
    $key[$k] = utf8_encode($v);
    }
    J'ai supprimé et nickel
    Franchement du super taf ce moteur bravo et merci pour le partage.
    A bientôt

    • Bonjour,
      Merci bien pour le compliment. J'ai d'autres idées en tête pour faire mieux que ce moteur pour être honnête, j'ai déjà commencé (doucement, à mes heures perdues) une refonte du moteur, à la fois plus directe dans son code mais plus modulaire pour le commun des mortels. J'ai déjà prévu un moyen de faire de la recherche multi-tables par exemple, que ne propose pas cette version. Mais c'est du boulot, et comme ça ne me fait pas gagner un centime, j'y vais tranquillement. :-)
      Je devrais préciser que le bout de code que vous avez supprimé correspond bien à une gestion de l'encodage en cas de soucis, mais cela dépend vraiment de votre base de données. Parfois c'est inutile, comme pour vous ici... ;-)
      A bientôt

  • Massinissa dit :

    Bonjour ,
    Merci beaucoup pour ce magnifique code , çà marche parfaitement sur mon outil .
    J'ai deux petite questions :
    1. y a t’il un moyen pour faire une recherche sur plusieurs tables en même temps ?
    2.Sur le code de la connexion a la bdd est ce qu'il y a une possibilité de mettre PDO a la place de mysqli ?

    Un grand merci a vous .

    • Bonjour,
      Merci pour vos compliments.
      Malheureusement, la requête ne permet pas à ce jour de faire une recherche sur plusieurs tables, ni en PDO.
      J'ai commencé à réécrire un nouveau moteur de recherche PHP qui ferait cela, mais je ne sais pas quand je pourrais en sortir une version suffisamment qualitative et stable.
      Bonnes fêtes à vous

  • Bonjour Mathieu,
    Je tenais à vous remercier.
    Je vous ai contacté il y a quelques jours.
    Un bout de chemin a été parcouru depuis.
    Votre code m'a donné l'envie de réalisé un site pour la recherche de film streaming multiplateforme.
    Pratique quand l'on est frustré de ne pas trouver sur son site préféré le film que l'on souhaite.
    https://www.meagles.fr
    C'est grâce à vous qu'il a vu le jour et souhaite vous remercier d’avoir réalisé et partager ce moteur de recherche qui fonctionne à merveille.
    Je vous souhaite une très bonne nouvelle année 2021.
    Un grand merci et Bonne continuation

    Amicalement,
    Guillaume

    • Bonjour,
      Et bien merci, et surtout bravo pour votre travail. Je suis très fier d'avoir pu contribuer à ma manière dans votre projet, auquel je souhaite de la réussite.
      Meilleurs voeux pour 2021.
      Amicalement,
      Mathieu

  • Bonjour Mathieu,

    Comment aller vous ?
    Je reprends contact avec vous car j'ai besoin de vos lumières.
    Une chose toute bête que je ne trouve pas à résoudre sur une requête pour l'affichage des résultats.
    Malgré bon nombre de test, je suis toujours au point mort.
    2 tables en relation pour allégé les données me contraigne a une modification de clause mais je ne trouve pas ou l'insérer.
    Code ci dessous testé et fonctionnel sur un appel simplifié de la base.

    REQUETE:
    SELECT * FROM BDD_update, bddstream WHERE BDD_update.site = bddstream.site AND BDD_update.inline = 'on' AND titre LIKE

    Je vous remercie de votre aide.

    Bien cordialement,

    Guillaume

    • Bonjour,
      Il faut que je me replonge dans le moteur là car je n'y suis plus trop depuis le temps.
      De mémoire, les requêtes sont gérées directement côté "algorithme" du moteur, et la restitution ne fait que suivre cela. Cela signifie donc que la requête de recherche est identique pour la recherche et la résultat des résultats (logique). Dans le moteur, on peut seulement modifier quelques informations (la limite, etc.) et ajouter une clause libre. Les requêtes sont gérées dans la méthode "moteurAffichage()", autour des lignes 417-438 normalement. Attention car certaines parties de la requête sont automatisées en fonction du nombre de mots recherchés, etc.

      • Bonjour Mathieu,

        Je vous remercie pour votre prompt réponse.
        Après lecture de la quasi totalité des questions posé sur votre page, je m'informe qu'il n'est apparemment pas possible d'inclure la recherche sur 2 tables.
        La requête demandé en ce qui me concerne doit obligatoirement établir la relation entre les tables et donc inclure cette clause pour évité une répétition d'information.
        A ce jour plus de 2 millions de lien sont répertorié et je souhaiterais pouvoir allégé les données pour une recherche plus rapide et prendre en considération des éléments indicatif pour ne pas affiché les résultat si offline et d'autre encore.
        Vous devez être très occupé et il m'est difficile avec le peu de connaissance en php d'arrivé à une conclusion positive et me retrouve limité dans mon développement.
        Pensez vous pouvoir m'aidé dans ma démarche ou éventuellement une personne de votre entourage pouvais établir un bout de code en complément pour aller en ce sens ?
        Je ne perçois aucun revenu sur cette activité, investi beaucoup de temps pour apprendre et souhaite continué de développer davantage.
        Je vous prie de bien vouloir m'excusé pour ma demande qui peut paraitre inhabituel et me tourne vers vous pour trouvé une solution.
        Peut être souhaitez vous communiquer par message personnel et vous laisse mes coordonnées électronique si nécessaire.
        guillaumemautalent@gmail.com
        Toute l'aide apporté serais extrêmement appréciable.
        Je vous remercie et vous souhaite une excellente journée

        Bien cordialement,

        Guillaume

      • En effet, ce moteur n'est pas spécialisé dans la recherche sur plusieurs tables, je ne l'avais pas prévu au départ et il est difficile de l'intégrer dans cette version (j'ai déjà essayé mais les résultats étaient décevants). J'ai récemment écrit un article sur la question, avec un code PHP qui fait de la recherche multi-tables et multi-colonnes en toute simplicité : https://blog.internet-formation.fr/2021/01/creer-fonction-moteur-de-recherche-php-multi-tables-multi-colonnes-mysql/. C'est à partir de cette base que j'aimerais réécrire un moteur de recherche PHP performant, mais je manque cruellement de temps pour le moment (j'ai déjà les prémices mais je ne veux pas me précipiter et faire n'importe quoi).
        Pour le coup, je risque de ne pas trop pouvoir vous aider ici, et hormis vous rapprocher d'un indépendant (moins cher qu'une agence) ou d'une personne de bonne volonté, je ne vois pas trop comment répondre à votre besoin. :(
        Cordialement,
        Mathieu Chartier

  • Déposer un commentaire

    Répondre à Paul Annuler la réponse

    L'adresse de messagerie ne sera pas publiée.* Champs obligatoires