PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Recherche.php

https://bitbucket.org/mw4rf/ajpsc-annuaire
PHP | 688 lines | 385 code | 98 blank | 205 comment | 62 complexity | 333451426c50b952c37e092d7c61054b MD5 | raw file
  1. <?php
  2. // Annuaire Alumnii
  3. // Base de données et annuaire d'anciens étudiants.
  4. // Copyright (C) <2006> <Guillaume Florimond>
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. class Recherche
  16. {
  17. // Variables de classe
  18. var $tab; // stocke les résultats avant affichage
  19. var $num = 0; // stocke le nombre de résultats retournés par la recherche
  20. var $rq; // stocke la requête
  21. var $type; // le type de recherche: DEFAULT ; REGEX ; FULLTEXT
  22. // Mots-clés génériques qui doivent être exclus de la recherche
  23. var $gen = array(
  24. // Français
  25. "le", "la", "les", "de", "du", "des", "un", "une", "et", "a",
  26. // Espagnol
  27. "el", "los", "lo", "del", "uno", "una", "y", "en", "para", "por", "no", "o",
  28. // Anglais
  29. "the", "and", "or"
  30. );
  31. /*
  32. ****** CONSTRUCTEUR *****
  33. Nom: Recherche
  34. But: constructeur de la classe Recherche. Effectue les traitements préliminaires sur les données transmises par le formulaire, et effectue la recherche.
  35. Info: Guillaume Florimond, 07/04/2007
  36. Arguments:
  37. $rq est la requête (le contenu du champ de recherche)
  38. $ch est la valeur du champ modificateur (combobox)
  39. */
  40. function Recherche($rq = null, $ch = null)
  41. {
  42. // Si $rq n'a pas été initialisée, c'est qu'on n'utilisera qu'une méthode statique
  43. // donc: pas besoin de continuer le traitement ici
  44. if(!isset($rq) or !isset($ch) or $rq == "") return;
  45. // Enregistrement de la requête dans la session
  46. $_SESSION["searchquery-rq"] = $rq; // la requête
  47. $_SESSION["searchquery-ch"] = $ch; // le champ de délimitation
  48. /* Protection des requêtes SQL: l'espace étant un opérateur ET, il faut enlever les espaces au début et à la fin de la requête ; de plus, c'est important car l'analyse de la formation de la requête s'opère en prélevant des caractères spéciaux à des endroits précis (p. ex. le premier et le dernier caractères doivent être " pour une fulltext search) */
  49. $rq = trim($rq);
  50. /* On enlève les slash pour ne pas causer de problème lors de la vérification des conditions. On remettra plus tard les slash pour protéger la requête SQL. */
  51. $rq = stripslashes($rq);
  52. // 1er cas: c'est une expression régulière
  53. if(strcasecmp(substr($rq, 0, 6) , "regex=") == 0)
  54. {
  55. $this->type = "REGEX";
  56. // Note: la condition ci-dessus a 2 particularités:
  57. // 1) la comparaison est insensible à la casse
  58. // 2) la méthode strcasecmp retourne 0 si les deux chaînes comparées sont égales...
  59. // Extraire l'expression régulière
  60. // Ne pas utiliser la fonction explode car elle est sensible à la casse...
  61. $regex = substr($rq, 6);
  62. // Protection des requêtes SQL: on protège les ' par des \
  63. $regex = addslashes($regex);
  64. /* Construction de la requête et exécution */
  65. $this->rq = $regex;
  66. $this->executer_requete($this->construire_requete( $regex , $ch , true , false ));
  67. }
  68. // 2ème cas: c'est une recherche fulltext
  69. elseif(substr($rq, 0, 1) == '(' and substr($rq, -1, 1) == ')')
  70. {
  71. $this->type = "FULLTEXT";
  72. // Note: substr prélève une partie de la chaîne $rq
  73. // 0,1 signifie 1 caractère depuis la position 0 (le premier caractère)
  74. // -1,1 signifie 1 caractère depuis la position -1 (le dernière caractère)
  75. // Extraire le motif (ce qui se trouve entre les guillemets)
  76. $rqa = substr($rq, 1, -1);
  77. // Protection des requêtes SQL: on protège les ' par des \
  78. $rqa = addslashes($rqa);
  79. /* Construction de la requête et exécution */
  80. $this->rq = $rqa;
  81. $this->executer_requete( $this->construire_requete ( $rqa , $ch , false, true ) );
  82. }
  83. // 3ème cas: ce n'est PAS une expression régulière NI une recherche fulltext
  84. else
  85. {
  86. $this->type = "DEFAULT";
  87. // Nettoyage: on enlève tous les mots-clés génériques
  88. $rq = $this->nettoyer_requete($rq);
  89. // Protection des requêtes SQL: on protège les ' par des \
  90. $rq = addslashes($rq);
  91. // On récupère les mots séparés: il y a autant d'espaces que de requêtes
  92. $rqa = explode(" ", $rq);
  93. // Combien de mots dans ce tableau ?
  94. $nbr = count($rqa);
  95. // Recherche intelligente: on crée autant de requêtes SQL qu'il y a de mots
  96. for ( $i = 0 ; $i < $nbr ; $i++ )
  97. {
  98. /* Construction de la requête et exécution */
  99. $this->rq[$i] = $rqa[$i];
  100. $this->executer_requete($this->construire_requete($rqa[$i],$ch,false,false));
  101. }
  102. // Traitement des résultats
  103. $this->definir_pertinence();
  104. }
  105. }
  106. /*
  107. *******************************************************************************************
  108. */
  109. /*
  110. Nom: afficher_requete
  111. But: Renvoie la requête pour être affichée "proprement" (la transtype en string si elle est de type array)
  112. Info: Guillaume Florimond, 07/04/2007
  113. */
  114. function afficher_requete($req)
  115. {
  116. $str = "";
  117. if(is_array($req))
  118. foreach($req as $key=>$val)
  119. $str .= $val." ";
  120. else
  121. $str = $req;
  122. $str = trim($str);
  123. return $str;
  124. //return $_SESSION["searchquery-rq"]; // DEBUG
  125. }
  126. /*
  127. Nom: nettoyer_requete
  128. But: Elimine les mots-clés génériques de la chaîne passée en argument, tels que définis dans la variable de classe $gen.
  129. Info: Guillaume Florimond, 07/04/2007
  130. */
  131. function nettoyer_requete($req)
  132. {
  133. /* La fonction remplace à l'intérieur des mots. Pour éviter d'enlever des lettres aux mots recherchés, il faut que ce qu'on enlève soient des mots complets, c'est-à-dire des chaînes entournées d'espaces... Le tableau $gen n'admettant pas d'espace de part et d'autre de ses composantes, pour des raisons de lisibilité, il convient d'en ajouter ici */
  134. for($i = 0 ; $i < count($this->gen) ; $i++ )
  135. $mots[$i] = " ".$this->gen[$i]." ";
  136. /* On ajoute un espace AVANT et APRES le mot à éliminer. Bien. Mais si ce mot est en début de chaîne, il n'aura pas d'espace avant lui. S'il est en fin de chaîne, il n'aura pas d'espace après lui. Il ne sera donc pas éliminé. Il faut donc ajouter ici un espace en début de chaîne et un espace en fin de chaîne, pour que l'analyse soit correcte. Il faudra par la suite retirer ces espaces à l'aide de la fonction trim() */
  137. $req = " ".$req." ";
  138. /* Cette fonction remplace les occurences des mots définis dans $mots rencontrés dans $req par des chaînes vides
  139. NB 1: str_replace est sensible à la casse, str_ireplace ne l'est pas
  140. NB 2: la fonction se charge de parcourir le tableau $mots toute seule
  141. NB 3: il faut remplacer PAR un espace, sinon les mots seront collés les uns autre autres
  142. */
  143. // PHP 4
  144. if (!function_exists('str_ireplace'))
  145. include "lib/php5functions/str_ireplace.php";
  146. $req = str_ireplace($mots, " ", $req);
  147. /* La fonction ci-dessus remplace le mot clé par un caractère vide. Mais comme ce mot était séparé d'un espace de chaque côté, on se retrouve avec 2 espaces à la suite. Cela déclenche la fonction explode utilisée pour séparer les mots dans la requête, et cela génère une erreur car un espace n'est pas un motif de recherche valable... Il faut donc absolument réparer ce dommage et remplacer les espaces doubles par des espaces simples */
  148. //$req = str_ireplace(" ", " ", $req); // DEPRECATED
  149. $req = preg_replace('/\s\s+/', ' ', $req);
  150. // Retirer l'espace simple en début et fin de chaîne qui a été ajouté plus haut
  151. $req = trim($req);
  152. // retour
  153. return $req;
  154. }
  155. /*
  156. Nom: definir_pertinence
  157. But: Calcule la pertinence de chacun des résultats de la recherche. Modifie le conteneur des résultats, $this->tab, pour y ajouter l'indice de pertinence de chaque résultat: $this->pertinence[X]["pertinence"]
  158. Info: Guillaume Florimond, 07/04/2007
  159. */
  160. function definir_pertinence()
  161. {
  162. // Retour s'il n'y a pas de résultat
  163. if($this->num == 0) return;
  164. // Initialisation des variables
  165. $note = 0; // La note du résultat (sa pertinence, sur une échelle de 0 à 10)
  166. $p = 0;// Variable de comptage
  167. $ct = 0; // Variable de comptage
  168. $rq = $this->rq; // Variable stockant la requête (tableau ou non)
  169. $rs = $this->tab; // Variable stockant les résultats de la recherche
  170. // Vérifier qu'en fait d'une requête simple ce soit une agrégation ou une comparaison
  171. $regexa = "`^([[:digit:]]{2,4})<([[:digit:]]{2,4})$`"; // a < b
  172. $regexb = "`^([[:digit:]]{2,4})>([[:digit:]]{2,4})$`"; // a > b
  173. $regexc = "`^(.+)&&(.+)$`"; // a&&b
  174. if(is_array($rq)
  175. and count($rq) == 1
  176. and (preg_match($regexa,$rq[0],$tabx)
  177. or preg_match($regexb,$rq[0],$tabx)
  178. or preg_match($regexc,$rq[0],$tabx)) )
  179. {
  180. $rq[0] = $tabx[1];
  181. $rq[1] = $tabx[2];
  182. }
  183. // 1. CALCULER LA PERTINENCE INDIVIDUELLE DE CHAQUE FICHE
  184. // A. Si $rq est un tableau (si la requête contient plusieurs mots-clés)
  185. if(is_array($rq) and count($rq) > 1)
  186. {
  187. // Parcourir les résultats
  188. for($i = 0; $i < count($rs) ; $i++)
  189. {
  190. // Parcourir les mots-clés (les mots qui composent la requête)
  191. foreach( $rq as $key=>$val ) /* val contient les mots-clés */
  192. {
  193. // Parcourir les champs de chaque résultat
  194. foreach($rs[$i] as $k=>$v)
  195. {
  196. /* substr_count(A,B) compte le nombre d'occurrences de B dans A*/
  197. /*si ce qu'on cherche est + petit ou = à que ce dans quoi on cherche!!*/
  198. if(strlen($v) >= strlen($val))
  199. $ct = substr_count( $v , $val );
  200. $p = $p + $ct; // $p contient le nombre d'occurences
  201. $ct = 0; // on réinitialise le compteur
  202. }
  203. $note = $note + $p; // note = somme des notes (p) pour chaque champ
  204. $p = 0; // on réinitialise le compteur
  205. $rs[$i]["pertinence"] = $note; // on enregistre la note
  206. }
  207. $note = 0; // on réinitialise le compteur
  208. }
  209. }
  210. // B. Si $rq n'est pas un tableau (si la requête ne contient qu'une expression)
  211. else
  212. {
  213. // Parcourir les résultats
  214. for($i = 0; $i < count($rs) ; $i++)
  215. {
  216. $val = $rq[0];
  217. // Parcourir les champs de chaque résultat
  218. foreach($rs[$i] as $k=>$v)
  219. {
  220. /* substr_count(A,B) compte le nombre d'occurrences de B dans A*/
  221. /*si ce qu'on cherche est + petit ou = à que ce dans quoi on cherche!!*/
  222. if(strlen($v) >= strlen($val))
  223. $ct = substr_count( $v , $val );
  224. $p = $p + $ct; // $p contient le nombre d'occurences
  225. $ct = 0; // on réinitialise le compteur
  226. }
  227. $note = $p;
  228. $p = 0; // on réinitialise le compteur
  229. $rs[$i]["pertinence"] = $note; // on enregistre la note
  230. }
  231. }
  232. // 2. CALCULER LE POURCENTAGE DE PERTINENCE DE CHAQUE FICHE
  233. $rs = $this->normaliser_pertinence($rs);
  234. // 3. TRI DU TABLEAU PAR PERTINENCE DÉCROISSANTE
  235. foreach($rs as $key=>$val)
  236. $tri[$key] = $val["pertinence"];
  237. array_multisort($tri, SORT_DESC, $rs);
  238. // 4. FINITION: retour le nouveau tableau avec toutes les notes de pertinence en plus
  239. $this->tab = $rs;
  240. }
  241. /*
  242. Nom: normaliser_pertinence
  243. But: Calcule le pourcentage de pertinence de chaque résultat en fonction de la petinence des autres résultats (le plus pertinence est l'indice: 100%).
  244. Info: Guillaume Florimond, 07/04/2007
  245. */
  246. function normaliser_pertinence($rs)
  247. {
  248. // Retour s'il n'y a pas de résultat
  249. if($this->num == 0) return;
  250. // Calculer la plus haute valeur de pertinence
  251. $max = 0;
  252. for($i = 0; $i < count($rs); $i++)
  253. if($rs[$i]["pertinence"] > $max)
  254. $max = $rs[$i]["pertinence"];
  255. // Pour empêcher une future division par 0...
  256. if($max == 0) $max = 1;
  257. // Calculer le pourcentage de chaque pertinence ($max = 100%)
  258. for($i = 0; $i < count($rs); $i++)
  259. $rs[$i]["pertinence"] = round(($rs[$i]["pertinence"] / $max) * 100);
  260. return $rs;
  261. }
  262. /*
  263. Nom: executer_requete
  264. But: Exécute la requête SQL passée en argument et appelle la fonction ajouter_ligne pour chaque résultat.
  265. Info: Guillaume Florimond, 07/04/2007
  266. */
  267. function executer_requete($sql)
  268. {
  269. /* Exécution de la requête */
  270. connexion();
  271. $req = mysql_query($sql) or die("Erreur ".$sql);
  272. /* Calcul du nombre de résultats (remplissage de $this->num) -- Avec ce système de recherche, chaque motif de recherche séparé d'un espace donne lieu à sa propre requête. On doit donc INCREMENTER le compteur et non pas remplacer le compteur existant par une nouvelle valeur (d'où += au lieu de =), sinon seul le nombre de résultats de la dernière recherche sera affiché. */
  273. $this->num += mysql_num_rows($req);
  274. /* Remplissage du tableau ($this->tab) des résultats */
  275. while($data = mysql_fetch_assoc($req))
  276. {
  277. $afficher['nom'] = (formater_nom(stripslashes($data['nom'])));
  278. $afficher['prenom'] = (formater_nom(stripslashes($data['prenom'])));
  279. $afficher['promotion'] = (stripslashes($data['promotion']));
  280. $afficher['nationalite'] = (stripslashes($data['nationalite']));
  281. $afficher['naissance'] = (stripslashes($data['naissance']));
  282. $afficher['adresse'] = (stripslashes($data['adresse']));
  283. $afficher['email'] = (stripslashes($data['email']));
  284. $afficher['q1'] = (stripslashes($data['q1']));
  285. $afficher['q2'] = (stripslashes($data['q2']));
  286. $afficher['q3'] = (stripslashes($data['q3']));
  287. $afficher['q4'] = (stripslashes($data['q4']));
  288. $afficher['q5'] = (stripslashes($data['q5']));
  289. $afficher['q6'] = (stripslashes($data['q6']));
  290. $afficher['q7'] = (stripslashes($data['q7']));
  291. $afficher['fiche'] = "index.php?action=page_voir&prov=search&id=".$data['id'];
  292. // Dans le cas d'une fulltext search
  293. if(isset($data["pertinence"])) $afficher["pertinence"] = $data["pertinence"];
  294. // Appelle la fonction qui ajoute une ligne qui correspond à un résultat.
  295. $this->ajouter_ligne($afficher);
  296. }
  297. }
  298. /*
  299. Nom: ajouter_ligne
  300. But: Ajoute une ligne dans le tableau qui stocke les résultats, $this->tab. Fonction appelée par la fonction executer_requete pour chaque résultat de recherche.
  301. Info: Guillaume Florimond, 07/04/2007
  302. */
  303. function ajouter_ligne($data)
  304. {
  305. // On se place à la prochaine ligne
  306. $i = count($this->tab); // pas de + 1 car tab est initialisé à 0, il a 1 élt de retard
  307. // On ajoute les données dans $tab
  308. $this->tab[$i]["nom"] = $data["nom"];
  309. $this->tab[$i]["prenom"] = $data["prenom"];
  310. $this->tab[$i]["promotion"] = $data["promotion"];
  311. $this->tab[$i]["nationalite"] = $data["nationalite"];
  312. $this->tab[$i]["naissance"] = $data["naissance"];
  313. $this->tab[$i]["adresse"] = $data["adresse"];
  314. $this->tab[$i]["email"] = $data["email"];
  315. $this->tab[$i]["q1"] = $data["q1"];
  316. $this->tab[$i]["q2"] = $data["q2"];
  317. $this->tab[$i]["q3"] = $data["q3"];
  318. $this->tab[$i]["q4"] = $data["q4"];
  319. $this->tab[$i]["q5"] = $data["q5"];
  320. $this->tab[$i]["q6"] = $data["q6"];
  321. $this->tab[$i]["q7"] = $data["q7"];
  322. $this->tab[$i]["fiche"] = $data["fiche"];
  323. // Dans le cas d'une fulltext search
  324. if(isset($data["pertinence"])) $this->tab[$i]["pertinence"] = $data["pertinence"];
  325. }
  326. /*
  327. Nom: afficher_resultats
  328. But: Affiche les résultats de la recherche à l'écran. Cette fonction affiche le contenu de la variable de classe $this->tab qui contient les résultats.
  329. Info: Guillaume Florimond, 07/04/2007
  330. Argument $ttype:
  331. DEFAULT => recherche intelligente, focalisée ou diffuse
  332. REGEX => expression régulière
  333. FULLTEXT => full text search
  334. La définition de cet argument permet de déterminer quand afficher la pertinence des résultats. La pertinence n'est affichée que s'il est DEFAULT.
  335. */
  336. function afficher_resultats($ttype = null)
  337. {
  338. if(isset($this->type)) $ttype = $this->type;
  339. // Déclaration du tableau
  340. $ligne = '<div class="container"><table width="80%" align="center" cellpadding="4" cellspacing="0" border="0" class="table table-hover">';
  341. // Nombre de résultats
  342. $ligne .= '<tr>';
  343. $ligne .= '<td colspan="2"><b class="label">';
  344. // Afficher le nombre ou afficher "Aucun" (si 0 résultat) ?
  345. if ($this->num == 0) $ligne .= donner("rech_resultat_aucun").' ';
  346. else $ligne .= $this->num.' ';
  347. // Mot "résultat" au singulier ou au pluriel ?
  348. if($this->num < 2 != 0) $ligne .= donner("rech_resultat_singulier");
  349. else $ligne .= donner("rech_resultat_pluriel");
  350. $ligne .= '</b></td>';
  351. $ligne .= '<td colspan="3"><b>'.donner("rech_requete").'</b> ';
  352. $ligne .= '( <u>'.$ttype.'</u> )';
  353. $ligne .= ' &gt; <i>'.$this->afficher_requete($this->rq).'</i></td>';
  354. $ligne .= "</tr>";
  355. // En-tête du tableau
  356. $ligne .= '<tr>';
  357. $ligne .= '<th>'.donner("c1").'</th>';
  358. $ligne .= '<th>'.donner("c2").'</th>';
  359. $ligne .= '<th>'.donner("c3").'</th>';
  360. $ligne .= '<th>'.donner("c7").'</th>';
  361. if($ttype == "DEFAULT" or $ttype == "FULLTEXT")
  362. $ligne .= '<th>'.donner("pertinence").'</th>';
  363. $ligne .= '</tr>';
  364. echo $ligne;
  365. /* Avant d'afficher les résultats, on doit normaliser la pertinence s'il s'agit d'une fulltext search. La raison est la suivante: l'indice de pertinence des fulltext search est calculé directement par MySQL. Il n'est pas calculé par la fonction definir_pertinence comme l'indice de pertinence "classique" pour les recherches normales. Or, MySQL n'utilise pas un indice 100 comme cette classe. Il en résulte une distortion de l'indice de pertinence qu'il faut corriger. C'est pourquoi on appelle ici la fonction normaliser_pertinence sur les résultats de recherche s'il s'agit d'une fulltext search */
  366. if($ttype == "FULLTEXT")
  367. $this->tab = $this->normaliser_pertinence($this->tab);
  368. // Remplissage: $lignes = 1 résultat de recherche par ligne
  369. for($i = 0; $i < count($this->tab) ; $i++)
  370. {
  371. // Calcul de la pertinence
  372. if(isset($this->tab[$i]["pertinence"]))
  373. {
  374. $nbsp = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
  375. $pertinence = "<td><div class=\"alert-info\" ";
  376. $pertinence .= "style=\"width:".$this->tab[$i]["pertinence"]."px;\">";
  377. $pertinence .= abbr3($nbsp, donner("pertinence").": ".$this->tab[$i]["pertinence"]."%");
  378. $pertinence .="</div></td>";
  379. }
  380. $lignes[$i] = "<tr class=\"transparent\" style=\"cursor:pointer\"
  381. onClick=\"javascript:js_direct('".$this->tab[$i]["fiche"]."');\">
  382. <td>".abbr3($this->tab[$i]["nom"], donner("afficher_details"))."</td>
  383. <td>".abbr3($this->tab[$i]["prenom"], donner("afficher_details"))."</td>
  384. <td>".abbr3($this->tab[$i]["promotion"], donner("afficher_details"))."</td>
  385. <td>".abbr3($this->tab[$i]["email"], donner("afficher_details"))."</td>";
  386. if(isset($this->tab[$i]["pertinence"])
  387. and ($ttype == "DEFAULT" or $ttype == "FULLTEXT") )
  388. $lignes[$i] .= $pertinence;
  389. else
  390. $lignes[$i] .= "<td>&nbsp;</td>";
  391. $lignes[$i] .= "</tr>\n";
  392. }
  393. // Dédoublonnage (uniquement s'il y a plusieurs lignes...)
  394. if(isset($lignes) and count($lignes) > 1)
  395. $lignes = array_unique($lignes);
  396. // Affichage final (uniquement s'il y a des résultats, càd si $lignes existe...)
  397. if(isset($lignes))
  398. foreach($lignes as $key=>$val)
  399. echo $val;
  400. echo "</table></div>";
  401. }
  402. /*
  403. Nom: construire_requete
  404. But: Cette fonction construit la requête SQL de recherche en fonction des arguments qui lui sont transmis.
  405. Info: Guillaume Florimond, 07/04/2007
  406. Arguments:
  407. $rq => la chaîne ou l'expression régulière à rechercher
  408. $rc => le délimiteur du champ de recherche ($_POST["champ"])
  409. $regex => TRUE s'il s'agit d'une expression régulière, FALSE dans le cas contraire
  410. $fulltext => TRUE si on fait une recherche fulltext, FALSE dans le cas contraire
  411. */
  412. function construire_requete($rq, $rc, $regex, $fulltext)
  413. {
  414. $recherche["requete"] = $rq;
  415. $recherche["champ"] = $rc;
  416. /* Construction de la racine de la requête SQL */
  417. /* Ne pas faire de (SELECT * FROM...) pour éviter que les champs contenant la question personnelle et la réponse secrète soient exportés. */
  418. $sql = "SELECT id, nom, prenom, promotion, email, naissance, adresse, nationalite, q1, q2, q3, q4, q5, q6, q7 FROM utilisateur WHERE ";
  419. /* RECHERCHE FOCALISEE
  420. */
  421. if(isset($recherche["champ"])
  422. and $recherche["champ"] != "tous"
  423. and $recherche["champ"] != "defaut")
  424. {
  425. $sql .= $recherche["champ"];
  426. // Si c'est une expression régulière
  427. if($regex)
  428. $sql .= " REGEXP '".$recherche["requete"]."';";
  429. // Si c'est une fulltext search
  430. elseif($fulltext)
  431. // la recherche fulltext ne fonctionne pas dans les colonnes DATE
  432. $sql = "SELECT id, nom, prenom, promotion, email FROM utilisateur WHERE MATCH(q1,q2,q3,q4,q5,q6,q7) AGAINST ('".$recherche["requete"]."');";
  433. // Si ce n'est pas une expression régulière ni une fulltext search
  434. else
  435. $sql .= "= '".$recherche["requete"]."';";
  436. }
  437. /* RECHERCHE DIFFUSE
  438. */
  439. elseif(isset($recherche["champ"])
  440. and $recherche["champ"] == "tous"
  441. and $recherche["champ"] != "defaut")
  442. {
  443. // Si c'est une expression régulière
  444. if($regex)
  445. {
  446. $sql .= "nom REGEXP '".$recherche["requete"]."' OR ";
  447. $sql .= "prenom REGEXP '".$recherche["requete"]."' OR ";
  448. $sql .= "promotion REGEXP '".$recherche["requete"]."' OR ";
  449. $sql .= "naissance REGEXP '".$recherche["requete"]."' OR ";
  450. $sql .= "nationalite REGEXP '".$recherche["requete"]."' OR ";
  451. $sql .= "adresse REGEXP '".$recherche["requete"]."' OR ";
  452. $sql .= "email REGEXP '".$recherche["requete"]."' OR ";
  453. $sql .= "q1 REGEXP '".$recherche["requete"]."' OR ";
  454. $sql .= "q2 REGEXP '".$recherche["requete"]."' OR ";
  455. $sql .= "q3 REGEXP '".$recherche["requete"]."' OR ";
  456. $sql .= "q4 REGEXP '".$recherche["requete"]."' OR ";
  457. $sql .= "q5 REGEXP '".$recherche["requete"]."' OR ";
  458. $sql .= "q6 REGEXP '".$recherche["requete"]."' OR ";
  459. $sql .= "q7 REGEXP '".$recherche["requete"]."';";
  460. }
  461. // Si c'est une fulltext search
  462. elseif($fulltext)
  463. {
  464. /* Ancienne forme: avant pertinence: DEPRECATED
  465. $sql = "SELECT id, nom, prenom, promotion, email FROM utilisateur WHERE MATCH(q1,q2,q3,q4,q5,q6,q7) AGAINST ('".$recherche["requete"]."');";
  466. */
  467. $sql = "SELECT id, nom, prenom, promotion, email, naissance, adresse, nationalite, q1, q2, q3, q4, q5, q6, q7, MATCH (q1,q2,q3,q4,q5,q6,q7) AGAINST ('".$recherche["requete"]."') AS pertinence FROM utilisateur WHERE MATCH (q1,q2,q3,q4,q5,q6,q7) AGAINST ('".$recherche["requete"]."');";
  468. }
  469. // Si ce n'est pas une expression régulière ni une fulltext search
  470. else
  471. {
  472. $sql .= "nom LIKE '%".$recherche["requete"]."%' OR ";
  473. $sql .= "prenom LIKE '%".$recherche["requete"]."%' OR ";
  474. $sql .= "promotion LIKE '%".$recherche["requete"]."%' OR ";
  475. $sql .= "naissance LIKE '%".$recherche["requete"]."%' OR ";
  476. $sql .= "nationalite LIKE '%".$recherche["requete"]."%' OR ";
  477. $sql .= "adresse LIKE '%".$recherche["requete"]."%' OR ";
  478. $sql .= "email LIKE '%".$recherche["requete"]."%' OR ";
  479. $sql .= "q1 LIKE '%".$recherche["requete"]."%' OR ";
  480. $sql .= "q2 LIKE '%".$recherche["requete"]."%' OR ";
  481. $sql .= "q3 LIKE '%".$recherche["requete"]."%' OR ";
  482. $sql .= "q4 LIKE '%".$recherche["requete"]."%' OR ";
  483. $sql .= "q5 LIKE '%".$recherche["requete"]."%' OR ";
  484. $sql .= "q6 LIKE '%".$recherche["requete"]."%' OR ";
  485. $sql .= "q7 LIKE '%".$recherche["requete"]."%';";
  486. }
  487. }
  488. /* RECHERCHE INTELLIGENTE
  489. */
  490. else
  491. {
  492. // 1. S'il s'agit d'une expression régulière
  493. if($regex)
  494. {
  495. $sql .= "nom REGEXP '".$recherche["requete"]."' OR ";
  496. $sql .= "prenom REGEXP '".$recherche["requete"]."' OR ";
  497. $sql .= "promotion REGEXP '".$recherche["requete"]."' OR ";
  498. $sql .= "naissance REGEXP '".$recherche["requete"]."' OR ";
  499. $sql .= "nationalite REGEXP '".$recherche["requete"]."' OR ";
  500. $sql .= "adresse REGEXP '".$recherche["requete"]."' OR ";
  501. $sql .= "email REGEXP '".$recherche["requete"]."' OR ";
  502. $sql .= "q1 REGEXP '".$recherche["requete"]."' OR ";
  503. $sql .= "q2 REGEXP '".$recherche["requete"]."' OR ";
  504. $sql .= "q3 REGEXP '".$recherche["requete"]."' OR ";
  505. $sql .= "q4 REGEXP '".$recherche["requete"]."' OR ";
  506. $sql .= "q5 REGEXP '".$recherche["requete"]."' OR ";
  507. $sql .= "q6 REGEXP '".$recherche["requete"]."' OR ";
  508. $sql .= "q7 REGEXP '".$recherche["requete"]."';";
  509. // Pour l'exportation
  510. $_SESSION["exportation_permission"] = true;
  511. $_SESSION["exportation_requete"] = $sql;
  512. // Retour
  513. return $sql;
  514. }
  515. // 2. S'il s'agit d'une fulltext search
  516. if($fulltext)
  517. {
  518. // Requête générale
  519. /* Ancienne forme: avant pertinence: DEPRECATED
  520. $sql = "SELECT id, nom, prenom, promotion, email FROM utilisateur WHERE MATCH(q1,q2,q3,q4,q5,q6,q7) AGAINST ('".$recherche["requete"]."');";
  521. */
  522. $sql = "SELECT id, nom, prenom, promotion, email, naissance, adresse, nationalite, q1, q2, q3, q4, q5, q6, q7, MATCH (q1,q2,q3,q4,q5,q6,q7) AGAINST ('".$recherche["requete"]."') AS pertinence FROM utilisateur WHERE MATCH (q1,q2,q3,q4,q5,q6,q7) AGAINST ('".$recherche["requete"]."');";
  523. // Pour l'exportation
  524. $_SESSION["exportation_permission"] = true;
  525. $_SESSION["exportation_requete"] = $sql;
  526. // Retour
  527. return $sql;
  528. }
  529. /* 3. Si ce n'est pas une expression régulière ni une fulltext search, on continue le traitement... */
  530. /* Combien y a-t-il d'opérateurs ET ? (&&)
  531. S'il n'y en a pas, le tableau $rqb aura tout de même 1 instance, qui contiendra la chaîne de recherche entière= $rqb[0];*/
  532. $rqb = explode("&&", $recherche["requete"]);
  533. /* On exécute la boucle de recherche autant de fois qu'il y a de termes dans la boucle ET (p. ex. A&&B&&C&&D = 4 fois ; A = 1 fois). S'il n'y a aucun "ET", il y a tout de même 1 terme dans la recherche, et la boucle est exécutée 1 fois (l'opérateur AND n'est pas ajouté dans ce cas, c'est un ; qui termine l'instruction qui le remplace) */
  534. for ( $i = 0 ; $i < count($rqb) ; $i++ )
  535. {
  536. // Détermine s'il existe un opérateur de comparaison pour la suite
  537. // Les régex exigent entre 2 et 4 chiffres, < ou >, et entre 2 et 4 chiffres.
  538. $regexa = "`^([[:digit:]]{2,4})<([[:digit:]]{2,4})$`";
  539. $regexb = "`^([[:digit:]]{2,4})>([[:digit:]]{2,4})$`";
  540. // 1. Si l'opérateur de comparaison est présent, il est exclusif du reste
  541. if(preg_match($regexa,$rqb[$i]) or preg_match($regexb,$rqb[$i]))
  542. {
  543. // Si c'est l'opérateur < qui est utilisé
  544. if(preg_match($regexa,$rqb[$i],$taba))
  545. $sql .= "promotion BETWEEN ".$taba[1]." AND ".$taba[2];
  546. // Si c'est l'opérateur > qui est utilisé
  547. if(preg_match($regexb,$rqb[$i],$tabb))
  548. $sql .= "promotion BETWEEN ".$tabb[2]." AND ".$tabb[1];
  549. }
  550. // 2. Si l'opérateur de comparaison n'est pas présent, continuer le traitement
  551. else
  552. {
  553. /* Si on recherche une promotion ou une date de naissance... */
  554. if(is_numeric($rqb[$i]))
  555. {
  556. $sql .= "(promotion='".$rqb[$i]."' OR ";
  557. $sql .= "naissance='".$rqb[$i]."')";
  558. }
  559. /* Sinon, c'est qu'on recherche du texte ...*/
  560. else
  561. {
  562. $sql .= "(nom LIKE '%".$rqb[$i]."%' OR ";
  563. $sql .= "prenom LIKE '%".$rqb[$i]."%' OR ";
  564. $sql .= "adresse LIKE '%".$rqb[$i]."%' OR ";
  565. $sql .= "email LIKE '%".$rqb[$i]."%' OR ";
  566. $sql .= "q1 LIKE '%".$rqb[$i]."%' OR ";
  567. $sql .= "q2 LIKE '%".$rqb[$i]."%' OR ";
  568. $sql .= "q3 LIKE '%".$rqb[$i]."%' OR ";
  569. $sql .= "q4 LIKE '%".$rqb[$i]."%' OR ";
  570. $sql .= "q5 LIKE '%".$rqb[$i]."%' OR ";
  571. $sql .= "q6 LIKE '%".$rqb[$i]."%' OR ";
  572. $sql .= "q7 LIKE '%".$rqb[$i]."%')";
  573. }
  574. }
  575. // On n'ajoute AND que si la boucle va s'exécuter encore une fois au moins
  576. if($i+1 < count($rqb))
  577. $sql .= " AND ";
  578. else
  579. $sql .= ";";
  580. }
  581. }
  582. // FIN RECHERCHE INTELLIGENTE
  583. // Pour l'exportation
  584. $_SESSION["exportation_permission"] = true;
  585. $_SESSION["exportation_requete"] = $sql;
  586. // Retour
  587. return $sql;
  588. }
  589. } // fin de la classe
  590. ?>