squellete2
[aidenligne_francais_universite.git] / ecrire / public / references.php
CommitLineData
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// fonctions de recherche et de reservation
16// dans l'arborescence des boucles
17
18if (!defined("_ECRIRE_INC_VERSION")) return;
19
20// index_pile retourne la position dans la pile du champ SQL $nom_champ
21// en prenant la boucle la plus proche du sommet de pile (indique par $idb).
22// Si on ne trouve rien, on considere que ca doit provenir du contexte
23// (par l'URL ou l'include) qui a ete recopie dans Pile[0]
24// (un essai d'affinage a debouche sur un bug vicieux)
25// Si ca reference un champ SQL, on le memorise dans la structure $boucles
26// afin de construire un requete SQL minimale (plutot qu'un brutal 'SELECT *')
27
28// http://doc.spip.org/@index_pile
29function index_pile($idb, $nom_champ, &$boucles, $explicite='') {
30 global $exceptions_des_tables, $table_des_tables, $tables_des_serveurs_sql;
31
32 $i = 0;
33 if (strlen($explicite)) {
34 // Recherche d'un champ dans un etage superieur
35 while (($idb != $explicite) && ($idb !='')) {
36# spip_log("Cherchexpl: $nom_champ '$explicite' '$idb' '$i'");
37 $i++;
38 $idb = $boucles[$idb]->id_parent;
39 }
40 }
41
42# spip_log("Cherche: $nom_champ a partir de '$idb'");
43 $nom_champ = strtolower($nom_champ);
44 // attention: entre la boucle nommee 0, "" et le tableau vide,
45 // il y a incoherences qu'il vaut mieux eviter
46 while (isset($boucles[$idb])) {
47 list ($t, $c) = index_tables_en_pile($idb, $nom_champ, $boucles);
48 if ($t) {
49 if (!in_array($t, $boucles[$idb]->select))
50 $boucles[$idb]->select[] = $t;
51 return '$Pile[$SP' . ($i ? "-$i" : "") . '][\'' . $c . '\']';
52 }
53# spip_log("On remonte vers $i");
54 // Sinon on remonte d'un cran
55 $idb = $boucles[$idb]->id_parent;
56 $i++;
57 }
58
59# spip_log("Pas vu $nom_champ");
60 // esperons qu'il y sera
61 return('$Pile[0][\''. strtolower($nom_champ) . '\']');
62}
63
64/**
65 * retourne la description de la table associee a un type de boucle
66 * retourne un tableau avec les entrees field et key (comme dans serial.php)
67 * et type = type de boucle, serveur = serveur bdd associe et table = nom de
68 * la table concernee
69 * retourne null si on ne trouve pas la table
70 */
71// http://doc.spip.org/@description_type_requete
72function description_type_requete($type, $serveur='') {
73 global $table_des_tables, $tables_des_serveurs_sql;
74
75 if (!$serveur) {
76 $s = 'localhost';
77 // indirection (pour les rares cas ou le nom de la table!=type)
78 $t = $table_des_tables[$type];
79 } else $s = $serveur;
80 // pour les tables non Spip
81 if (!$t) {
82 $nom_table = $t = $type;
83 } else {
84 $nom_table = 'spip_' . $t;
85 }
86
87 $desc = $tables_des_serveurs_sql[$s][$nom_table];
88 if (!isset($desc['field'])) {
89 $desc = $table_des_tables[$type] ?
90 (($GLOBALS['table_prefix'] ? $GLOBALS['table_prefix'] : 'spip')
91 . '_' . $t) : $nom_table;
92
93 $desc = spip_abstract_showtable($desc, $serveur);
94 if (!isset($desc['field']))
95 return null;
96 $tables_des_serveurs_sql[$s][$nom_table]= $desc;
97 }
98 $desc['serveur']= $s;
99 $desc['type']= $t;
100 $desc['table']= $nom_table;
101
102 return $desc;
103}
104
105// http://doc.spip.org/@index_tables_en_pile
106function index_tables_en_pile($idb, $nom_champ, &$boucles) {
107 global $exceptions_des_tables;
108
109 $r = $boucles[$idb]->type_requete;
110 $s = $boucles[$idb]->sql_serveur;
111
112 $desc= description_type_requete($r, $s);
113
114 if(!$desc) {
115 erreur_squelette(_T('zbug_table_inconnue', array('table' => $r)),
116 "'$idb'");
117 # continuer pour chercher l'erreur suivante
118 return array("'#" . $r . ':' . $nom_champ . "'",'');
119 }
120
121 $t= $desc['type'];
122 $excep = isset($exceptions_des_tables[$r]) ? $exceptions_des_tables[$r] : '';
123 if ($excep)
124 $excep = isset($excep[$nom_champ]) ? $excep[$nom_champ] : '';
125
126 if ($excep) {
127 return index_exception($boucles[$idb], $desc, $nom_champ, $excep);
128 } else {
129 if (isset($desc['field'][$nom_champ]))
130 return array("$t.$nom_champ", $nom_champ);
131 else {
132 if ($boucles[$idb]->jointures_explicites) {
133 $t = trouver_champ_exterieur($nom_champ,
134 $boucles[$idb]->jointures,
135 $boucles[$idb]);
136 if ($t)
137 return index_exception($boucles[$idb],
138 $desc,
139 $nom_champ,
140 array($t[0], $nom_champ));
141 }
142 return array('','');
143 }
144 }
145}
146
147// Reference a une entite SPIP alias d'un champ SQL
148// Ca peut meme etre d'un champ dans une jointure
149// qu'il faut provoquer si ce n'est fait
150
151// http://doc.spip.org/@index_exception
152function index_exception(&$boucle, $desc, $nom_champ, $excep)
153{
154 global $tables_des_serveurs_sql;
155
156 if (is_array($excep)) {
157 // permettre aux plugins de gerer eux meme des jointures derogatoire ingérables
158 $t = NULL;
159 if (count($excep)==3){
160 $index_exception_derogatoire = array_pop($excep);
161 $t = $index_exception_derogatoire($boucle, $desc, $nom_champ, $excep);
162 }
163 if ($t == NULL) {
164 list($e, $x) = $excep; #PHP4 affecte de gauche a droite
165 $excep = $x; #PHP5 de droite a gauche !
166 if (!$t = array_search($e, $boucle->from)) {
167 $t = 'J' . count($boucle->from);
168 $boucle->from[$t] = $e;
169 $j = $tables_des_serveurs_sql[$desc['serveur']][$e];
170 # essayer ca un jour: list($nom, $j) = trouver_def_table($e, $boucle);
171 $j = $j['key']['PRIMARY KEY'];
172 $boucle->where[]= array("'='", "'$boucle->id_table." . "$j'", "'$t.$j'");
173 }
174 }
175 }
176 else $t = $desc['type'];
177 // demander a SQL de gerer le synonyme
178 // ca permet que excep soit dynamique (Cedric, 2/3/06)
179 if ($excep != $nom_champ) $excep .= ' AS '. $nom_champ;
180 return array("$t.$excep", $nom_champ);
181}
182
183
184// cette fonction sert d'API pour demander le champ '$champ' dans la pile
185// http://doc.spip.org/@champ_sql
186function champ_sql($champ, $p) {
187 return index_pile($p->id_boucle, $champ, $p->boucles, $p->nom_boucle);
188}
189
190// cette fonction sert d'API pour demander une balise Spip avec filtres
191
192// http://doc.spip.org/@calculer_champ
193function calculer_champ($p) {
194 $p = calculer_balise($p->nom_champ, $p);
195 return applique_filtres($p);
196}
197
198// Cette fonction sert d'API pour demander une balise SPIP sans filtres.
199// Pour une balise nommmee NOM, elle demande a charger_fonction de chercher
200// s'il existe une fonction balise_NOM ou balise_NOM_dist
201// eventuellement en chargeant le fichier balise/NOM.php.
202// Si ce n'est pas le cas, hormis le cas historique des balise LOGO_*,
203// elle estime que c'est une reference a une colonne de table connue.
204// Les surcharges via charger_fonction sont donc possibles.
205
206// http://doc.spip.org/@calculer_balise
207function calculer_balise($nom, $p) {
208
209 // S'agit-t-il d'une balise_XXXX[_dist]() ?
210 if ($f = charger_fonction($nom, 'balise', true)) {
211 $res = $f($p);
212 if ($res !== NULL)
213 return $res;
214 }
215
216 // S'agit-il d'un logo ? Une fonction speciale les traite tous
217 if (ereg('^LOGO_', $nom)) {
218 if (!function_exists($f = 'calculer_balise_logo')) $f .= '_dist';
219 $res = $f($p);
220 if ($res !== NULL)
221 return $res;
222 }
223
224 // ca pourrait etre un champ SQL homonyme,
225 $p->code = index_pile($p->id_boucle, $nom, $p->boucles, $p->nom_boucle);
226
227 // compatibilite: depuis qu'on accepte #BALISE{ses_args} sans [(...)] autour
228 // il faut recracher {...} quand ce n'est finalement pas des args
229 if ($p->fonctions AND (!$p->fonctions[0][0]) AND $p->fonctions[0][1]) {
230 $code = addslashes($p->fonctions[0][1]);
231 $p->code .= " . '$code'";
232 }
233
234 // ne pas passer le filtre securite sur les id_xxx
235 if (strpos($nom, 'ID_') === 0)
236 $p->interdire_scripts = false;
237
238 // Compatibilite ascendante avec les couleurs html (#FEFEFE) :
239 // SI le champ SQL n'est pas trouve
240 // ET si la balise a une forme de couleur
241 // ET s'il n'y a ni filtre ni etoile
242 // ALORS retourner la couleur.
243 // Ca permet si l'on veut vraiment de recuperer [(#ACCEDE*)]
244 if (preg_match("/^[A-F]{1,6}$/i", $nom)
245 AND !$p->etoile
246 AND !$p->fonctions) {
247 $p->code = "'#$nom'";
248 $p->interdire_scripts = false;
249 }
250
251 return $p;
252}
253
254/*
255
256L'appel direct de #ARTICLE_TRADUCTIONS devient #MODELE{article_traductions}
257
258// fonction speciale d'appel a un modele modeles/truc.html pour la balise #TRUC
259// exemples : #TRADUCTIONS, #DOC, #IMG...
260// http://doc.spip.org/@calculer_balise_modele_dist
261function calculer_balise_modele_dist($p){
262 $nom = strtolower($p->nom_champ);
263 $contexte = array();
264
265 if (isset($p->param[0])){
266 while (count($p->param[0])>2){
267 $p->param[]=array($p->param[0][0],array_pop($p->param[0]));
268 }
269 }
270print_r($p->param);
271 $champ = phraser_arguments_inclure($p, true);
272 // a priori true
273 // si false, le compilo va bloquer sur des syntaxes avec un filtre sans argument qui suit la balise
274 // si true, les arguments simples (sans truc=chose) vont degager
275 $code_contexte = argumenter_inclure($champ, $p->descr, $p->boucles, $p->id_boucle, false);
276
277 // Si le champ existe dans la pile, on le met dans le contexte
278 // (a priori c'est du code mort ; il servait pour #LESAUTEURS dans
279 // le cas spip_syndic_articles)
280 #$code_contexte[] = "'$nom='.".champ_sql($nom, $p);
281
282 // Reserver la cle primaire de la boucle courante
283 if ($primary = $p->boucles[$p->id_boucle]->primary) {
284 $id = champ_sql($primary, $p);
285 $code_contexte[] = "'$primary='.".$id;
286 }
287
288#print_r($code_contexte);
289
290 $p->code = "( ((\$recurs=(isset(\$Pile[0]['recurs'])?\$Pile[0]['recurs']:0))<5)?
291 recuperer_fond('modeles/".$nom."',
292 creer_contexte_de_modele(array(".join(',', $code_contexte).",'recurs='.++\$recurs, \$GLOBALS['spip_lang']))):'')";
293 $p->interdire_scripts = false; // securite assuree par le squelette
294
295print $p->code."\n<hr/>\n";
296
297 return $p;
298}
299*/
300
301//
302// Traduction des balises dynamiques, notamment les "formulaire_*"
303// Inclusion du fichier associe a son nom.
304// Ca donne les arguments a chercher dans la pile,on compile leur localisation
305// Ensuite on delegue a une fonction generale definie dans executer_squelette
306// qui recevra a l'execution la valeur des arguments,
307// ainsi que les pseudo filtres qui ne sont donc pas traites a la compil
308// mais on traite le vrai parametre si present.
309
310// http://doc.spip.org/@calculer_balise_dynamique
311function calculer_balise_dynamique($p, $nom, $l) {
312
313 balise_distante_interdite($p);
314 $param = "";
315 if ($a = $p->param) {
316 $c = array_shift($a);
317 if (!array_shift($c)) {
318 $p->fonctions = $a;
319 array_shift( $p->param );
320 $param = compose_filtres_args($p, $c, ',');
321 }
322 }
323 $collecte = join(',',collecter_balise_dynamique($l, $p, $nom));
324 $p->code = "executer_balise_dynamique('" . $nom . "',\n\tarray("
325 . $collecte
326 . ($collecte ? $param : substr($param,1)) # virer la virgule
327 . "),\n\tarray("
328 . argumenter_balise($p->param, "', '")
329 . "), \$GLOBALS['spip_lang'],"
330 . $p->ligne
331 . ')';
332 $p->interdire_scripts = false;
333 $p->fonctions = array();
334 $p->param = array();
335
336 return $p;
337}
338
339// Construction du tableau des arguments d'une balise dynamique.
340// Ces arguments peuvent etre eux-meme des balises (cf FORMULAIRE_SIGNATURE)
341// mais gare au bouclage (on peut s'aider de $nom pour le reperer au besoin)
342
343// http://doc.spip.org/@collecter_balise_dynamique
344function collecter_balise_dynamique($l, &$p, $nom) {
345 $args = array();
346 foreach($l as $c) { $x = calculer_balise($c, $p); $args[] = $x->code;}
347 return $args;
348}
349
350
351// il faudrait savoir traiter les formulaires en local
352// tout en appelant le serveur SQL distant.
353// En attendant, cette fonction permet de refuser une authentification
354// sur qqch qui n'a rien a voir.
355
356// http://doc.spip.org/@balise_distante_interdite
357function balise_distante_interdite($p) {
358 $nom = $p->id_boucle;
359 if ($nom AND $p->boucles[$nom]->sql_serveur) {
360 erreur_squelette($p->nom_champ .' '._T('zbug_distant_interdit'), $nom);
361 }
362}
363
364
365//
366// Traitements standard de divers champs
367// definis par $table_des_traitements, cf. inc-compilo-api.php3
368//
369// http://doc.spip.org/@champs_traitements
370function champs_traitements ($p) {
371 global $table_des_traitements;
372
373 if (!isset($table_des_traitements[$p->nom_champ]))
374 return $p->code;
375 $ps = $table_des_traitements[$p->nom_champ];
376 if (is_array($ps)) {
377 // new style
378
379 if ($p->nom_boucle)
380 $type = $p->boucles[$p->nom_boucle]->type_requete;
381 else
382 $type = $p->type_requete;
383 $ps = $ps[isset($ps[$type]) ? $type : 0];
384 }
385
386 if (!$ps) return $p->code;
387
388 // Si une boucle sous-jacente (?) traite les documents, on insere ici
389 // une fonction de remplissage du tableau des doublons -- mais seulement
390 // si on rencontre le filtre propre (qui traite les
391 // raccourcis <docXX> qui nous interessent)
392 if (isset($p->descr['documents'])
393 AND preg_match(',propre,', $ps))
394 $ps = 'traiter_doublons_documents($doublons, '.$ps.')';
395
396 // De meme, en cas de sql_serveur, on supprime les < IMGnnn > tant
397 // qu'on ne rapatrie pas les documents distants joints..
398 // il faudrait aussi corriger les raccourcis d'URL locales
399 if ($p->id_boucle AND $p->boucles[$p->id_boucle]->sql_serveur)
400 $p->code = 'supprime_img(' . $p->code . ')';
401
402
403 // Passer |safehtml sur les boucles "sensibles"
404 // sauf sur les champs dont on est surs
405 switch ($p->type_requete) {
406 case 'forums':
407 case 'signatures':
408 case 'syndic_articles':
409 $champs_surs = array(
410 'date', 'date_heure', 'statut', 'ip', 'url_article', 'maj', 'idx',
411 'parametres_forum');
412 if (!in_array(strtolower($p->nom_champ), $champs_surs)
413 AND !preg_match(',^ID_,', $p->nom_champ))
414 $ps = 'safehtml('.$ps.')';
415 break;
416 default:
417 break;
418 }
419
420 // Remplacer enfin le placeholder %s par le vrai code de la balise
421 return str_replace('%s', $p->code, $ps);
422}
423
424
425//
426// Appliquer les filtres a un champ [(#CHAMP|filtre1|filtre2)]
427// retourne un code php compile exprimant ce champ filtre et securise
428// - une etoile => pas de processeurs standards
429// - deux etoiles => pas de securite non plus !
430//
431// http://doc.spip.org/@applique_filtres
432function applique_filtres($p) {
433
434 // Traitements standards (cf. supra)
435 if ($p->etoile == '')
436 $code = champs_traitements($p);
437 else
438 $code = $p->code;
439
440 // Appliquer les filtres perso
441 if ($p->param)
442 $code = compose_filtres($p, $code);
443
444 // Securite
445 if ($p->interdire_scripts
446 AND $p->etoile != '**')
447 $code = "interdire_scripts($code)";
448
449 return $code;
450}
451
452// Cf. function pipeline dans ecrire/inc_utils.php
453// http://doc.spip.org/@compose_filtres
454function compose_filtres($p, $code) {
455 foreach($p->param as $filtre) {
456 $fonc = array_shift($filtre);
457 if ($fonc) {
458 // recuperer les arguments du filtre, les separer par des virgules
459 // *sauf* dans le cas du filtre "?" qui demande un ":"
460 if ($fonc == '?') {
461 // |?{a,b} *doit* avoir exactement 2 arguments ; on les force
462 if (count($filtre) != 2)
463 $filtre = array($filtre[0], $filtre[1]);
464 $arglist = compose_filtres_args($p, $filtre, ':');
465 } else
466 $arglist = compose_filtres_args($p, $filtre, ',');
467
468 // le filtre est defini dans la matrice ? il faut alors l'appeler
469 // de maniere indirecte, pour charger au prealable sa definition
470 if (isset($GLOBALS['spip_matrice'][$fonc])) {
471 $code = "filtrer('$fonc',$code$arglist)";
472 }
473 // le filtre est defini sous forme de fonction ou de methode
474 // par ex. dans inc_texte, inc_filtres ou mes_fonctions
475 else if (function_exists($fonc)
476 OR (preg_match("/^(\w*)::(\w*)$/", $fonc, $regs)
477 AND is_callable(array($regs[1], $regs[2]))
478 ))
479 $code = "$fonc($code$arglist)";
480 // est-ce un test ?
481 else if (strpos("x < > <= >= == === != !== <> ? ", " $fonc "))
482 $code = "($code $fonc " . substr($arglist,1) . ')';
483 else
484 $code = "erreur_squelette('"
485 .texte_script(_T('zbug_erreur_filtre', array('filtre'=>$fonc)))
486 ."','" . $p->id_boucle . "')";
487 }
488 }
489 return $code;
490}
491
492// http://doc.spip.org/@compose_filtres_args
493function compose_filtres_args($p, $args, $sep)
494{
495 $arglist = "";
496 foreach ($args as $arg) {
497 $arglist .= $sep .
498 calculer_liste($arg, $p->descr, $p->boucles, $p->id_boucle);
499 }
500 return $arglist;
501}
502
503//
504// Reserve les champs necessaires a la comparaison avec le contexte donne par
505// la boucle parente ; attention en recursif il faut les reserver chez soi-meme
506// ET chez sa maman
507//
508// http://doc.spip.org/@calculer_argument_precedent
509function calculer_argument_precedent($idb, $nom_champ, &$boucles) {
510
511 // si recursif, forcer l'extraction du champ SQL mais ignorer le code
512 if ($boucles[$idb]->externe)
513 index_pile ($idb, $nom_champ, $boucles);
514 // retourner $Pile[$SP] et pas $Pile[0] (bug recursion en 1ere boucle)
515 $prec = $boucles[$idb]->id_parent;
516 return (($prec==="") ? ('$Pile[$SP][\''.$nom_champ.'\']') :
517 index_pile($prec, $nom_champ, $boucles));
518}
519
520//
521// Rechercher dans la pile des boucles actives celle ayant un critere
522// comportant un certain $motif, et construire alors une reference
523// a l'environnement de cette boucle, qu'on indexe avec $champ.
524// Sert a referencer une cellule non declaree dans la table et pourtant la.
525// Par exemple pour la balise #POINTS on produit $Pile[$SP-n]['points']
526// si la n-ieme boucle a un critere "recherche", car on sait qu'il a produit
527// "SELECT XXXX AS points"
528//
529
530// http://doc.spip.org/@rindex_pile
531function rindex_pile($p, $champ, $motif)
532{
533 $n = 0;
534 $b = $p->id_boucle;
535 $p->code = '';
536 while ($b != '') {
537 if ($s = $p->boucles[$b]->param) {
538 foreach($s as $v) {
539 if (strpos($v[1][0]->texte,$motif) !== false) {
540 $p->code = '$Pile[$SP' . (($n==0) ? "" : "-$n") .
541 "]['$champ']";
542 $b = '';
543 break;
544 }
545 }
546 }
547 $n++;
548 $b = $p->boucles[$b]->id_parent;
549 }
550 if (!$p->code) {
551 erreur_squelette(_T('zbug_champ_hors_motif',
552 array('champ' => '#' . strtoupper($champ),
553 'motif' => $motif)
554 ), $p->id_boucle);
555 }
556 $p->interdire_scripts = false;
557 return $p;
558}
559
560?>