Commit | Line | Data |
---|---|---|
c495c100 P |
1 | <?php |
2 | ||
3 | /***************************************************************************\ | |
4 | * SPIP, Systeme de publication pour l'internet * | |
5 | * * | |
6 | * Copyright (c) 2001-2007 * | |
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 | // | |
15 | // Definition des {criteres} d'une boucle | |
16 | // | |
17 | ||
18 | if (!defined("_ECRIRE_INC_VERSION")) return; | |
19 | ||
20 | // {racine} | |
21 | // http://www.spip.net/@racine | |
22 | // http://doc.spip.org/@critere_racine_dist | |
23 | function critere_racine_dist($idb, &$boucles, $crit) { | |
24 | $not = $crit->not; | |
25 | $boucle = &$boucles[$idb]; | |
26 | ||
27 | if ($not) | |
28 | erreur_squelette(_T('zbug_info_erreur_squelette'), $crit->op); | |
29 | ||
30 | $boucle->where[]= array("'='", "'$boucle->id_table." . "id_parent'", 0); | |
31 | } | |
32 | ||
33 | // {exclus} | |
34 | // http://www.spip.net/@exclus | |
35 | // http://doc.spip.org/@critere_exclus_dist | |
36 | function critere_exclus_dist($idb, &$boucles, $crit) { | |
37 | $param = $crit->op; | |
38 | $not = $crit->not; | |
39 | $boucle = &$boucles[$idb]; | |
40 | $id = $boucle->primary; | |
41 | ||
42 | if ($not OR !$id) | |
43 | erreur_squelette(_T('zbug_info_erreur_squelette'), $param); | |
44 | ||
45 | $arg = kwote(calculer_argument_precedent($idb, $id, $boucles)); | |
46 | $boucle->where[]= array("'!='", "'$boucle->id_table." . "$id'", $arg); | |
47 | } | |
48 | ||
49 | // {doublons} ou {unique} | |
50 | // http://www.spip.net/@doublons | |
51 | // attention: boucle->doublons designe une variable qu'on affecte | |
52 | // http://doc.spip.org/@critere_doublons_dist | |
53 | function critere_doublons_dist($idb, &$boucles, $crit) { | |
54 | $boucle = &$boucles[$idb]; | |
55 | if (!$boucle->primary) | |
56 | erreur_squelette(_T('zbug_doublon_table_sans_index'), "BOUCLE$idb"); | |
57 | $nom = !isset($crit->param[0]) ? "''" : calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent); | |
58 | // mettre un tableau pour que ce ne soit pas vu comme une constante | |
59 | $boucle->where[]= array("calcul_mysql_in('".$boucle->id_table . '.' . $boucle->primary . | |
60 | "', " . | |
61 | '"0".$doublons[' . | |
62 | ($crit->not ? '' : ($boucle->doublons . "[]= ")) . | |
63 | "('" . | |
64 | $boucle->type_requete . | |
65 | "'" . | |
66 | ($nom == "''" ? '' : " . $nom") . | |
67 | ')], \'' . | |
68 | ($crit->not ? '' : 'NOT') . | |
69 | "')"); | |
70 | # la ligne suivante avait l'intention d'eviter une collecte deja faite | |
71 | # mais elle fait planter une boucle a 2 critere doublons: | |
72 | # {!doublons A}{doublons B} | |
73 | # (de http://article.gmane.org/gmane.comp.web.spip.devel/31034) | |
74 | # if ($crit->not) $boucle->doublons = ""; | |
75 | } | |
76 | ||
77 | // {lang_select} | |
78 | // http://www.spip.net/@lang_select | |
79 | // http://doc.spip.org/@critere_lang_select_dist | |
80 | function critere_lang_select_dist($idb, &$boucles, $crit) { | |
81 | if (!($param = $crit->param[1][0]->texte)) $param = 'oui'; | |
82 | if ($crit->not) $param = ($param=='oui') ? 'non' : 'oui'; | |
83 | $boucle = &$boucles[$idb]; | |
84 | $boucle->lang_select = $param; | |
85 | } | |
86 | ||
87 | // {debut_xxx} | |
88 | // http://www.spip.net/@debut_ | |
89 | // http://doc.spip.org/@critere_debut_dist | |
90 | function critere_debut_dist($idb, &$boucles, $crit) { | |
91 | $boucle = &$boucles[$idb]; | |
92 | $boucle->limit = 'intval($GLOBALS["debut' . | |
93 | $crit->param[0][0]->texte . | |
94 | '"]) . ",' . | |
95 | $crit->param[1][0]->texte . | |
96 | '"' ; | |
97 | } | |
98 | // {pagination} | |
99 | // {pagination 20} | |
100 | // {pagination #ENV{pages,5}} etc | |
101 | // {pagination 20 #ENV{truc,chose}} pour utiliser la variable debut_#ENV{truc,chose} | |
102 | // http://www.spip.net/@pagination | |
103 | // http://doc.spip.org/@critere_pagination_dist | |
104 | function critere_pagination_dist($idb, &$boucles, $crit) { | |
105 | ||
106 | // definition de la taille de la page | |
107 | $pas = !isset($crit->param[0][0]) ? "''" : calculer_liste(array($crit->param[0][0]), array(), $boucles, $boucles[$idb]->id_parent); | |
108 | $debut = !isset($crit->param[0][1]) ? "'$idb'" : calculer_liste(array($crit->param[0][1]), array(), $boucles, $boucles[$idb]->id_parent); | |
109 | $pas = ($pas== "''") ? '10' : "((\$a = intval($pas)) ? \$a : 10)"; | |
110 | ||
111 | $boucle = &$boucles[$idb]; | |
112 | $boucle->mode_partie = 'p+'; | |
113 | $boucle->partie = 'intval(_request("debut".'.$debut.'))'; | |
114 | $boucle->modificateur['debut_nom'] = $debut; | |
115 | $boucle->total_parties = $pas; | |
116 | if (!isset($boucle->modificateur['fragment'])) | |
117 | $boucle->modificateur['fragment'] = 'fragment_'.$boucle->descr['nom'].$idb; | |
118 | } | |
119 | ||
120 | // {fragment} | |
121 | // http://www.spip.net/@fragment | |
122 | // http://doc.spip.org/@critere_fragment_dist | |
123 | function critere_fragment_dist($idb, &$boucles, $crit) { | |
124 | if (!($param = $crit->param[0][0]->texte)) | |
125 | $param = 'fragment_'.$boucle->descr['nom'].$idb; | |
126 | if ($crit->not) | |
127 | $param = false; | |
128 | $boucle = &$boucles[$idb]; | |
129 | $boucle->modificateur['fragment'] = $param; | |
130 | } | |
131 | ||
132 | ||
133 | // {recherche} | |
134 | // http://www.spip.net/@recherche | |
135 | // http://doc.spip.org/@critere_recherche_dist | |
136 | function critere_recherche_dist($idb, &$boucles, $crit) { | |
137 | global $table_des_tables; | |
138 | $boucle = &$boucles[$idb]; | |
139 | $t = $boucle->id_table; | |
140 | if (in_array($t,$table_des_tables)) | |
141 | $t = "spip_$t"; | |
142 | ||
143 | // Ne pas executer la requete en cas de hash vide | |
144 | $boucle->hash = ' | |
145 | // RECHERCHE | |
146 | list($rech_select, $rech_where) = prepare_recherche($GLOBALS["recherche"], "'.$boucle->primary.'", "'.$boucle->id_table.'", "'.$t.'", "'.$crit->cond.'"); | |
147 | '; | |
148 | ||
149 | // Sauf si le critere est conditionnel {recherche ?} | |
150 | if (!$crit->cond) | |
151 | $boucle->hash .= ' | |
152 | if ($rech_where) '; | |
153 | ||
154 | $t = $boucle->id_table . '.' . $boucle->primary; | |
155 | if (!in_array($t, $boucles[$idb]->select)) | |
156 | $boucle->select[]= $t; # pour postgres, neuneu ici | |
157 | $boucle->select[]= '$rech_select as points'; | |
158 | ||
159 | // et la recherche trouve | |
160 | $boucle->where[]= '$rech_where'; | |
161 | } | |
162 | ||
163 | // {traduction} | |
164 | // http://www.spip.net/@traduction | |
165 | // (id_trad>0 AND id_trad=id_trad(precedent)) | |
166 | // OR id_article=id_article(precedent) | |
167 | // http://doc.spip.org/@critere_traduction_dist | |
168 | function critere_traduction_dist($idb, &$boucles, $crit) { | |
169 | $boucle = &$boucles[$idb]; | |
170 | $prim = $boucle->primary; | |
171 | $table = $boucle->id_table; | |
172 | $arg = kwote(calculer_argument_precedent($idb, 'id_trad', $boucles)); | |
173 | $dprim = kwote(calculer_argument_precedent($idb, $prim, $boucles)); | |
174 | $boucle->where[]= | |
175 | array("'OR'", | |
176 | array("'AND'", | |
177 | array("'='", "'$table.id_trad'", 0), | |
178 | array("'='", "'$table.$prim'", $dprim) | |
179 | ), | |
180 | array("'AND'", | |
181 | array("'>'", "'$table.id_trad'", 0), | |
182 | array("'='", "'$table.id_trad'", $arg) | |
183 | ) | |
184 | ); | |
185 | } | |
186 | ||
187 | // {origine_traduction} | |
188 | // (id_trad>0 AND id_article=id_trad) OR (id_trad=0) | |
189 | // http://www.spip.net/@origine_traduction | |
190 | // http://doc.spip.org/@critere_origine_traduction_dist | |
191 | function critere_origine_traduction_dist($idb, &$boucles, $crit) { | |
192 | $boucle = &$boucles[$idb]; | |
193 | $prim = $boucle->primary; | |
194 | $table = $boucle->id_table; | |
195 | ||
196 | $c = | |
197 | array("'OR'", | |
198 | array("'='", "'$table." . "id_trad'", "'$table.$prim'"), | |
199 | array("'='", "'$table.id_trad'", "'0'") | |
200 | ); | |
201 | $boucle->where[]= ($crit->not ? array("'NOT'", $c) : $c); | |
202 | } | |
203 | ||
204 | // {meme_parent} | |
205 | // http://www.spip.net/@meme_parent | |
206 | // http://doc.spip.org/@critere_meme_parent_dist | |
207 | function critere_meme_parent_dist($idb, &$boucles, $crit) { | |
208 | $boucle = &$boucles[$idb]; | |
209 | $arg = kwote(calculer_argument_precedent($idb, 'id_parent', $boucles)); | |
210 | $mparent = $boucle->id_table . '.id_parent'; | |
211 | ||
212 | if ($boucle->type_requete == 'rubriques') { | |
213 | $boucle->where[]= array("'='", "'$mparent'", $arg); | |
214 | ||
215 | } else if ($boucle->type_requete == 'forums') { | |
216 | $boucle->where[]= array("'='", "'$mparent'", $arg); | |
217 | $boucle->where[]= array("'>'", "'$mparent'", 0); | |
218 | $boucle->modificateur['plat'] = true; | |
219 | } else erreur_squelette(_T('zbug_info_erreur_squelette'), "{meme_parent} BOUCLE$idb"); | |
220 | } | |
221 | ||
222 | // {branche ?} | |
223 | // http://www.spip.net/@branche | |
224 | // http://doc.spip.org/@critere_branche_dist | |
225 | function critere_branche_dist($idb, &$boucles, $crit) { | |
226 | $not = $crit->not; | |
227 | $boucle = &$boucles[$idb]; | |
228 | ||
229 | $arg = calculer_argument_precedent($idb, 'id_rubrique', $boucles); | |
230 | ||
231 | $c = "calcul_mysql_in('" . | |
232 | $boucle->id_table . | |
233 | ".id_rubrique', calcul_branche($arg), '')"; | |
234 | if ($crit->cond) $c = "($arg ? $c : 1)"; | |
235 | ||
236 | if ($not) | |
237 | $boucle->where[]= array("'NOT'", $c); | |
238 | else | |
239 | $boucle->where[]= $c; | |
240 | } | |
241 | ||
242 | // {logo} liste les objets qui ont un logo | |
243 | // http://doc.spip.org/@critere_logo_dist | |
244 | function critere_logo_dist($idb, &$boucles, $crit) { | |
245 | $not = $crit->not; | |
246 | $boucle = &$boucles[$idb]; | |
247 | ||
248 | $c = "calcul_mysql_in('" . | |
249 | $boucle->id_table . '.' . $boucle->primary | |
250 | . "', lister_objets_avec_logos(". $boucle->type_requete ."), '')"; | |
251 | if ($crit->cond) $c = "($arg ? $c : 1)"; | |
252 | ||
253 | if ($not) | |
254 | $boucle->where[]= array("'NOT'", $c); | |
255 | else | |
256 | $boucle->where[]= $c; | |
257 | } | |
258 | ||
259 | // c'est la commande SQL "GROUP BY" | |
260 | // par exemple <boucle(articles){fusion lang}> | |
261 | // http://doc.spip.org/@critere_fusion_dist | |
262 | function critere_fusion_dist($idb,&$boucles, $crit) { | |
263 | if (isset($crit->param[0])) { | |
264 | $x = $crit->param[0]; | |
265 | if ($x[0]->type == 'texte') | |
266 | $boucles[$idb]->group[] = $x[0]->texte; | |
267 | else $boucles[$idb]->group[] = '".' . calculer_critere_arg_dynamique($idb, $boucles, $x) . '."'; | |
268 | } else | |
269 | erreur_squelette(_T('zbug_info_erreur_squelette'), | |
270 | "{groupby ?} BOUCLE$idb"); | |
271 | } | |
272 | ||
273 | // http://doc.spip.org/@calculer_critere_arg_dynamique | |
274 | function calculer_critere_arg_dynamique($idb, &$boucles, $crit, $suffix='') | |
275 | { | |
276 | global $table_des_tables, $tables_des_serveurs_sql; | |
277 | ||
278 | $boucle = $boucles[$idb]; | |
279 | ||
280 | $arg = calculer_liste($crit, array(), $boucles, $boucle->id_parent); | |
281 | $r = $boucle->type_requete; | |
282 | $s = $boucles[$idb]->sql_serveur; | |
283 | if (!$s) $s = 'localhost'; | |
284 | $t = $table_des_tables[$r]; | |
285 | // pour les tables non Spip | |
286 | if (!$t) $t = $r; else $t = "spip_$t"; | |
287 | $desc = $tables_des_serveurs_sql[$s][$t]; | |
288 | ||
289 | if (is_array($desc['field'])){ | |
290 | $liste_field = implode(',',array_map('_q',array_keys($desc['field']))); | |
291 | return "((\$x = preg_replace(\"/\\W/\",'',$arg)) ? ( in_array(\$x,array($liste_field)) ? ('$boucle->id_table.' . \$x$suffix):(\$x$suffix) ) : '')"; | |
292 | } else { | |
293 | return "((\$x = preg_replace(\"/\\W/\",'',$arg)) ? ('$boucle->id_table.' . \$x$suffix) : '')"; | |
294 | } | |
295 | } | |
296 | // Tri : {par xxxx} | |
297 | // http://www.spip.net/@par | |
298 | // http://doc.spip.org/@critere_par_dist | |
299 | function critere_par_dist($idb, &$boucles, $crit) { | |
300 | critere_parinverse($idb, $boucles, $crit, '') ; | |
301 | } | |
302 | ||
303 | // http://doc.spip.org/@critere_parinverse | |
304 | function critere_parinverse($idb, &$boucles, $crit, $sens) { | |
305 | global $table_des_tables, $tables_des_serveurs_sql, $exceptions_des_jointures; | |
306 | $boucle = &$boucles[$idb]; | |
307 | if ($crit->not) $sens = $sens ? "" : " . ' DESC'"; | |
308 | ||
309 | foreach ($crit->param as $tri) { | |
310 | ||
311 | $fct = ""; // en cas de fonction SQL | |
312 | // tris specifies dynamiquement | |
313 | if ($tri[0]->type != 'texte') { | |
314 | // on sait pas faire pour les serveurs externes. A revoir. | |
315 | if (!$boucles[$idb]->sql_serveur) { | |
316 | // calculer le order dynamique qui verifie les champs | |
317 | $order = calculer_critere_arg_dynamique($idb, $boucles, $tri, $sens); | |
318 | // et ajouter un champ hasard dans le select pour supporter 'hasard' comme tri dynamique | |
319 | if (spip_abstract_select(array("RAND()"))) | |
320 | $par = "RAND()"; | |
321 | else | |
322 | $par = "MOD(".$boucle->id_table.'.'.$boucle->primary | |
323 | ." * UNIX_TIMESTAMP(),32767) & UNIX_TIMESTAMP()"; | |
324 | $boucle->select[]= $par . " AS hasard"; | |
325 | } | |
326 | } else { | |
327 | $par = array_shift($tri); | |
328 | $par = $par->texte; | |
329 | // par multi champ | |
330 | if (ereg("^multi[[:space:]]*(.*)$",$par, $m)) { | |
331 | $texte = $boucle->id_table . '.' . trim($m[1]); | |
332 | $boucle->select[] = " \".creer_objet_multi('".$texte."', \$GLOBALS['spip_lang']).\"" ; | |
333 | $order = "multi"; | |
334 | // par num champ(, suite) | |
335 | } else if (ereg("^num[[:space:]]*(.*)$",$par, $m)) { | |
336 | $texte = '0+' . $boucle->id_table . '.' . trim($m[1]); | |
337 | $suite = calculer_liste($tri, array(), $boucles, $boucle->id_parent); | |
338 | if ($suite !== "''") | |
339 | $texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . " . \""; | |
340 | $as = 'num' .($boucle->order ? count($boucle->order) : ""); | |
341 | $boucle->select[] = $texte . " AS $as"; | |
342 | $order = "'$as'"; | |
343 | } else { | |
344 | if (!preg_match(",^" . CHAMP_SQL_PLUS_FONC . '$,is', $par, $match)) | |
345 | erreur_squelette(_T('zbug_info_erreur_squelette'), "{par $par} BOUCLE$idb"); | |
346 | else { | |
347 | if ($match[2]) { $par = substr($match[2],1,-1); $fct = $match[1]; } | |
348 | // par hasard | |
349 | if ($par == 'hasard') { | |
350 | // tester si cette version de MySQL accepte la commande RAND() | |
351 | // sinon faire un gloubi-boulga maison avec de la mayonnaise. | |
352 | if (spip_abstract_select(array("RAND()"))) | |
353 | $par = "RAND()"; | |
354 | else | |
355 | $par = "MOD(".$boucle->id_table.'.'.$boucle->primary | |
356 | ." * UNIX_TIMESTAMP(),32767) & UNIX_TIMESTAMP()"; | |
357 | $boucle->select[]= $par . " AS alea"; | |
358 | $order = "'alea'"; | |
359 | } | |
360 | // par date_thread | |
361 | // (date la plus recente d'un message dans un fil de discussion) | |
362 | else if ($par == 'date_thread') { | |
363 | if ($boucle->type_requete == 'forums') { | |
364 | $t = 'forum'; | |
365 | } else { | |
366 | $t = critere_par_jointure($boucle, array('spip_forum','id_thread')); | |
367 | $t = substr($t, 1, strpos($t,'.')-1); | |
368 | } | |
369 | $boucle->select[] = "MAX($t" . ".". | |
370 | $GLOBALS['table_date']['forums'] | |
371 | .") AS date_thread"; | |
372 | $boucle->group[] = $t . ".id_thread"; | |
373 | $order = "'date_thread'"; | |
374 | $boucle->modificateur['plat'] = true; | |
375 | } | |
376 | // par titre_mot ou type_mot voire d'autres | |
377 | else if (isset($exceptions_des_jointures[$par])) { | |
378 | $order = critere_par_jointure($boucle, $exceptions_des_jointures[$par]); | |
379 | } | |
380 | else if ($par == 'date' | |
381 | AND isset($GLOBALS['table_date'][$boucle->type_requete])) { | |
382 | $m = $GLOBALS['table_date'][$boucle->type_requete]; | |
383 | $order = "'".$boucle->id_table ."." . $m . "'"; | |
384 | } | |
385 | // par champ. Verifier qu'ils sont presents. | |
386 | else { | |
387 | $r = $boucle->type_requete; | |
388 | $s = $boucles[$idb]->sql_serveur; | |
389 | if (!$s) $s = 'localhost'; | |
390 | $t = $table_des_tables[$r]; | |
391 | // pour les tables non Spip | |
392 | if (!$t) $t = $r; else $t = "spip_$t"; | |
393 | $desc = $tables_des_serveurs_sql[$s][$t]; | |
394 | if ($desc['field'][$par]) | |
395 | $par = $boucle->id_table.".".$par; | |
396 | // sinon tant pis, ca doit etre un champ synthetise (cf points) | |
397 | $order = "'$par'"; | |
398 | } | |
399 | } | |
400 | } | |
401 | } | |
402 | if ($order) | |
403 | $boucle->order[] = ($fct ? "'$fct(' . $order . ')'" : $order) . | |
404 | (($order[0]=="'") ? $sens : ""); | |
405 | } | |
406 | } | |
407 | ||
408 | // http://doc.spip.org/@critere_par_jointure | |
409 | function critere_par_jointure(&$boucle, $join) | |
410 | { | |
411 | global $table_des_tables; | |
412 | list($table, $champ) = $join; | |
413 | $t = array_search($table, $boucle->from); | |
414 | if (!$t) { | |
415 | $type = $boucle->type_requete; | |
416 | $nom = $table_des_tables[$type]; | |
417 | list($nom, $desc) = trouver_def_table($nom ? $nom : $type, $boucle); | |
418 | ||
419 | $cle = trouver_champ_exterieur($champ, $boucle->jointures, $boucle); | |
420 | if ($cle) | |
421 | $cle = calculer_jointure($boucle, array($boucle->id_table, $desc), $cle, false); | |
422 | if ($cle) $t = "L$cle"; | |
423 | else erreur_squelette(_T('zbug_info_erreur_squelette'), "{par ?} BOUCLE$idb"); | |
424 | ||
425 | } | |
426 | return "'" . $t . '.' . $champ . "'"; | |
427 | } | |
428 | ||
429 | // {inverse} | |
430 | // http://www.spip.net/@inverse | |
431 | ||
432 | // http://doc.spip.org/@critere_inverse_dist | |
433 | function critere_inverse_dist($idb, &$boucles, $crit) { | |
434 | ||
435 | $boucle = &$boucles[$idb]; | |
436 | // Classement par ordre inverse | |
437 | if ($crit->not) | |
438 | critere_parinverse($idb, $boucles, $crit, " . ' DESC'"); | |
439 | else | |
440 | { | |
441 | $order = "' DESC'"; | |
442 | // Classement par ordre inverse fonction eventuelle de #ENV{...} | |
443 | if (isset($crit->param[0])){ | |
444 | $critere = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent); | |
445 | $order = "(($critere)?' DESC':'')"; | |
446 | } | |
447 | ||
448 | $n = count($boucle->order); | |
449 | if ($n) | |
450 | $boucle->order[$n-1] .= " . $order"; | |
451 | else | |
452 | $boucle->default_order[] = ' DESC'; | |
453 | } | |
454 | } | |
455 | ||
456 | // http://doc.spip.org/@critere_agenda_dist | |
457 | function critere_agenda_dist($idb, &$boucles, $crit) | |
458 | { | |
459 | $params = $crit->param; | |
460 | ||
461 | if (count($params) < 1) | |
462 | erreur_squelette(_T('zbug_info_erreur_squelette'), | |
463 | "{agenda ?} BOUCLE$idb"); | |
464 | ||
465 | $parent = $boucles[$idb]->id_parent; | |
466 | ||
467 | // les valeurs $date et $type doivent etre connus a la compilation | |
468 | // autrement dit ne pas etre des champs | |
469 | ||
470 | $date = array_shift($params); | |
471 | $date = $date[0]->texte; | |
472 | ||
473 | $type = array_shift($params); | |
474 | $type = $type[0]->texte; | |
475 | ||
476 | $annee = $params ? array_shift($params) : ""; | |
477 | $annee = "\n" . 'sprintf("%04d", ($x = ' . | |
478 | calculer_liste($annee, array(), $boucles, $parent) . | |
479 | ') ? $x : date("Y"))'; | |
480 | ||
481 | $mois = $params ? array_shift($params) : ""; | |
482 | $mois = "\n" . 'sprintf("%02d", ($x = ' . | |
483 | calculer_liste($mois, array(), $boucles, $parent) . | |
484 | ') ? $x : date("m"))'; | |
485 | ||
486 | $jour = $params ? array_shift($params) : ""; | |
487 | $jour = "\n" . 'sprintf("%02d", ($x = ' . | |
488 | calculer_liste($jour, array(), $boucles, $parent) . | |
489 | ') ? $x : date("d"))'; | |
490 | ||
491 | $annee2 = $params ? array_shift($params) : ""; | |
492 | $annee2 = "\n" . 'sprintf("%04d", ($x = ' . | |
493 | calculer_liste($annee2, array(), $boucles, $parent) . | |
494 | ') ? $x : date("Y"))'; | |
495 | ||
496 | $mois2 = $params ? array_shift($params) : ""; | |
497 | $mois2 = "\n" . 'sprintf("%02d", ($x = ' . | |
498 | calculer_liste($mois2, array(), $boucles, $parent) . | |
499 | ') ? $x : date("m"))'; | |
500 | ||
501 | $jour2 = $params ? array_shift($params) : ""; | |
502 | $jour2 = "\n" . 'sprintf("%02d", ($x = ' . | |
503 | calculer_liste($jour2, array(), $boucles, $parent) . | |
504 | ') ? $x : date("d"))'; | |
505 | ||
506 | $boucle = &$boucles[$idb]; | |
507 | $date = $boucle->id_table . ".$date"; | |
508 | ||
509 | if ($type == 'jour') | |
510 | $boucle->where[]= array("'='", "'DATE_FORMAT($date, \'%Y%m%d\')'", | |
511 | ("$annee . $mois . $jour")); | |
512 | elseif ($type == 'mois') | |
513 | $boucle->where[]= array("'='", "'DATE_FORMAT($date, \'%Y%m\')'", | |
514 | ("$annee . $mois")); | |
515 | elseif ($type == 'semaine') | |
516 | $boucle->where[]= array("'AND'", | |
517 | array("'>='", | |
518 | "'DATE_FORMAT($date, \'%Y%m%d\')'", | |
519 | ("date_debut_semaine($annee, $mois, $jour)")), | |
520 | array("'<='", | |
521 | "'DATE_FORMAT($date, \'%Y%m%d\')'", | |
522 | ("date_fin_semaine($annee, $mois, $jour)"))); | |
523 | elseif (count($crit->param) > 2) | |
524 | $boucle->where[]= array("'AND'", | |
525 | array("'>='", | |
526 | "'DATE_FORMAT($date, \'%Y%m%d\')'", | |
527 | ("$annee . $mois . $jour")), | |
528 | array("'<='", "'DATE_FORMAT($date, \'%Y%m%d\')'", ("$annee2 . $mois2 . $jour2"))); | |
529 | // sinon on prend tout | |
530 | } | |
531 | ||
532 | // http://doc.spip.org/@calculer_critere_parties | |
533 | function calculer_critere_parties($idb, &$boucles, $crit) { | |
534 | $boucle = &$boucles[$idb]; | |
535 | $a1 = $crit->param[0]; | |
536 | $a2 = $crit->param[1]; | |
537 | $op = $crit->op; | |
538 | list($a11,$a12) = calculer_critere_parties_aux($idb, $boucles, $a1); | |
539 | list($a21,$a22) = calculer_critere_parties_aux($idb, $boucles, $a2); | |
540 | if (($op== ',')&&(is_numeric($a11) && (is_numeric($a21)))) | |
541 | $boucle->limit = $a11 .',' . $a21; | |
542 | else { | |
543 | $boucle->partie = ($a11 != 'n') ? $a11 : $a12; | |
544 | $boucle->total_parties = ($a21 != 'n') ? $a21 : $a22; | |
545 | $boucle->mode_partie = (($op == '/') ? '/' : | |
546 | (($a11=='n') ? '-' : '+').(($a21=='n') ? '-' : '+')); | |
547 | } | |
548 | } | |
549 | ||
550 | // http://doc.spip.org/@calculer_critere_parties_aux | |
551 | function calculer_critere_parties_aux($idb, &$boucles, $param) { | |
552 | if ($param[0]->type != 'texte') | |
553 | { | |
554 | $a1 = calculer_liste(array($param[0]), array('id_mere' => $idb), $boucles, $boucles[$idb]->id_parent); | |
555 | ereg('^ *(-([0-9]+))? *$', $param[1]->texte, $m); | |
556 | return array("intval($a1)", ($m[2] ? $m[2] : 0)); | |
557 | } else { | |
558 | ereg('^ *(([0-9]+)|n) *(- *([0-9]+)? *)?$', $param[0]->texte, $m); | |
559 | $a1 = $m[1]; | |
560 | if (!$m[3]) | |
561 | return array($a1, 0); | |
562 | elseif ($m[4]) | |
563 | return array($a1, $m[4]); | |
564 | else return array($a1, | |
565 | calculer_liste(array($param[1]), array(), $boucles[$idb]->id_parent, $boucles)); | |
566 | } | |
567 | } | |
568 | ||
569 | // | |
570 | // La fonction d'aiguillage sur le nom du critere | |
571 | // | |
572 | ||
573 | // http://doc.spip.org/@calculer_criteres | |
574 | function calculer_criteres ($idb, &$boucles) { | |
575 | ||
576 | foreach($boucles[$idb]->criteres as $crit) { | |
577 | $critere = $crit->op; | |
578 | // critere personnalise ? | |
579 | $f = "critere_".$critere; | |
580 | if (!function_exists($f)) | |
581 | $f .= '_dist'; | |
582 | ||
583 | // fonction critere standard ? | |
584 | if (!function_exists($f)) { | |
585 | // double cas particulier repere a l'analyse lexicale | |
586 | if (($critere == ",") OR ($critere == '/')) | |
587 | $f = 'calculer_critere_parties'; | |
588 | else $f = 'calculer_critere_DEFAUT'; | |
589 | } | |
590 | // Applique le critere | |
591 | $res = $f($idb, $boucles, $crit); | |
592 | ||
593 | // Gestion d'erreur | |
594 | if (is_array($res)) erreur_squelette($res); | |
595 | } | |
596 | } | |
597 | ||
598 | // Madeleine de Proust, revision MIT-1958 sqq, revision CERN-1989 | |
599 | // hum, c'est kwoi cette fonxion ? | |
600 | // http://doc.spip.org/@kwote | |
601 | function kwote($lisp) | |
602 | { | |
603 | if (preg_match(",^(\n//[^\n]*\n)? *'(.*)' *$,", $lisp, $r)) | |
604 | return $r[1] . "\"" . _q(str_replace(array("\\'","\\\\"),array("'","\\"),$r[2])) . "\"" ; | |
605 | else | |
606 | return "_q($lisp)"; | |
607 | } | |
608 | ||
609 | // Si on a une liste de valeurs dans #ENV{x}, utiliser la double etoile | |
610 | // pour faire par exemple {id_article IN #ENV**{liste_articles}} | |
611 | // http://doc.spip.org/@critere_IN_dist | |
612 | function critere_IN_dist ($idb, &$boucles, $crit) | |
613 | { | |
614 | static $cpt = 0; | |
615 | list($arg, $op, $val, $col)= calculer_critere_infixe($idb, $boucles, $crit); | |
616 | ||
617 | $var = '$in' . $cpt++; | |
618 | $x= "\n\t$var = array();"; | |
619 | foreach ($val as $k => $v) { | |
620 | if (preg_match(",^(\n//.*\n)?'(.*)'$,", $v, $r)) { | |
621 | // optimiser le traitement des constantes | |
622 | if (is_numeric($r[2])) | |
623 | $x .= "\n\t$var" . "[]= $r[2];"; | |
624 | else | |
625 | $x .= "\n\t$var" . "[]= " . _q($r[2]) . ";"; | |
626 | } else { | |
627 | // Pour permettre de passer des tableaux de valeurs | |
628 | // on repere l'utilisation brute de #ENV**{X}, | |
629 | // c'est-a-dire sa traduction en ($PILE[0][X]). | |
630 | // et on deballe mais en rajoutant l'anti XSS | |
631 | $x .= "\n\tif (!(is_array($v)))\n\t\t$var" ."[]= $v;\n\telse $var = array_merge($var, $v);"; | |
632 | } | |
633 | } | |
634 | ||
635 | $boucles[$idb]->in .= $x; | |
636 | ||
637 | // inserer la negation (cf !...) | |
638 | if (!$crit->not) { | |
639 | $boucles[$idb]->default_order[] = "'cpt$cpt'"; | |
640 | $op = '<>'; | |
641 | } else $op = '='; | |
642 | ||
643 | $arg = "FIELD($arg,\" . join(',',array_map('_q', $var)) . \")"; | |
644 | if ($boucles[$idb]->group) $arg = "SUM($arg)"; | |
645 | $boucles[$idb]->select[]= "$arg AS cpt$cpt"; | |
646 | $op = array("'$op'", "'cpt$cpt'", 0); | |
647 | ||
648 | // inserer la condition; exemple: {id_mot ?IN (66, 62, 64)} | |
649 | ||
650 | $boucles[$idb]->having[]= (!$crit->cond ? $op : | |
651 | array("'?'", | |
652 | calculer_argument_precedent($idb, $col, $boucles), | |
653 | $op, | |
654 | "''")); | |
655 | } | |
656 | ||
657 | ||
658 | # Criteres de comparaison | |
659 | ||
660 | // http://doc.spip.org/@calculer_critere_DEFAUT | |
661 | function calculer_critere_DEFAUT($idb, &$boucles, $crit) | |
662 | { | |
663 | list($arg, $op, $val, $col)= calculer_critere_infixe($idb, $boucles, $crit); | |
664 | ||
665 | $where = array("'$op'", "'$arg'", $val[0]); | |
666 | ||
667 | // inserer la negation (cf !...) | |
668 | ||
669 | if ($crit->not) $where = array("'NOT'", $where); | |
670 | ||
671 | // inserer la condition (cf {lang?}) | |
672 | ||
673 | $boucles[$idb]->where[]= (!$crit->cond ? $where : | |
674 | array("'?'", | |
675 | calculer_argument_precedent($idb, $col, $boucles), | |
676 | $where, | |
677 | "''")); | |
678 | } | |
679 | ||
680 | // http://doc.spip.org/@calculer_critere_infixe | |
681 | function calculer_critere_infixe($idb, &$boucles, $crit) { | |
682 | ||
683 | global $table_des_tables, $tables_principales, $table_date; | |
684 | global $exceptions_des_jointures; | |
685 | $boucle = &$boucles[$idb]; | |
686 | $type = $boucle->type_requete; | |
687 | $table = $boucle->id_table; | |
688 | ||
689 | list($fct, $col, $op, $val, $args_sql) = | |
690 | calculer_critere_infixe_ops($idb, $boucles, $crit); | |
691 | $col_alias = $col; | |
692 | ||
693 | // Cas particulier : id_enfant => utiliser la colonne id_objet | |
694 | if ($col == 'id_enfant') | |
695 | $col = $boucle->primary; | |
696 | ||
697 | // Cas particulier : id_secteur pour certaines tables | |
698 | else if (($col == 'id_secteur')&&($type == 'breves')) { | |
699 | $col = 'id_rubrique'; | |
700 | } | |
701 | else if (($col == 'id_secteur')&& ($type == 'forums')) { | |
702 | $table = critere_secteur_forum($idb, $boucles, $val, $crit); | |
703 | } | |
704 | ||
705 | // Cas particulier : expressions de date | |
706 | else if ($table_date[$type] | |
707 | AND preg_match(",^((age|jour|mois|annee)_relatif|date|mois|annee|jour|heure|age)(_[a-z]+)?$,", | |
708 | $col, $regs)) { | |
709 | list($col, $table) = | |
710 | calculer_critere_infixe_date($idb, $boucles, $regs); | |
711 | } | |
712 | ||
713 | // HACK : selection des documents selon mode 'image' | |
714 | // => on cherche en fait 'vignette' | |
715 | else if ($type == 'documents' AND $col == 'mode') | |
716 | $val[0] = str_replace('image', 'vignette', $val[0]); | |
717 | ||
718 | else { | |
719 | $nom = $table_des_tables[$type]; | |
720 | list($nom, $desc) = trouver_def_table($nom ? $nom : $type, $boucle); | |
721 | if (@!array_key_exists($col, $desc['field'])) { | |
722 | $calculer_critere_externe = 'calculer_critere_externe_init'; | |
723 | // gestion par les plugins des jointures tordues pas automatiques mais necessaires | |
724 | if (isset($exceptions_des_jointures[$table][$col])){ | |
725 | if (count($exceptions_des_jointures[$table][$col])==3) | |
726 | list($t, $col, $calculer_critere_externe) = $exceptions_des_jointures[$table][$col]; | |
727 | else | |
728 | list($t, $col) = $exceptions_des_jointures[$table][$col]; | |
729 | } | |
730 | else if (isset($exceptions_des_jointures[$col])) | |
731 | // on ignore la table, quel luxe! | |
732 | list($t, $col) = $exceptions_des_jointures[$col]; | |
733 | $table = $calculer_critere_externe($boucle, $boucle->jointures, $col, $desc, ($crit->cond OR $op !='='), $t); | |
734 | } | |
735 | } | |
736 | // tag du critere pour permettre aux boucles de modifier leurs requetes par defaut en fonction de ca | |
737 | $boucles[$idb]->modificateur['criteres'][$col] = true; | |
738 | ||
739 | // ajout pour le cas special d'une condition sur le champ statut: | |
740 | // il faut alors interdire a la fonction de boucle | |
741 | // de mettre ses propres criteres de statut | |
742 | // http://www.spip.net/@statut (a documenter) | |
743 | // garde pour compatibilite avec code des plugins anterieurs, mais redondant avec la ligne precedente | |
744 | if ($col == 'statut') $boucles[$idb]->statut = true; | |
745 | ||
746 | // ajout pour le cas special des forums | |
747 | // il faut alors interdire a la fonction de boucle sur forum | |
748 | // de selectionner uniquement les forums sans pere | |
749 | ||
750 | elseif ($boucles[$idb]->type_requete == 'forums' AND | |
751 | ($col == 'id_parent' OR $col == 'id_forum')) | |
752 | $boucles[$idb]->modificateur['plat'] = true; | |
753 | // inserer le nom de la table SQL devant le nom du champ | |
754 | if ($table) { | |
755 | if ($col[0] == "`") | |
756 | $arg = "$table." . substr($col,1,-1); | |
757 | else $arg = "$table.$col"; | |
758 | } else $arg = $col; | |
759 | ||
760 | // inserer la fonction SQL | |
761 | if ($fct) $arg = "$fct($arg$args_sql)"; | |
762 | ||
763 | return array($arg, $op, $val, $col_alias); | |
764 | } | |
765 | ||
766 | // Faute de copie du champ id_secteur dans la table des forums, | |
767 | // faut le retrouver par jointure | |
768 | // Pour chaque Row il faudrait tester si le forum est | |
769 | // d'article, de breve, de rubrique, ou de syndication. | |
770 | // Pour le moment on ne traite que les articles, | |
771 | // les 3 autres cas ne marcheront donc pas: ca ferait 4 jointures | |
772 | // qu'il faut traiter optimalement ou alors pas du tout. | |
773 | ||
774 | // http://doc.spip.org/@critere_secteur_forum | |
775 | function critere_secteur_forum($idb, &$boucles, $val, $crit) | |
776 | { | |
777 | list($nom, $desc) = trouver_def_table('articles', $boucles[$idb]); | |
778 | return calculer_critere_externe_init($boucles[$idb], array($nom), 'id_secteur', $desc, $crit->cond, true); | |
779 | } | |
780 | ||
781 | // Champ hors table, ca ne peut etre qu'une jointure. | |
782 | // On cherche la table du champ et on regarde si elle est deja jointe | |
783 | // Si oui et qu'on y cherche un champ nouveau, pas de jointure supplementaire | |
784 | // Exemple: criteres {titre_mot=...}{type_mot=...} | |
785 | // Dans les 2 autres cas ==> jointure | |
786 | // (Exemple: criteres {type_mot=...}{type_mot=...} donne 2 jointures | |
787 | // pour selectioner ce qui a exactement ces 2 mots-cles. | |
788 | ||
789 | // http://doc.spip.org/@calculer_critere_externe_init | |
790 | function calculer_critere_externe_init(&$boucle, $joints, $col, $desc, $eg, $checkarrivee = false) | |
791 | { | |
792 | $cle = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee); | |
793 | if ($cle) { | |
794 | $t = array_search($cle[0], $boucle->from); | |
795 | if ($t) { | |
796 | $c = '/\b' . $t . ".$col" . '\b/'; | |
797 | if (!trouver_champ($c, $boucle->where)) { | |
798 | // mais ca peut etre dans le FIELD pour le Having | |
799 | $c = "/FIELD.$t" .".$col,/"; | |
800 | if (!trouver_champ($c, $boucle->select)) return $t; | |
801 | } | |
802 | } | |
803 | $cle = calculer_jointure($boucle, array($boucle->id_table, $desc), $cle, $col, $eg); | |
804 | if ($cle) return "L$cle"; | |
805 | } | |
806 | ||
807 | erreur_squelette(_T('zbug_info_erreur_squelette'), | |
808 | _T('zbug_boucle') . | |
809 | " $idb " . | |
810 | _T('zbug_critere_inconnu', | |
811 | array('critere' => $col))); | |
812 | } | |
813 | ||
814 | // http://doc.spip.org/@trouver_champ | |
815 | function trouver_champ($champ, $where) | |
816 | { | |
817 | if (!is_array($where)) | |
818 | return preg_match($champ,$where); | |
819 | else { | |
820 | foreach ($where as $clause) { | |
821 | if (trouver_champ($champ, $clause)) return true; | |
822 | } | |
823 | return false; | |
824 | } | |
825 | } | |
826 | ||
827 | // deduction automatique des jointures | |
828 | // une jointure sur une table avec primary key doit se faire sur celle-ci. | |
829 | ||
830 | // http://doc.spip.org/@calculer_jointure | |
831 | function calculer_jointure(&$boucle, $depart, $arrivee, $col='', $cond=false) | |
832 | { | |
833 | static $num=array(); | |
834 | $res = calculer_chaine_jointures($boucle, $depart, $arrivee); | |
835 | if (!$res) return ""; | |
836 | ||
837 | list($dnom,$ddesc) = $depart; | |
838 | $id_primary = $ddesc['key']['PRIMARY KEY']; | |
839 | $keys = preg_split('/,\s*/', $id_primary); | |
840 | $id_table = ""; | |
841 | $cpt = &$num[$boucle->descr['nom']][$boucle->id_boucle]; | |
842 | foreach($res as $r) { | |
843 | list($d, $a, $j) = $r; | |
844 | $n = ++$cpt; | |
845 | $boucle->join[$n]= array(($id_table ? $id_table : $d), $j); | |
846 | $boucle->from[$id_table = "L$n"] = $a[0]; | |
847 | } | |
848 | ||
849 | // pas besoin de group by | |
850 | // (cf http://article.gmane.org/gmane.comp.web.spip.devel/30555) | |
851 | // si une seule jointure et sur une table avec primary key formee | |
852 | // de l'index principal et de l'index de jointure (non conditionnel! [6031]) | |
853 | // et operateur d'egalite (http://trac.rezo.net/trac/spip/ticket/477) | |
854 | ||
855 | if ($pk = (count($boucle->from) == 1) && !$cond) { | |
856 | if ($pk = $a[1]['key']['PRIMARY KEY']) { | |
857 | $pk=preg_match("/^$id_primary, *$col$/", $pk) OR | |
858 | preg_match("/^$col, *$id_primary$/", $pk); | |
859 | } | |
860 | } | |
861 | // la clause Group by est en conflit avec ORDER BY, a completer | |
862 | ||
863 | if (!$pk) | |
864 | foreach($keys as $id_prim){ | |
865 | $id_field = $dnom . '.' . $id_prim; | |
866 | if (!in_array($id_field, $boucle->group)) { | |
867 | $boucle->group[] = $id_field; | |
868 | // postgres exige que le champ pour GROUP soit dans le SELECT | |
869 | if (!in_array($id_field, $boucle->select)) | |
870 | $boucle->select[] = $id_field; | |
871 | } | |
872 | } | |
873 | ||
874 | $boucle->modificateur['lien'] = true; | |
875 | return $n; | |
876 | } | |
877 | ||
878 | // http://doc.spip.org/@calculer_chaine_jointures | |
879 | function calculer_chaine_jointures(&$boucle, $depart, $arrivee, $vu=array(), $milieu_prec = false) | |
880 | { | |
881 | list($dnom,$ddesc) = $depart; | |
882 | list($anom,$adesc) = $arrivee; | |
883 | if (!count($vu)) | |
884 | $vu[] = $dnom; // ne pas oublier la table de depart | |
885 | ||
886 | $keys = $ddesc['key']; | |
887 | if ($v = $adesc['key']['PRIMARY KEY']) { | |
888 | unset($adesc['key']['PRIMARY KEY']); | |
889 | $akeys = array_merge(preg_split('/,\s*/', $v), $adesc['key']); | |
890 | } | |
891 | else $akeys = $adesc['key']; | |
892 | // priorite a la primaire, qui peut etre multiple | |
893 | if ($v = (preg_split('/,\s*/', $keys['PRIMARY KEY']))) | |
894 | $keys = $v; | |
895 | $v = array_intersect($keys, $akeys); | |
896 | if ($v) | |
897 | return array(array($dnom, $arrivee, array_shift($v))); | |
898 | else { | |
899 | $new = $vu; | |
900 | foreach($boucle->jointures as $v) { | |
901 | if ($v && (!in_array($v,$vu)) && | |
902 | ($def = trouver_def_table($v, $boucle))) { | |
903 | list($table,$join) = $def; | |
904 | $milieu = array_intersect($ddesc['key'], trouver_cles_table($join['key'])); | |
905 | $new[] = $v; | |
906 | foreach ($milieu as $k) | |
907 | if ($k!=$milieu_prec) // ne pas repasser par la meme cle car c'est un chemin inutilement long | |
908 | { | |
909 | $r = calculer_chaine_jointures($boucle, array($v, $join), $arrivee, $new, $k); | |
910 | if ($r) { | |
911 | array_unshift($r, array($dnom, $def, $k)); | |
912 | return $r; | |
913 | } | |
914 | } | |
915 | } | |
916 | } | |
917 | } | |
918 | return array(); | |
919 | } | |
920 | ||
921 | // applatit les cles multiples | |
922 | ||
923 | // http://doc.spip.org/@trouver_cles_table | |
924 | function trouver_cles_table($keys) | |
925 | { | |
926 | $res =array(); | |
927 | foreach ($keys as $v) { | |
928 | if (!strpos($v,",")) | |
929 | $res[$v]=1; | |
930 | else { | |
931 | foreach (split(" *, *", $v) as $k) { | |
932 | $res[$k]=1; | |
933 | } | |
934 | } | |
935 | } | |
936 | return array_keys($res); | |
937 | } | |
938 | ||
939 | // Trouve la description d'une table dans les globales de Spip | |
940 | // (le prefixe des tables y est toujours 'spip_', son chgt est ulterieur) | |
941 | // Si on ne la trouve pas, on demande au serveur SQL (marche pas toujours) | |
942 | ||
943 | // http://doc.spip.org/@trouver_def_table | |
944 | function trouver_def_table($nom, &$boucle) | |
945 | { | |
946 | global $tables_principales, $tables_auxiliaires, $table_des_tables, $tables_des_serveurs_sql; | |
947 | ||
948 | $nom_table = $nom; | |
949 | $s = $boucle->sql_serveur; | |
950 | if (!$s) { | |
951 | $s = 'localhost'; | |
952 | if (in_array($nom, $table_des_tables)) | |
953 | $nom_table = 'spip_' . $nom; | |
954 | } | |
955 | ||
956 | $desc = $tables_des_serveurs_sql[$s]; | |
957 | ||
958 | if (isset($desc[$nom_table])) | |
959 | return array($nom_table, $desc[$nom_table]); | |
960 | ||
961 | include_spip('base/auxiliaires'); | |
962 | $nom_table = 'spip_' . $nom; | |
963 | if ($desc = $tables_auxiliaires[$nom_table]) | |
964 | return array($nom_table, $desc); | |
965 | ||
966 | if ($desc = spip_abstract_showtable($nom, $boucle->sql_serveur)) | |
967 | if (isset($desc['field'])) { | |
968 | // faudrait aussi prevoir le cas du serveur externe | |
969 | $tables_principales[$nom] = $desc; | |
970 | return array($nom, $desc); | |
971 | } | |
972 | erreur_squelette(_T('zbug_table_inconnue', array('table' => $nom)), | |
973 | $boucle->id_boucle); | |
974 | } | |
975 | ||
976 | // http://doc.spip.org/@trouver_champ_exterieur | |
977 | function trouver_champ_exterieur($cle, $joints, &$boucle, $checkarrivee = false) | |
978 | { | |
979 | foreach($joints as $k => $join) { | |
980 | if ($join && $table = trouver_def_table($join, $boucle)) { | |
981 | if (array_key_exists($cle, $table[1]['field']) | |
982 | && ($checkarrivee==false || $checkarrivee==$table[0])) // si on sait ou on veut arriver, il faut que ca colle | |
983 | return $table; | |
984 | } | |
985 | } | |
986 | return ""; | |
987 | } | |
988 | ||
989 | // determine l'operateur et les operandes | |
990 | ||
991 | // http://doc.spip.org/@calculer_critere_infixe_ops | |
992 | function calculer_critere_infixe_ops($idb, &$boucles, $crit) | |
993 | { | |
994 | // cas d'une valeur comparee a elle-meme ou son referent | |
995 | if (count($crit->param) == 0) | |
996 | { $op = '='; | |
997 | $col = $val = $crit->op; | |
998 | // Cas special {lang} : aller chercher $GLOBALS['spip_lang'] | |
999 | if ($val == 'lang') | |
1000 | $val = array(kwote('$GLOBALS[\'spip_lang\']')); | |
1001 | else { | |
1002 | // Si id_parent, comparer l'id_parent avec l'id_objet | |
1003 | // de la boucle superieure.... faudrait verifier qu'il existe | |
1004 | // pour eviter l'erreur SQL | |
1005 | if ($val == 'id_parent') | |
1006 | $val = $boucles[$idb]->primary; | |
1007 | // Si id_enfant, comparer l'id_objet avec l'id_parent | |
1008 | // de la boucle superieure | |
1009 | else if ($val == 'id_enfant') | |
1010 | $val = 'id_parent'; | |
1011 | $val = array(kwote(calculer_argument_precedent($idb, $val, $boucles))); | |
1012 | } | |
1013 | } else { | |
1014 | // comparaison explicite | |
1015 | // le phraseur impose que le premier param soit du texte | |
1016 | $params = $crit->param; | |
1017 | $op = $crit->op; | |
1018 | if ($op == '==') $op = 'REGEXP'; | |
1019 | $col = array_shift($params); | |
1020 | $col = $col[0]->texte; | |
1021 | ||
1022 | $val = array(); | |
1023 | $desc = array('id_mere' => $idb); | |
1024 | $parent = $boucles[$idb]->id_parent; | |
1025 | ||
1026 | // Dans le cas {x=='#DATE'} etc, defaire le travail du phraseur, | |
1027 | // celui ne sachant pas ce qu'est un critere infixe | |
1028 | // et a fortiori son 2e operande qu'entoure " ou ' | |
1029 | if (count($params)==1 | |
1030 | AND count($params[0]==3) | |
1031 | AND $params[0][0]->type == 'texte' | |
1032 | AND $params[0][2]->type == 'texte' | |
1033 | AND ($p=$params[0][0]->texte) == $params[0][2]->texte | |
1034 | AND (($p == "'") OR ($p == '"')) | |
1035 | AND $params[0][1]->type == 'champ' ) { | |
1036 | $val[]= "$p\\$p#" . $params[0][1]->nom_champ . "\\$p$p"; | |
1037 | } | |
1038 | else | |
1039 | foreach ((($op != 'IN') ? $params : calculer_vieux_in($params)) as $p) { | |
1040 | $a = calculer_liste($p, $desc, $boucles, $parent); | |
1041 | if ($op == 'IN') $val[]= $a; | |
1042 | else $val[]=kwote($a); | |
1043 | } | |
1044 | } | |
1045 | ||
1046 | $fct = $args_sql = ''; | |
1047 | // fonction SQL ? | |
1048 | if (preg_match('/^(.*)' . SQL_ARGS . '$/', $col, $m)) { | |
1049 | $fct = $m[1]; | |
1050 | preg_match('/^\(([^,]*)(.*)\)$/', $m[2], $a); | |
1051 | $col = $a[1]; | |
1052 | if (preg_match('/^(\S*)(\s+AS\s+.*)$/i', $col, $m)) { | |
1053 | $col=$m[1]; | |
1054 | $args_sql = $m[2]; | |
1055 | } | |
1056 | $args_sql .= $a[2];; | |
1057 | } | |
1058 | return array($fct, $col, $op, $val, $args_sql); | |
1059 | } | |
1060 | ||
1061 | // compatibilite ancienne version | |
1062 | ||
1063 | // http://doc.spip.org/@calculer_vieux_in | |
1064 | function calculer_vieux_in($params) | |
1065 | { | |
1066 | $deb = $params[0][0]; | |
1067 | $k = count($params)-1; | |
1068 | $last = $params[$k]; | |
1069 | $j = count($last)-1; | |
1070 | $last = $last[$j]; | |
1071 | $n = strlen($last->texte); | |
1072 | ||
1073 | if (!(($deb->texte[0] == '(') && ($last->texte[$n-1] == ')'))) | |
1074 | return $params; | |
1075 | $params[0][0]->texte = substr($deb->texte,1); | |
1076 | // attention, on peut avoir k=0,j=0 ==> recalculer | |
1077 | $last = $params[$k][$j]; | |
1078 | $n = strlen($last->texte); | |
1079 | $params[$k][$j]->texte = substr($last->texte,0,$n-1); | |
1080 | $newp = array(); | |
1081 | foreach($params as $v) { | |
1082 | if ($v[0]->type != 'texte') | |
1083 | $newp[] = $v; | |
1084 | else { | |
1085 | foreach(split(',', $v[0]->texte) as $x) { | |
1086 | $t = new Texte; | |
1087 | $t->texte = $x; | |
1088 | $newp[] = array($t); | |
1089 | } | |
1090 | } | |
1091 | } | |
1092 | return $newp; | |
1093 | } | |
1094 | ||
1095 | // http://doc.spip.org/@calculer_critere_infixe_date | |
1096 | function calculer_critere_infixe_date($idb, &$boucles, $regs) | |
1097 | { | |
1098 | global $table_date, $table_des_tables, $tables_principales; | |
1099 | $boucle = $boucles[$idb]; | |
1100 | list(,$col, $rel, $suite) = $regs; | |
1101 | $date_orig = $pred = $table_date[$boucle->type_requete]; | |
1102 | if ($suite) { | |
1103 | # Recherche de l'existence du champ date_xxxx, | |
1104 | # si oui choisir ce champ, sinon choisir xxxx | |
1105 | list(,$t)= trouver_def_table($boucle->type_requete, $boucle); | |
1106 | if ($t['field']["date$suite"]) | |
1107 | $date_orig = 'date'.$suite; | |
1108 | else | |
1109 | $date_orig = substr($suite, 1); | |
1110 | $pred = $date_orig; | |
1111 | } else if ($rel) $pred = 'date'; | |
1112 | ||
1113 | $date_compare = "\"' . normaliser_date(" . | |
1114 | calculer_argument_precedent($idb, $pred, $boucles) . | |
1115 | ") . '\""; | |
1116 | $date_orig = $boucle->id_table . '.' . $date_orig; | |
1117 | ||
1118 | if ($col == 'date') { | |
1119 | $col = $date_orig; | |
1120 | $col_table = ''; | |
1121 | } | |
1122 | else if ($col == 'jour') { | |
1123 | $col = "DAYOFMONTH($date_orig)"; | |
1124 | $col_table = ''; | |
1125 | } | |
1126 | else if ($col == 'mois') { | |
1127 | $col = "MONTH($date_orig)"; | |
1128 | $col_table = ''; | |
1129 | } | |
1130 | else if ($col == 'annee') { | |
1131 | $col = "YEAR($date_orig)"; | |
1132 | $col_table = ''; | |
1133 | } | |
1134 | else if ($col == 'heure') { | |
1135 | $col = "DATE_FORMAT($date_orig, '%H:%i')"; | |
1136 | $col_table = ''; | |
1137 | } | |
1138 | else if ($col == 'age') { | |
1139 | $col = calculer_param_date("now()", $date_orig); | |
1140 | $col_table = ''; | |
1141 | } | |
1142 | else if ($col == 'age_relatif') { | |
1143 | $col = calculer_param_date($date_compare, $date_orig); | |
1144 | $col_table = ''; | |
1145 | } | |
1146 | else if ($col == 'jour_relatif') { | |
1147 | $col = "LEAST(TO_DAYS(" .$date_compare . ")-TO_DAYS(" . | |
1148 | $date_orig . "), DAYOFMONTH(" . $date_compare . | |
1149 | ")-DAYOFMONTH(" . $date_orig . ")+30.4368*(MONTH(" . | |
1150 | $date_compare . ")-MONTH(" . $date_orig . | |
1151 | "))+365.2422*(YEAR(" . $date_compare . ")-YEAR(" . | |
1152 | $date_orig . ")))"; | |
1153 | $col_table = ''; | |
1154 | } | |
1155 | else if ($col == 'mois_relatif') { | |
1156 | $col = "MONTH(" . $date_compare . ")-MONTH(" . | |
1157 | $date_orig . ")+12*(YEAR(" . $date_compare . | |
1158 | ")-YEAR(" . $date_orig . "))"; | |
1159 | $col_table = ''; | |
1160 | } | |
1161 | else if ($col == 'annee_relatif') { | |
1162 | $col = "YEAR(" . $date_compare . ")-YEAR(" . | |
1163 | $date_orig . ")"; | |
1164 | $col_table = ''; | |
1165 | } | |
1166 | return array($col, $col_table); | |
1167 | } | |
1168 | ||
1169 | // http://doc.spip.org/@calculer_param_date | |
1170 | function calculer_param_date($date_compare, $date_orig) { | |
1171 | if (ereg("'\" *\.(.*)\. *\"'", $date_compare, $r)) { | |
1172 | $init = "'\" . (\$x = $r[1]) . \"'"; | |
1173 | $date_compare = '\'$x\''; | |
1174 | } | |
1175 | else | |
1176 | $init = $date_compare; | |
1177 | ||
1178 | return | |
1179 | "LEAST((UNIX_TIMESTAMP(" . | |
1180 | $init . | |
1181 | ")-UNIX_TIMESTAMP(" . | |
1182 | $date_orig . | |
1183 | "))/86400,\n\tTO_DAYS(" . | |
1184 | $date_compare . | |
1185 | ")-TO_DAYS(" . | |
1186 | $date_orig . | |
1187 | "),\n\tDAYOFMONTH(" . | |
1188 | $date_compare . | |
1189 | ")-DAYOFMONTH(" . | |
1190 | $date_orig . | |
1191 | ")+30.4368*(MONTH(" . | |
1192 | $date_compare . | |
1193 | ")-MONTH(" . | |
1194 | $date_orig . | |
1195 | "))+365.2422*(YEAR(" . | |
1196 | $date_compare . | |
1197 | ")-YEAR(" . | |
1198 | $date_orig . | |
1199 | ")))"; | |
1200 | } | |
1201 | ?> |