source: spip-zone/_plugins_/fulltext/inc/recherche_to_array.php @ 50704

Last change on this file since 50704 was 50704, checked in by cedric@…, 10 years ago

filtrer la recherche sur le statut publie presume de ce qu'on veut en faire.
On met un define pour patcher rapidement, mais il faudra y revenir mieux que ça

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