[SPIP] ~2.1.12 -->2.1.25
[velocampus/web/www.git] / www / ecrire / inc / rechercher.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2014 *
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 if (!defined('_ECRIRE_INC_VERSION')) return;
15
16
17 // Donne la liste des champs/tables ou l'on sait chercher/remplacer
18 // avec un poids pour le score
19 // http://doc.spip.org/@liste_des_champs
20 function liste_des_champs() {
21 return
22 pipeline('rechercher_liste_des_champs',
23 array(
24 'article' => array(
25 'surtitre' => 5, 'titre' => 8, 'soustitre' => 5, 'chapo' => 3,
26 'texte' => 1, 'ps' => 1, 'nom_site' => 1, 'url_site' => 1,
27 'descriptif' => 4
28 ),
29 'breve' => array(
30 'titre' => 8, 'texte' => 2, 'lien_titre' => 1, 'lien_url' => 1
31 ),
32 'rubrique' => array(
33 'titre' => 8, 'descriptif' => 5, 'texte' => 1
34 ),
35 'site' => array(
36 'nom_site' => 5, 'url_site' => 1, 'descriptif' => 3
37 ),
38 'mot' => array(
39 'titre' => 8, 'texte' => 1, 'descriptif' => 5
40 ),
41 'auteur' => array(
42 'nom' => 5, 'bio' => 1, 'email' => 1, 'nom_site' => 1, 'url_site' => 1, 'login' => 1
43 ),
44 'forum' => array(
45 'titre' => 3, 'texte' => 1, 'auteur' => 2, 'email_auteur' => 2, 'nom_site' => 1, 'url_site' => 1
46 ),
47 'document' => array(
48 'titre' => 3, 'descriptif' => 1, 'fichier' => 1
49 ),
50 'syndic_article' => array(
51 'titre' => 5, 'descriptif' => 1
52 ),
53 'signature' => array(
54 'nom_email' => 2, 'ad_email' => 4,
55 'nom_site' => 2, 'url_site' => 4,
56 'message' => 1
57 )
58
59 )
60 );
61 }
62
63
64 // Recherche des auteurs et mots-cles associes
65 // en ne regardant que le titre ou le nom
66 // http://doc.spip.org/@liste_des_jointures
67 function liste_des_jointures() {
68 return
69 pipeline('rechercher_liste_des_jointures',
70 array(
71 'article' => array(
72 'auteur' => array('nom' => 10),
73 'mot' => array('titre' => 3),
74 'document' => array('titre' => 2, 'descriptif' => 1)
75 ),
76 'breve' => array(
77 'mot' => array('titre' => 3),
78 'document' => array('titre' => 2, 'descriptif' => 1)
79 ),
80 'rubrique' => array(
81 'mot' => array('titre' => 3),
82 'document' => array('titre' => 2, 'descriptif' => 1)
83 ),
84 'document' => array(
85 'mot' => array('titre' => 3)
86 )
87 )
88 );
89 }
90
91
92
93
94 // Effectue une recherche sur toutes les tables de la base de donnees
95 // options :
96 // - toutvoir pour eviter autoriser(voir)
97 // - flags pour eviter les flags regexp par defaut (UimsS)
98 // - champs pour retourner les champs concernes
99 // - score pour retourner un score
100 // On peut passer les tables, ou une chaine listant les tables souhaitees
101 // http://doc.spip.org/@recherche_en_base
102 function recherche_en_base($recherche='', $tables=NULL, $options=array(), $serveur='') {
103 include_spip('base/abstract_sql');
104
105 if (!is_array($tables)) {
106 $liste = liste_des_champs();
107
108 if (is_string($tables)
109 AND $tables != '') {
110 $toutes = array();
111 foreach(explode(',', $tables) as $t)
112 if (isset($liste[$t]))
113 $toutes[$t] = $liste[$t];
114 $tables = $toutes;
115 unset($toutes);
116 } else
117 $tables = $liste;
118 }
119
120 include_spip('inc/autoriser');
121
122 // options par defaut
123 $options = array_merge(array(
124 'preg_flags' => 'UimsS',
125 'toutvoir' => false,
126 'champs' => false,
127 'score' => false,
128 'matches' => false,
129 'jointures' => false
130 ),
131 $options
132 );
133
134 $results = array();
135
136 if (!strlen($recherche) OR !count($tables))
137 return array();
138 include_spip('inc/charsets');
139 $recherche = translitteration($recherche);
140
141 $is_preg = false;
142 if (substr($recherche,0,1)=='/' AND substr($recherche,-1,1)=='/'){
143 // c'est une preg
144 $preg = $recherche.$options['preg_flags'];
145 $is_preg = true;
146 }
147 else
148 $preg = '/'.str_replace('/', '\\/', $recherche).'/' . $options['preg_flags'];
149 // Si la chaine est inactive, on va utiliser LIKE pour aller plus vite
150 // ou si l'expression reguliere est invalide
151 if (!$is_preg
152 OR (@preg_match($preg,'')===FALSE) ) {
153 $methode = 'LIKE';
154 $u = $GLOBALS['meta']['pcre_u'];
155 // eviter les parentheses et autres caractères qui interferent avec pcre par la suite (dans le preg_match_all) s'il y a des reponses
156 $recherche = str_replace(
157 array('(',')','?','[', ']', '+', '*', '/'),
158 array('\(','\)','[?]', '\[', '\]', '\+', '\*', '\/'),
159 $recherche);
160 $recherche_mod = $recherche;
161
162 // echapper les % et _
163 $q = str_replace(array('%','_'), array('\%', '\_'), trim($recherche));
164 // les expressions entre " " sont un mot a chercher tel quel
165 // -> on remplace les espaces par un _ et on enleve les guillemets
166 if (preg_match(',["][^"]+["],Uims',$q,$matches)){
167 foreach($matches as $match){
168 // corriger le like dans le $q
169 $word = preg_replace(",\s+,Uims","_",$match);
170 $word = trim($word,'"');
171 $q = str_replace($match,$word,$q);
172 // corriger la regexp
173 $word = preg_replace(",\s+,Uims","[\s]",$match);
174 $word = trim($word,'"');
175 $recherche_mod = str_replace($match,$word,$recherche_mod);
176 }
177 }
178 $q = sql_quote(
179 "%"
180 . preg_replace(",\s+,".$u, "%", $q)
181 . "%"
182 );
183
184 $preg = '/'.preg_replace(",\s+,".$u, ".+", trim($recherche_mod)).'/' . $options['preg_flags'];
185
186 } else {
187 $methode = 'REGEXP';
188 $q = sql_quote(substr($recherche,1,-1));
189 }
190
191 $jointures = $options['jointures']
192 ? liste_des_jointures()
193 : array();
194
195 foreach ($tables as $table => $champs) {
196 $requete = array(
197 "SELECT"=>array(),
198 "FROM"=>array(),
199 "WHERE"=>array(),
200 "GROUPBY"=>array(),
201 "ORDERBY"=>array(),
202 "LIMIT"=>"",
203 "HAVING"=>array()
204 );
205
206 $_id_table = id_table_objet($table);
207 $requete['SELECT'][] = "t.".$_id_table;
208 $a = array();
209 // Recherche fulltext
210 foreach ($champs as $champ => $poids) {
211 if (is_array($champ)){
212 spip_log("requetes imbriquees interdites");
213 } else {
214 if (strpos($champ,".")===FALSE)
215 $champ = "t.$champ";
216 $requete['SELECT'][] = $champ;
217 $a[] = $champ.' '.$methode.' '.$q;
218 }
219 }
220 if ($a) $requete['WHERE'][] = join(" OR ", $a);
221 $requete['FROM'][] = table_objet_sql($table).' AS t';
222
223 $s = sql_select(
224 $requete['SELECT'], $requete['FROM'], $requete['WHERE'],
225 implode(" ",$requete['GROUPBY']),
226 $requete['ORDERBY'], $requete['LIMIT'],
227 $requete['HAVING'], $serveur
228 );
229
230 while ($t = sql_fetch($s,$serveur)) {
231 $id = intval($t[$_id_table]);
232 if ($options['toutvoir']
233 OR autoriser('voir', $table, $id)) {
234 // indiquer les champs concernes
235 $champs_vus = array();
236 $score = 0;
237 $matches = array();
238
239 $vu = false;
240 foreach ($champs as $champ => $poids) {
241 $champ = explode('.',$champ);
242 $champ = end($champ);
243 if ($n =
244 ($options['score'] || $options['matches'])
245 ? preg_match_all($preg, translitteration_rapide($t[$champ]), $regs, PREG_SET_ORDER)
246 : preg_match($preg, translitteration_rapide($t[$champ]))
247 ) {
248 $vu = true;
249
250 if ($options['champs'])
251 $champs_vus[$champ] = $t[$champ];
252 if ($options['score'])
253 $score += $n * $poids;
254 if ($options['matches'])
255 $matches[$champ] = $regs;
256
257 if (!$options['champs']
258 AND !$options['score']
259 AND !$options['matches'])
260 break;
261 }
262 }
263
264 if ($vu) {
265 if (!isset($results[$table]))
266 $results[$table] = array();
267 $results[$table][$id] = array();
268 if ($champs_vus)
269 $results[$table][$id]['champs'] = $champs_vus;
270 if ($score)
271 $results[$table][$id]['score'] = $score;
272 if ($matches)
273 $results[$table][$id]['matches'] = $matches;
274 }
275 }
276 }
277
278
279 // Gerer les donnees associees
280 if (isset($jointures[$table])
281 AND $joints = recherche_en_base(
282 $recherche,
283 $jointures[$table],
284 array_merge($options, array('jointures' => false))
285 )
286 ) {
287 foreach ($joints as $table_liee => $ids_trouves) {
288 if (!$rechercher_joints = charger_fonction("rechercher_joints_${table}_${table_liee}","inc",true)){
289 $cle_depart = id_table_objet($table);
290 $cle_arrivee = id_table_objet($table_liee);
291 $table_sql = preg_replace('/^spip_/', '', table_objet_sql($table));
292 $table_liee_sql = preg_replace('/^spip_/', '', table_objet_sql($table_liee));
293 if ($table_liee == 'document')
294 $s = sql_select("id_objet as $cle_depart, $cle_arrivee", "spip_documents_liens", array("objet='$table'",sql_in('id_'.${table_liee}, array_keys($ids_trouves))), '','','','',$serveur);
295 else
296 $s = sql_select("$cle_depart,$cle_arrivee", "spip_${table_liee_sql}_${table_sql}", sql_in('id_'.${table_liee}, array_keys($ids_trouves)), '','','','',$serveur);
297 }
298 else
299 list($cle_depart,$cle_arrivee,$s) = $rechercher_joints($table,$table_liee,array_keys($ids_trouves), $serveur);
300
301 while ($t = is_array($s)?array_shift($s):sql_fetch($s)) {
302 $id = $t[$cle_depart];
303 $joint = $ids_trouves[$t[$cle_arrivee]];
304 if (!isset($results[$table]))
305 $results[$table] = array();
306 if (!isset($results[$table][$id]))
307 $results[$table][$id] = array();
308 if ($joint['score'])
309 $results[$table][$id]['score'] += $joint['score'];
310 if ($joint['champs'])
311 foreach($joint['champs'] as $c => $val)
312 $results[$table][$id]['champs'][$table_liee.'.'.$c] = $val;
313 if ($joint['matches'])
314 foreach($joint['matches'] as $c => $val)
315 $results[$table][$id]['matches'][$table_liee.'.'.$c] = $val;
316 }
317 }
318 }
319 }
320
321 return $results;
322 }
323
324
325 // Effectue une recherche sur toutes les tables de la base de donnees
326 // http://doc.spip.org/@remplace_en_base
327 function remplace_en_base($recherche='', $remplace=NULL, $tables=NULL, $options=array()) {
328 include_spip('inc/modifier');
329
330 // options par defaut
331 $options = array_merge(array(
332 'preg_flags' => 'UimsS',
333 'toutmodifier' => false
334 ),
335 $options
336 );
337 $options['champs'] = true;
338
339
340 if (!is_array($tables))
341 $tables = liste_des_champs();
342
343 $results = recherche_en_base($recherche, $tables, $options);
344
345 $preg = '/'.str_replace('/', '\\/', $recherche).'/' . $options['preg_flags'];
346
347 foreach ($results as $table => $r) {
348 $_id_table = id_table_objet($table);
349 foreach ($r as $id => $x) {
350 if ($options['toutmodifier']
351 OR autoriser('modifier', $table, $id)) {
352 $modifs = array();
353 foreach ($x['champs'] as $key => $val) {
354 if ($key == $_id_table) next;
355 $repl = preg_replace($preg, $remplace, $val);
356 if ($repl <> $val)
357 $modifs[$key] = $repl;
358 }
359 if ($modifs)
360 modifier_contenu($table, $id,
361 array(
362 'champs' => array_keys($modifs),
363 ),
364 $modifs);
365 }
366 }
367 }
368 }
369
370 ?>