[SPIP] v3.2.7-->v3.2.9
[lhc/web/www.git] / www / ecrire / inc / prepare_recherche.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Gestion des préparatifs de recherches
15 *
16 * @package SPIP\Core\Recherche
17 **/
18
19 if (!defined('_ECRIRE_INC_VERSION')) {
20 return;
21 }
22
23 include_spip('inc/rechercher');
24 if (!defined('_DELAI_CACHE_resultats')) {
25 define('_DELAI_CACHE_resultats', 600);
26 }
27
28 /**
29 * Préparer les listes `id_article IN (...)` pour les parties WHERE
30 * et calcul des `points` pour la partie SELECT des requêtes du moteur de recherche
31 *
32 * Le paramètre $serveur est utilisé pour savoir sur quelle base on cherche
33 * mais l'index des résultats est toujours stocké sur le serveur principal
34 * car on ne sait pas si la base distante dispose d'une table spip_resultats
35 * ni meme si on aurait le droit d'ecrire dedans
36 *
37 * @param string $recherche
38 * chaine recherchee
39 * @param string $table
40 * table dans laquelle porte la recherche
41 * @param bool $cond
42 * critere conditionnel sur {recherche?}
43 * @param string $serveur
44 * serveur de base de donnees
45 * @param array $modificateurs
46 * modificateurs de boucle, ie liste des criteres presents
47 * @param string $primary
48 * cle primaire de la table de recherche
49 * @return array
50 */
51 function inc_prepare_recherche_dist(
52 $recherche,
53 $table = 'articles',
54 $cond = false,
55 $serveur = '',
56 $modificateurs = array(),
57 $primary = ''
58 ) {
59 static $cache = array();
60 $delai_fraicheur = min(_DELAI_CACHE_resultats,
61 time() - (isset($GLOBALS['meta']['derniere_modif']) ? $GLOBALS['meta']['derniere_modif'] : 0));
62
63 // si recherche n'est pas dans le contexte, on va prendre en globals
64 // ca permet de faire des inclure simple.
65 if (!isset($recherche) and isset($GLOBALS['recherche'])) {
66 $recherche = $GLOBALS['recherche'];
67 }
68
69 // traiter le cas {recherche?}
70 if ($cond and !strlen($recherche)) {
71 return array(
72 "0 as points" /* as points */, /* where */
73 ''
74 );
75 }
76
77
78 $rechercher = false;
79
80 $where_resultat_recent = sql_date_proche('maj', (0 - ($delai_fraicheur + 100)), " SECOND");
81 if (!isset($cache[$serveur][$table][$recherche])) {
82 $hash_serv = ($serveur ? substr(md5($serveur), 0, 16) : '');
83 $hash = substr(md5($recherche . $table), 0, 16);
84 $where = "(resultats.recherche='$hash' AND resultats.table_objet=" . sql_quote($table) . " AND resultats.serveur='$hash_serv')";
85 $row = sql_fetsel('recherche', 'spip_resultats AS resultats',
86 $where . " AND $where_resultat_recent", '', '', '0,1');
87 if (!$row
88 or (defined('_VAR_MODE') and _VAR_MODE == 'recalcul')
89 ) {
90 $rechercher = true;
91 }
92 }
93
94 // si on n'a pas encore traite les donnees dans une boucle precedente
95 if ($rechercher) {
96 //$tables = liste_des_champs();
97 $x = objet_type($table);
98 $points = recherche_en_base($recherche,
99 $x,
100 array(
101 'score' => true,
102 'toutvoir' => true,
103 'jointures' => true
104 ),
105 $serveur);
106 // pas de résultat, pas de point
107 $points = isset($points[$x]) ? $points[$x] : array();
108
109 // permettre aux plugins de modifier le resultat
110 $points = pipeline('prepare_recherche', array(
111 'args' => array(
112 'type' => $x,
113 'recherche' => $recherche,
114 'serveur' => $serveur,
115 'modificateurs' => $modificateurs
116 ),
117 'data' => $points
118 ));
119
120 // supprimer les anciens resultats de cette recherche
121 // et les resultats trop vieux avec une marge
122 // pas de AS resultats dans un delete (mysql)
123 $whered = str_replace(array("resultats.recherche", "resultats.table_objet", "resultats.serveur"),
124 array("recherche", "table_objet", "serveur"), $where);
125
126 sql_delete('spip_resultats',
127 "NOT($where_resultat_recent) OR ($whered)");
128
129 // inserer les resultats dans la table de cache des resultats
130 if (count($points)) {
131 $tab_couples = array();
132 foreach ($points as $id => $p) {
133 $tab_couples[] = array(
134 'recherche' => $hash,
135 'id' => $id,
136 'points' => $p['score'],
137 'table_objet' => $table,
138 'serveur' => $hash_serv,
139 );
140 }
141 sql_insertq_multi('spip_resultats', $tab_couples, array());
142 }
143 }
144
145 if (!isset($cache[$serveur][$table][$recherche])) {
146 if (!$serveur) {
147 $cache[$serveur][$table][$recherche] = array("resultats.points AS points", $where);
148 } else {
149 if (sql_countsel('spip_resultats as resultats', $where)) {
150 $rows = sql_allfetsel('resultats.id,resultats.points', 'spip_resultats as resultats', $where);
151 }
152 $cache[$serveur][$table][$recherche] = generer_select_where_explicites($table, $primary, $rows, $serveur);
153 }
154 }
155
156 return $cache[$serveur][$table][$recherche];
157 }
158
159
160 /**
161 * Generer le select et where qui contiennent explicitement
162 * les id et points (ie comme dans SPIP 1.9.x)
163 * quand on fait une recherche sur une table externe
164 *
165 * @param string $table
166 * @param string $primary
167 * @param array $rows
168 * @param string $serveur
169 * @return array
170 */
171 function generer_select_where_explicites($table, $primary, $rows, $serveur) {
172 # calculer le {id_article IN()} et le {... as points}
173 if (!count($rows)) {
174 return array("''", "0=1");
175 } else {
176 $listes_ids = array();
177 $select = '0';
178 foreach ($rows as $r) {
179 $listes_ids[$r['points']][] = $r['id'];
180 }
181
182 foreach ($listes_ids as $p => $ids) {
183 $select .= "+$p*(" .
184 sql_in("$table.$primary", $ids, '', $serveur)
185 . ") ";
186 }
187
188 return array("$select AS points ", sql_in("$table.$primary", array_map('reset', $rows), '', $serveur));
189 }
190 }