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

Article rédigé par Mathieu Chartier

Publié par dans Programmation le 7 septembre 2013

104 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 (14/04/2014)

Le moteur de recherche PHP est régulièrement remis à jour avec de nouvelles fonctions, n'hésitez pas à visiter à nouveau cette page si vous voulez profiter des prochaines mises à jour. J'ai également mis en téléchargement  un pack complet contenant plusieurs versions de test du moteur de recherche PHP ainsi que les fichiers utiles (base SQL simple, fichiers JS...) aux différentes fonctionnalités (autocomplétion, pagination, scroll infini...).

Edit (17/04/2014)

Le moteur de recherche PHP est désormais entièrement compatible PHP 5.5, vous pouvez télécharger les versions PHP 5.5 ci-dessous ou un pack complet avec différentes variantes d'utilisation. Les anciennes versions du moteur de recherche PHP 4 et 5 sont conservées et seront maintenues à jour jusqu'à nouvel ordre.

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

 

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 »)

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

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

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

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...

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).

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).

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 :

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

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

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).

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

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

  1. Mike a écrit :

    9 septembre 2013 à 09:25

    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.

  2. Mathieu Chartier a écrit :

    9 septembre 2013 à 10:43

    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…

  3. moteur de recherche a écrit :

    9 septembre 2013 à 11:56

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

  4. Mathieu Chartier a écrit :

    9 septembre 2013 à 11:57

    Merci pour l’info ! Seebz n’est pas mon site, juste une source que j’ai citée… :D

  5. 2BubbleBlog a écrit :

    15 septembre 2013 à 17:50

    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 ;)

  6. Mohamed a écrit :

    5 octobre 2013 à 18:48

    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!

  7. Mathieu Chartier a écrit :

    5 octobre 2013 à 19:24

    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…

  8. Mohamed a écrit :

    5 octobre 2013 à 20:33

    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.

  9. Mathieu Chartier a écrit :

    5 octobre 2013 à 20:47

    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… :(

  10. Mohamed a écrit :

    5 octobre 2013 à 21:45

    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…

  11. Mathieu Chartier a écrit :

    5 octobre 2013 à 22:02

    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 !

  12. Mohamed a écrit :

    6 octobre 2013 à 11:40

    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.

  13. Mathieu Chartier a écrit :

    6 octobre 2013 à 12:01

    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…)

  14. Mohamed a écrit :

    6 octobre 2013 à 12:21

    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.

  15. Mathieu Chartier a écrit :

    6 octobre 2013 à 12:27

    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”.

  16. Luc a écrit :

    11 octobre 2013 à 02:31

    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 ! ;-)

  17. jef a écrit :

    30 octobre 2013 à 00:23

    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

  18. Mathieu Chartier a écrit :

    30 octobre 2013 à 00:32

    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…

  19. Patrice a écrit :

    7 novembre 2013 à 16:14

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

  20. Mathieu Chartier a écrit :

    7 novembre 2013 à 16:23

    De rien c’est fait pour ! L’important est d’utiliser l’essentiel et ce qui est utile après tout.

  21. Armel a écrit :

    22 novembre 2013 à 10:44

    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

  22. Armel a écrit :

    22 novembre 2013 à 10:45

    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!)

  23. Mathieu Chartier a écrit :

    22 novembre 2013 à 14:28

    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…

  24. Mathieu Chartier a écrit :

    22 novembre 2013 à 15:25

    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

  25. LitoFix a écrit :

    22 novembre 2013 à 19:19

    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 !

  26. Mathieu Chartier a écrit :

    22 novembre 2013 à 19:40

    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

  27. LitoFix a écrit :

    22 novembre 2013 à 20:57

    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…

  28. Mathieu Chartier a écrit :

    22 novembre 2013 à 21:51

    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.

  29. LitoFix a écrit :

    22 novembre 2013 à 22:22

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

  30. Mathieu Chartier a écrit :

    22 novembre 2013 à 22:37

    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. ^^

  31. LitoFix a écrit :

    22 novembre 2013 à 22:42

    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 ?

  32. Mathieu Chartier a écrit :

    22 novembre 2013 à 23:03

    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…

  33. LitoFix a écrit :

    23 novembre 2013 à 09:52

    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.

  34. Mathieu Chartier a écrit :

    23 novembre 2013 à 10:37

    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…

  35. LitoFix a écrit :

    23 novembre 2013 à 11:01

    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…

  36. Mathieu Chartier a écrit :

    23 novembre 2013 à 12:20

    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;

  37. LitoFix a écrit :

    23 novembre 2013 à 14:54

    Merci de m’avoir mis sur la voie !

  38. Legall a écrit :

    27 novembre 2013 à 15:08

    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

  39. Mathieu Chartier a écrit :

    27 novembre 2013 à 20:13

    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 ?

  40. Legall a écrit :

    28 novembre 2013 à 12:36

    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

  41. Legall a écrit :

    28 novembre 2013 à 16:04

    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

  42. Mathieu Chartier a écrit :

    28 novembre 2013 à 16:24

    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”.

  43. Legall a écrit :

    28 novembre 2013 à 17:16

    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

  44. Mathieu Chartier a écrit :

    28 novembre 2013 à 18:09

    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));

  45. Paul a écrit :

    1 décembre 2013 à 12:28

    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 !

  46. Mathieu Chartier a écrit :

    2 décembre 2013 à 00:11

    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… :(

  47. Paul a écrit :

    2 décembre 2013 à 14:31

    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 ?

  48. Mathieu Chartier a écrit :

    2 décembre 2013 à 20:21

    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 !

  49. Louis a écrit :

    8 décembre 2013 à 01:41

    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 ?

  50. Mathieu Chartier a écrit :

    8 décembre 2013 à 03:19

    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…

  51. Paul a écrit :

    27 décembre 2013 à 09:49

    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 !

  52. Mathieu Chartier a écrit :

    27 décembre 2013 à 09:55

    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.

  53. Paul a écrit :

    27 décembre 2013 à 14:44

    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.

  54. Mathieu Chartier a écrit :

    27 décembre 2013 à 15:31

    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… ^^

  55. Mathieu Chartier a écrit :

    27 décembre 2013 à 16:22

    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

  56. Sylphie a écrit :

    20 janvier 2014 à 15:22

    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 :)

  57. Mathieu Chartier a écrit :

    20 janvier 2014 à 19:17

    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. :(

  58. Sylphie a écrit :

    21 janvier 2014 à 11:15

    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! =)

  59. Sylphie a écrit :

    21 janvier 2014 à 16:43

    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 ^^

  60. Mathieu Chartier a écrit :

    21 janvier 2014 à 18:36

    Oui très bonne méthode en effet car ça permet de profiter du trigger pour faire le “nettoyage” des underscores. Nickel ! :D

  61. David a écrit :

    5 février 2014 à 23:54

    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 ?

  62. Mathieu Chartier a écrit :

    6 février 2014 à 00:04

    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…

  63. David a écrit :

    6 février 2014 à 00:24

    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

  64. David a écrit :

    6 février 2014 à 14:38

    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.

  65. Mathieu Chartier a écrit :

    6 février 2014 à 15:40

    Merci bien, il faudra que je regarde cela en détail ! :D

  66. Carde a écrit :

    10 février 2014 à 17:17

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

  67. carde a écrit :

    12 février 2014 à 11:18

    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 ?

  68. Mathieu Chartier a écrit :

    12 février 2014 à 14:16

    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.

  69. carde a écrit :

    12 février 2014 à 16:40

    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.

  70. Mathieu Chartier a écrit :

    12 février 2014 à 19:38

    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

  71. carde a écrit :

    13 février 2014 à 13:35

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

  72. Mathieu Chartier a écrit :

    13 février 2014 à 14:14

    Me voilà rassuré, il suffit de régler votre conflit alors et tout devrait rentrer dans l’ordre.

  73. Opanczuk a écrit :

    28 février 2014 à 11:14

    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. :)

  74. Romain a écrit :

    7 mars 2014 à 22:07

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

  75. carde a écrit :

    15 mars 2014 à 17:55

    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

  76. Mathieu Chartier a écrit :

    15 mars 2014 à 23:58

    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 !!! ^^

  77. guy a écrit :

    23 mars 2014 à 14:24

    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

  78. Mathieu Chartier a écrit :

    23 mars 2014 à 16:38

    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

  79. guy a écrit :

    1 avril 2014 à 20:41

    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

  80. Mathieu Chartier a écrit :

    1 avril 2014 à 20:50

    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

  81. carde a écrit :

    2 avril 2014 à 11:19

    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

  82. Mathieu Chartier a écrit :

    2 avril 2014 à 11:43

    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… ^^

  83. sabra a écrit :

    3 avril 2014 à 13:03

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

  84. Mathieu Chartier a écrit :

    3 avril 2014 à 13:16

    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

  85. sabra a écrit :

    4 avril 2014 à 09:46

    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 !!

  86. Mathieu Chartier a écrit :

    4 avril 2014 à 09:52

    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

  87. slicinga a écrit :

    14 avril 2014 à 18:14

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

  88. Mathieu Chartier a écrit :

    14 avril 2014 à 18:31

    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…

  89. Olivier a écrit :

    25 avril 2014 à 18:50

    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

  90. Mathieu Chartier a écrit :

    25 avril 2014 à 19:16

    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

  91. Anthony a écrit :

    6 mai 2014 à 13:33

    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.

  92. petite fée a écrit :

    6 mai 2014 à 16:05

    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.

  93. Mathieu Chartier a écrit :

    6 mai 2014 à 16:09

    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.

  94. Mathieu Chartier a écrit :

    6 mai 2014 à 16:20

    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

  95. petite fée a écrit :

    6 mai 2014 à 16:24

    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

  96. petite fée a écrit :

    6 mai 2014 à 16:30

    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 !

  97. Mathieu Chartier a écrit :

    6 mai 2014 à 17:58

    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.

  98. petite fée a écrit :

    6 mai 2014 à 18:28

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

  99. Darwin a écrit :

    28 mai 2014 à 22:26

    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?

  100. Mathieu Chartier a écrit :

    29 mai 2014 à 09:07

    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…

  101. Darwin a écrit :

    29 mai 2014 à 15:04

    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

  102. Darwin a écrit :

    29 mai 2014 à 15:13

    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 !

  103. Darwin a écrit :

    29 mai 2014 à 15:25

    (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 !

  104. Mathieu Chartier a écrit :

    29 mai 2014 à 21:53

    L’essentiel est que ça marche après tout ! C’était donc tout bête, mais il fallait trouver ce qui clochait. :D

Blog web d'Internet-Formation - Commentaires
Déposez un commentaire