PageRenderTime 22ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/main/class/search/search_fulltext_fsb.php

http://github.com/FSB/Fire-Soft-Board-2
PHP | 235 lines | 162 code | 22 blank | 51 comment | 30 complexity | 273799d75cc6a6f57d73cb2084ecc9c2 MD5 | raw file
  1. <?php
  2. /**
  3. * Fire-Soft-Board version 2
  4. *
  5. * @package FSB2
  6. * @author Genova <genova@fire-soft-board.com>
  7. * @version $Id$
  8. * @license http://opensource.org/licenses/gpl-2.0.php GNU GPL 2
  9. */
  10. /**
  11. * Methode FULLTEXT FSB, dont le principe s'inspire fortement de celui de phpBB, qui indexe chaque mot du forum.
  12. * Cette methode est utilisee pour les SGBD autre que MySQL, qui ne supportent pas le FULLTEXT MYSQL.
  13. * + Avantage : Rapide, fonctionne sur chaque SGBD
  14. * - Inconvenient : Un peu lourd, place prise dans la base de donnee assez importante
  15. */
  16. class Search_fulltext_fsb extends Search
  17. {
  18. /**
  19. * Liste des mots a ne pas indexer
  20. *
  21. * @var array
  22. */
  23. private $stopwords = array();
  24. /**
  25. * Constructeur, recupere les mots a ne pas indexer
  26. */
  27. public function __construct()
  28. {
  29. $this->min_len = $GLOBALS['_search_min_len'];
  30. $this->max_len = $GLOBALS['_search_max_len'];
  31. // Chargement des mots a ne pas indexer
  32. $this->stopwords = array();
  33. if (file_exists(ROOT . 'lang/' . Fsb::$session->data['u_language'] . '/stopword.txt'))
  34. {
  35. $this->stopwords = array_map('trim', file(ROOT . 'lang/' . Fsb::$session->data['u_language'] . '/stopword.txt'));
  36. }
  37. }
  38. /**
  39. * @see Search::_search()
  40. */
  41. public function _search($keywords_array, $author_nickname, $forum_idx, $topic_id, $date)
  42. {
  43. // Suivant si on doit chercher dans les messages / titres, on construit la clause $sql_is_title
  44. $sql_is_title = '';
  45. if ($this->search_in_post && !$this->search_in_title)
  46. {
  47. $sql_is_title = 'AND sm.is_title = 0';
  48. }
  49. else if (!$this->search_in_post && $this->search_in_title)
  50. {
  51. $sql_is_title = 'AND sm.is_title = 1';
  52. }
  53. $return = array();
  54. if ($total_keywords = count($keywords_array))
  55. {
  56. // Recuperation des sujets indexes sur les mots clefs
  57. $select = new Sql_select();
  58. $select->join_table('FROM', 'search_word sw');
  59. $select->join_table('INNER JOIN', 'search_match sm', 'COUNT(sw.word_content) AS total', 'ON sw.word_id = sm.word_id');
  60. $select->join_table('LEFT JOIN', 'posts p', 'p.p_id', 'ON sm.p_id = p.p_id ' . $sql_is_title);
  61. // Clauses WHERE
  62. $select->where('LOWER(sw.word_content) IN (\'' . implode('\', \'', $keywords_array) . '\')');
  63. $select->where('AND p.f_id IN (' . implode(', ', $forum_idx) . ')');
  64. if ($date > 0)
  65. {
  66. $select->where('AND p.p_time > ' . CURRENT_TIME . ' - ' . $date);
  67. }
  68. if ($author_nickname)
  69. {
  70. $select->where('AND p.p_nickname = \'' . Fsb::$db->escape($author_nickname) . '\'');
  71. }
  72. if ($topic_id)
  73. {
  74. $select->where('AND p.t_id = ' . $topic_id);
  75. }
  76. $select->group_by('p.p_id');
  77. // Resultats
  78. $result = $select->execute();
  79. while ($row = Fsb::$db->row($result))
  80. {
  81. if ($this->search_link == 'or' || $row['total'] == $total_keywords)
  82. {
  83. $return[] = $row['p_id'];
  84. }
  85. }
  86. Fsb::$db->free($result);
  87. }
  88. return ($return);
  89. }
  90. /**
  91. * Parse du message pour indexer les mots dans les tables de recherche
  92. *
  93. * @param int $post_id ID du message
  94. * @param string $content Contenu du message
  95. * @param bool $is_title Definit la valeur du champ is_title dans la table fsb2_search_match
  96. */
  97. public function index($post_id, $content, $is_title = false)
  98. {
  99. // On recupere chaque mot du message
  100. $split = preg_split('#[^\w]+#si', $content);
  101. if ($split)
  102. {
  103. // On recupere tous les mots de la base de donnee definis dans ce message
  104. $words = array();
  105. $word_exist = array();
  106. foreach ($split AS $key => $word)
  107. {
  108. $word = strtolower($word);
  109. if ($word && !isset($word_exist[$word]) && strlen($word) >= $this->min_len && strlen($word) <= $this->max_len && !is_numeric($word))
  110. {
  111. $words[] = $word;
  112. $word_exist[$word] = true;
  113. }
  114. else
  115. {
  116. unset($split[$key]);
  117. }
  118. }
  119. // On supprime les mots interdits
  120. $words = array_diff($words, $this->stopwords);
  121. $flip = array_flip($words);
  122. unset($word_exist);
  123. if ($words)
  124. {
  125. // On ajoute dans la table search_word tous les mots qui n'y sont pas
  126. Fsb::$db->transaction('begin');
  127. $sql = 'SELECT word_content
  128. FROM ' . SQL_PREFIX . 'search_word
  129. WHERE word_content IN (\'' . implode('\', \'', $words) . '\')';
  130. $result = Fsb::$db->query($sql);
  131. while ($row = Fsb::$db->row($result))
  132. {
  133. if (isset($flip[$row['word_content']]))
  134. {
  135. unset($flip[$row['word_content']]);
  136. }
  137. }
  138. Fsb::$db->free($result);
  139. foreach ($flip AS $word => $bool)
  140. {
  141. if ($word)
  142. {
  143. Fsb::$db->insert('search_word', array(
  144. 'word_content' => $word,
  145. ),' INSERT', true);
  146. }
  147. }
  148. Fsb::$db->query_multi_insert();
  149. unset($flip);
  150. // On cree une ocurence de chaque mot avec l'id du message dans la table search_match
  151. $sql = 'INSERT INTO ' . SQL_PREFIX . 'search_match (word_id, p_id, is_title)
  152. SELECT word_id, ' . $post_id . ', ' . (int) $is_title . '
  153. FROM ' . SQL_PREFIX . 'search_word
  154. WHERE word_content IN (\'' . implode('\', \'', $words) . '\')';
  155. Fsb::$db->query($sql);
  156. Fsb::$db->transaction('commit');
  157. }
  158. }
  159. }
  160. /**
  161. * Supprime les index de recherche fulltext_fsb d'un message
  162. *
  163. * @param int $p_id ID du message
  164. */
  165. public function delete_index($p_id)
  166. {
  167. if (!is_array($p_id))
  168. {
  169. $p_id = array($p_id);
  170. }
  171. $list_id = implode(', ', $p_id);
  172. // On selectionne tous les mots du message
  173. $sql = 'SELECT word_id
  174. FROM ' . SQL_PREFIX . 'search_match
  175. WHERE p_id IN (' . $list_id . ')';
  176. $result = Fsb::$db->query($sql);
  177. $idx = '';
  178. while ($row = Fsb::$db->row($result))
  179. {
  180. $idx .= $row['word_id'] . ', ';
  181. }
  182. $idx = substr($idx, 0, -2);
  183. Fsb::$db->free($result);
  184. if ($idx)
  185. {
  186. // On selectionne tous les mots du message existant en un seul exemplaire dans l'index
  187. $sql = 'SELECT word_id
  188. FROM ' . SQL_PREFIX . 'search_match
  189. WHERE word_id IN (' . $idx . ')
  190. GROUP BY word_id
  191. HAVING COUNT(word_id) = 1';
  192. $result = Fsb::$db->query($sql);
  193. $idx = '';
  194. while ($row = Fsb::$db->row($result))
  195. {
  196. $idx .= $row['word_id'] . ', ';
  197. }
  198. $idx = substr($idx, 0, -2);
  199. Fsb::$db->free($result);
  200. // Suppression des index des mots
  201. $sql = 'DELETE FROM ' . SQL_PREFIX . 'search_match
  202. WHERE p_id IN (' . $list_id . ')';
  203. Fsb::$db->query($sql);
  204. if ($idx)
  205. {
  206. $sql = 'DELETE FROM ' . SQL_PREFIX . 'search_word
  207. WHERE word_id IN (' . $idx . ')';
  208. Fsb::$db->query($sql);
  209. }
  210. }
  211. }
  212. }
  213. /* EOF */