PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/_plugins_/fulltext/inc/recherche_to_array.php

https://bitbucket.org/pombredanne/spip-zone-treemap
PHP | 321 lines | 223 code | 51 blank | 47 comment | 47 complexity | f5feb749a686c70971e046a2877345c1 MD5 | raw file
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. // Determiner les tables gerees via spip_xxx_liens
  13. function recherche_tables_liens() {
  14. if ($GLOBALS['spip_version_base'] >= 16428)
  15. return array('document', 'auteur', 'mot');
  16. else
  17. if ($GLOBALS['spip_version_base'] >= 12008)
  18. return array('document');
  19. else
  20. return array();
  21. }
  22. // methodes sql
  23. function inc_recherche_to_array_dist($recherche, $options=null) {
  24. $requete = array(
  25. "SELECT"=>array(),
  26. "FROM"=>array(),
  27. "WHERE"=>array(),
  28. "GROUPBY"=>array(),
  29. "ORDERBY"=>array(),
  30. "LIMIT"=>"",
  31. "HAVING"=>array()
  32. );
  33. $options = array_merge(
  34. array('table' => 'article',
  35. ),
  36. (array)$options
  37. );
  38. $table = $options['table'];
  39. $serveur = $options['serveur'];
  40. include_spip('inc/rechercher');
  41. // s'il n'y a qu'un mot mais <= 3 lettres, il faut le chercher avec une *
  42. // ex: RFC => RFC* ; car mysql fulltext n'indexe pas ces mots
  43. if (preg_match('/^\w{1,3}$/', $recherche))
  44. $recherche .= '*';
  45. list($methode, $q, $preg) = expression_recherche($recherche, $options);
  46. $l = liste_des_champs();
  47. $champs = $l[$table];
  48. $jointures = $options['jointures']
  49. ? liste_des_jointures()
  50. : array();
  51. $_id_table = id_table_objet($table);
  52. $requete['SELECT'][] = "t.".$_id_table;
  53. $a = array();
  54. // Recherche fulltext
  55. foreach ($champs as $champ => $poids) {
  56. if (is_array($champ)){
  57. spip_log("requetes imbriquees interdites");
  58. } else {
  59. if (strpos($champ,".")===FALSE)
  60. $champ = "t.$champ";
  61. $requete['SELECT'][] = $champ;
  62. $a[] = $champ.' '.$methode.' '.$q;
  63. }
  64. }
  65. if ($a) $requete['WHERE'][] = join(" OR ", $a);
  66. $requete['FROM'][] = table_objet_sql($table).' AS t';
  67. // FULLTEXT
  68. $fulltext = false; # cette table est-elle fulltext?
  69. if ($keys = fulltext_keys($table, 't', $serveur)) {
  70. $fulltext = true;
  71. $r = trim(preg_replace(',\s+,', ' ', $recherche));
  72. // si espace, ajouter la meme chaine avec des guillemets pour ameliorer la pertinence
  73. $pe = (strpos($r, ' ') AND strpos($r,'"')===false)
  74. ? sql_quote(trim("\"$r\""), $serveur) : '';
  75. // On utilise la translitteration pour contourner le pb des bases
  76. // declarees en iso-latin mais remplies d'utf8
  77. if (($r2 = translitteration($r)) != $r)
  78. $r .= ' '.$r2;
  79. $p = sql_quote(trim("$r"), $serveur);
  80. // On va additionner toutes les cles FULLTEXT
  81. // de la table
  82. $score = array();
  83. foreach ($keys as $name => $key) {
  84. $val = "MATCH($key) AGAINST ($p)";
  85. // Une chaine exacte rapporte plein de points
  86. if ($pe)
  87. $val .= "+ 2 * MATCH($key) AGAINST ($pe)";
  88. // Appliquer les ponderations donnees
  89. // quels sont les champs presents ?
  90. // par defaut le poids d'une cle est fonction decroissante
  91. // de son nombre d'elements
  92. // ainsi un FULLTEXT sur `titre` vaudra plus que `titre`,`chapo`
  93. $compteur = preg_match_all(',`.*`,U', $key, $ignore);
  94. $mult = intval(sqrt(1000/$compteur))/10;
  95. // (Compat ascendante) si un FULLTEXT porte sur un seul champ,
  96. // ET est nomme de la meme facon : `titre` (`titre`)
  97. // sa ponderation est eventuellement donnee par la table $liste
  98. if ($key == "t.`${name}`"
  99. AND $ponderation = $liste[$table][$name])
  100. $mult = $ponderation;
  101. // Appliquer le coefficient multiplicatif
  102. if ($mult != 1)
  103. $val = "($val) * $mult";
  104. // si symboles booleens les prendre en compte
  105. if ($boolean = preg_match(', [+-><~]|\* |".*?",', " $r "))
  106. $val = "MATCH($key) AGAINST ($p IN BOOLEAN MODE) * $mult";
  107. $score[] = $val;
  108. }
  109. // On ajoute la premiere cle FULLTEXT de chaque jointure
  110. $from = array_pop($requete['FROM']);
  111. if (is_array($jointures[$table]))
  112. foreach(array_keys($jointures[$table]) as $jtable) {
  113. $i++;
  114. spip_log($pe,'recherche');
  115. if ($mkeys = fulltext_keys($jtable, 'obj'.$i, $serveur)) {
  116. $score[] = "IF(SUM(o".$i.".score) IS NULL,0,SUM(o".$i.".score))";
  117. $_id_join = id_table_objet($jtable);
  118. $table_join = table_objet($jtable);
  119. $lesliens = recherche_tables_liens();
  120. $subscore = "MATCH(".implode($mkeys,',').") AGAINST ($p".($boolean ?' IN BOOLEAN MODE':'').")";
  121. if (in_array($jtable, $lesliens))
  122. $from .= "
  123. LEFT JOIN (
  124. SELECT lien$i.id_objet,$subscore AS score
  125. FROM spip_${jtable}s_liens as lien$i
  126. JOIN spip_${jtable}s as obj$i ON obj$i.$_id_join=lien$i.$_id_join
  127. WHERE lien$i.objet='${table}' ) AS o$i ON o$i.id_objet=t.$_id_table
  128. ";
  129. else
  130. $from .= "
  131. LEFT JOIN (
  132. SELECT lien$i.$_id_table,$subscore AS score
  133. FROM spip_${jtable}s_${table}s as lien$i
  134. JOIN spip_${table_join} AS obj$i ON lien$i.$_id_join=obj$i.$_id_join
  135. ) AS o$i ON o$i.$_id_table=t.$_id_table
  136. ";
  137. }
  138. }
  139. $requete['FROM'][] = $from;
  140. $score = join(' + ', $score).' AS score';
  141. spip_log($score, 'recherche');
  142. // si on define(_FULLTEXT_WHERE_$table,'date>"2000")
  143. // cette contrainte est ajoutee ici:)
  144. $requete['WHERE'] = array();
  145. if (defined('_FULLTEXT_WHERE_'.$table))
  146. $requete['WHERE'][] = constant('_FULLTEXT_WHERE_'.$table);
  147. else
  148. if (!test_espace_prive()
  149. AND !defined('_RECHERCHE_FULLTEXT_COMPLETE')
  150. AND in_array($table, array('article', 'rubrique', 'breve', 'forum', 'syndic_article')))
  151. $requete['WHERE'][] = "t.statut='publie'";
  152. // nombre max de resultats renvoyes par l'API
  153. define('_FULLTEXT_MAX_RESULTS', 500);
  154. // preparer la requete
  155. $requete['SELECT'] = array(
  156. "t.$_id_table"
  157. ,$score
  158. );
  159. // popularite ?
  160. if (true # config : "prendre en compte la popularite
  161. AND $table == 'article')
  162. $requete['SELECT'][] = "t.popularite";
  163. # "t.date"
  164. # "t.note"
  165. #array_unshift($requete['FROM'], table_objet_sql($table)." AS t");
  166. $requete['GROUPBY'] = array("t.$_id_table");
  167. $requete['ORDERBY'] = "score DESC";
  168. $requete['LIMIT'] = "0,"._FULLTEXT_MAX_RESULTS;
  169. $requete['HAVING'] = '';
  170. #var_dump($requete);
  171. #spip_log($requete,'recherche');
  172. #exit;
  173. }
  174. $r = array();
  175. $s = sql_select(
  176. $requete['SELECT'], $requete['FROM'], $requete['WHERE'],
  177. implode(" ",$requete['GROUPBY']),
  178. $requete['ORDERBY'], $requete['LIMIT'],
  179. $requete['HAVING'], $serveur
  180. );
  181. if (!$s) spip_log(mysql_errno().' '.mysql_error()."\n".$recherche, 'recherche');
  182. while ($t = sql_fetch($s,$serveur)
  183. AND (!isset($t['score']) OR $t['score']>0)) {
  184. $id = intval($t[$_id_table]);
  185. // FULLTEXT
  186. if ($fulltext) {
  187. $pts = $t['score'];
  188. if (isset($t['popularite'])
  189. AND $mpop = $GLOBALS['meta']['popularite_max'])
  190. $pts *= (1+$t['popularite']/$mpop);
  191. $r[$id]['score'] = $pts;
  192. } ELSE
  193. // fin FULLTEXT
  194. if ($options['toutvoir']
  195. OR autoriser('voir', $table, $id)) {
  196. // indiquer les champs concernes
  197. $champs_vus = array();
  198. $score = 0;
  199. $matches = array();
  200. $vu = false;
  201. foreach ($champs as $champ => $poids) {
  202. $champ = explode('.',$champ);
  203. $champ = end($champ);
  204. if ($n =
  205. ($options['score'] || $options['matches'])
  206. ? preg_match_all($preg, translitteration_rapide($t[$champ]), $regs, PREG_SET_ORDER)
  207. : preg_match($preg, translitteration_rapide($t[$champ]))
  208. ) {
  209. $vu = true;
  210. if ($options['champs'])
  211. $champs_vus[$champ] = $t[$champ];
  212. if ($options['score'])
  213. $score += $n * $poids;
  214. if ($options['matches'])
  215. $matches[$champ] = $regs;
  216. if (!$options['champs']
  217. AND !$options['score']
  218. AND !$options['matches'])
  219. break;
  220. }
  221. }
  222. if ($vu) {
  223. $r[$id] = array();
  224. if ($champs_vus)
  225. $r[$id]['champs'] = $champs_vus;
  226. if ($score)
  227. $r[$id]['score'] = $score;
  228. if ($matches)
  229. $r[$id]['matches'] = $matches;
  230. }
  231. }
  232. }
  233. // Gerer les donnees associees
  234. if (!$fulltext
  235. AND isset($jointures[$table])
  236. AND $joints = recherche_en_base(
  237. $recherche,
  238. $jointures[$table],
  239. array_merge($options, array('jointures' => false))
  240. )
  241. ) {
  242. foreach ($joints as $jtable => $jj) {
  243. $it = id_table_objet($table);
  244. $ij = id_table_objet($jtable);
  245. $lesliens = recherche_tables_liens();
  246. if (in_array($jtable, $lesliens))
  247. $s = sql_select("id_objet as $it", "spip_${jtable}s_liens", array("objet='$table'",sql_in('id_'.${jtable}, array_keys($jj))), '','','','',$serveur);
  248. else
  249. $s = sql_select("$it,$ij", "spip_${jtable}s_${table}s", sql_in('id_'.${jtable}, array_keys($jj)), '','','','',$serveur);
  250. while ($t = sql_fetch($s)) {
  251. $id = $t[$it];
  252. $joint = $jj[$t[$ij]];
  253. if (!isset($r))
  254. $r = array();
  255. if (!isset($r[$id]))
  256. $r[$id] = array();
  257. if ($joint['score'])
  258. $r[$id]['score'] += $joint['score'];
  259. if ($joint['champs'])
  260. foreach($joint['champs'] as $c => $val)
  261. $r[$id]['champs'][$jtable.'.'.$c] = $val;
  262. if ($joint['matches'])
  263. foreach($joint['matches'] as $c => $val)
  264. $r[$id]['matches'][$jtable.'.'.$c] = $val;
  265. }
  266. }
  267. }
  268. return $r;
  269. }
  270. ?>