[SPIP] ~v3.0.21-->v3.0.22
[lhc/web/www.git] / www / ecrire / public / balises.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2016 *
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 // Ce fichier regroupe la quasi totalite des definitions de #BALISES de spip
14 // Pour chaque balise, il est possible de surcharger, dans mes_fonctions,
15 // la fonction balise_TOTO_dist par une fonction balise_TOTO() respectant la
16 // meme API :
17 // elle recoit en entree un objet de classe CHAMP, le modifie et le retourne.
18 // Cette classe est definie dans public/interfaces
19
20 if (!defined('_ECRIRE_INC_VERSION')) return;
21
22 // http://doc.spip.org/@interprete_argument_balise
23 function interprete_argument_balise($n,$p) {
24 if (($p->param) && (!$p->param[0][0]) && (count($p->param[0])>$n))
25 return calculer_liste($p->param[0][$n],
26 $p->descr,
27 $p->boucles,
28 $p->id_boucle);
29 else
30 return NULL;
31 }
32 //
33 // Definition des balises
34 //
35 // http://doc.spip.org/@balise_NOM_SITE_SPIP_dist
36 function balise_NOM_SITE_SPIP_dist($p) {
37 $p->code = "\$GLOBALS['meta']['nom_site']";
38 #$p->interdire_scripts = true;
39 return $p;
40 }
41
42 // http://doc.spip.org/@balise_EMAIL_WEBMASTER_dist
43 function balise_EMAIL_WEBMASTER_dist($p) {
44 $p->code = "\$GLOBALS['meta']['email_webmaster']";
45 #$p->interdire_scripts = true;
46 return $p;
47 }
48
49 // http://doc.spip.org/@balise_DESCRIPTIF_SITE_SPIP_dist
50 function balise_DESCRIPTIF_SITE_SPIP_dist($p) {
51 $p->code = "\$GLOBALS['meta']['descriptif_site']";
52 #$p->interdire_scripts = true;
53 return $p;
54 }
55
56 // http://doc.spip.org/@balise_CHARSET_dist
57 function balise_CHARSET_dist($p) {
58 $p->code = "\$GLOBALS['meta']['charset']";
59 #$p->interdire_scripts = true;
60 return $p;
61 }
62
63 // http://doc.spip.org/@balise_LANG_LEFT_dist
64 function balise_LANG_LEFT_dist($p) {
65 $_lang = champ_sql('lang', $p);
66 $p->code = "lang_dir($_lang, 'left','right')";
67 $p->interdire_scripts = false;
68 return $p;
69 }
70
71 // http://doc.spip.org/@balise_LANG_RIGHT_dist
72 function balise_LANG_RIGHT_dist($p) {
73 $_lang = champ_sql('lang', $p);
74 $p->code = "lang_dir($_lang, 'right','left')";
75 $p->interdire_scripts = false;
76 return $p;
77 }
78
79 // http://doc.spip.org/@balise_LANG_DIR_dist
80 function balise_LANG_DIR_dist($p) {
81 $_lang = champ_sql('lang', $p);
82 $p->code = "lang_dir($_lang, 'ltr','rtl')";
83 $p->interdire_scripts = false;
84 return $p;
85 }
86
87 // http://doc.spip.org/@balise_PUCE_dist
88 function balise_PUCE_dist($p) {
89 $p->code = "definir_puce()";
90 $p->interdire_scripts = false;
91 return $p;
92 }
93
94 // #DATE
95 // Cette fonction sait aller chercher dans le contexte general
96 // quand #DATE est en dehors des boucles
97 // http://www.spip.net/fr_article1971.html
98 // http://doc.spip.org/@balise_DATE_dist
99 function balise_DATE_dist ($p) {
100 $d = champ_sql('date', $p);
101 # if ($d === "@\$Pile[0]['date']")
102 # $d = "isset(\$Pile[0]['date']) ? $d : time()";
103 $p->code = $d;
104 return $p;
105 }
106
107 // #DATE_REDAC
108 // http://www.spip.net/fr_article1971.html
109 // http://doc.spip.org/@balise_DATE_REDAC_dist
110 function balise_DATE_REDAC_dist ($p) {
111 $d = champ_sql('date_redac', $p);
112 # if ($d === "@\$Pile[0]['date_redac']")
113 # $d = "isset(\$Pile[0]['date_redac']) ? $d : time()";
114 $p->code = $d;
115 $p->interdire_scripts = false;
116 return $p;
117 }
118
119 // #DATE_MODIF
120 // http://www.spip.net/fr_article1971.html
121 // http://doc.spip.org/@balise_DATE_MODIF_dist
122 function balise_DATE_MODIF_dist ($p) {
123 $p->code = champ_sql('date_modif', $p);
124 $p->interdire_scripts = false;
125 return $p;
126 }
127
128 // #DATE_NOUVEAUTES
129 // http://www.spip.net/fr_article1971.html
130 // http://doc.spip.org/@balise_DATE_NOUVEAUTES_dist
131 function balise_DATE_NOUVEAUTES_dist($p) {
132 $p->code = "((\$GLOBALS['meta']['quoi_de_neuf'] == 'oui'
133 AND isset(\$GLOBALS['meta']['dernier_envoi_neuf'])) ?
134 \$GLOBALS['meta']['dernier_envoi_neuf'] :
135 \"'0000-00-00'\")";
136 $p->interdire_scripts = false;
137 return $p;
138 }
139
140 // http://doc.spip.org/@balise_DOSSIER_SQUELETTE_dist
141 function balise_DOSSIER_SQUELETTE_dist($p) {
142 $code = substr(addslashes(dirname($p->descr['sourcefile'])), strlen(_DIR_RACINE));
143 $p->code = "_DIR_RACINE . '$code'" .
144 $p->interdire_scripts = false;
145 return $p;
146 }
147
148 // http://doc.spip.org/@balise_SQUELETTE_dist
149 function balise_SQUELETTE_dist($p) {
150 $code = addslashes($p->descr['sourcefile']);
151 $p->code = "'$code'" .
152 $p->interdire_scripts = false;
153 return $p;
154 }
155
156 // http://doc.spip.org/@balise_SPIP_VERSION_dist
157 function balise_SPIP_VERSION_dist($p) {
158 $p->code = "spip_version()";
159 $p->interdire_scripts = false;
160 return $p;
161 }
162
163
164
165 /**
166 * Affiche le nom du site.
167 *
168 * Affiche le nom du site ou sinon l'URL ou le titre de l'objet
169 * Utiliser #NOM_SITE* pour avoir le nom du site ou rien.
170 *
171 * Cette balise interroge les colonnes 'nom_site' ou 'url_site'
172 * dans la boucle la plus proche.
173 *
174 * @example
175 * <code>
176 * <a href="#URL_SITE">#NOM_SITE</a>
177 * </code>
178 *
179 * @param Champ $p
180 * Pile au niveau de la balise
181 * @return Champ
182 * Pile complétée par le code à générer
183 **/
184 function balise_NOM_SITE_dist($p) {
185 if (!$p->etoile) {
186 $p->code = "supprimer_numero(calculer_url(" .
187 champ_sql('url_site',$p) ."," .
188 champ_sql('nom_site',$p) .
189 ", 'titre', \$connect, false))";
190 } else
191 $p->code = champ_sql('nom_site',$p);
192
193 $p->interdire_scripts = true;
194 return $p;
195 }
196
197 // http://doc.spip.org/@balise_NOTES_dist
198 function balise_NOTES_dist($p) {
199 // Recuperer les notes
200 $p->code = 'calculer_notes()';
201 #$p->interdire_scripts = true;
202 return $p;
203 }
204
205 // http://doc.spip.org/@balise_RECHERCHE_dist
206 function balise_RECHERCHE_dist($p) {
207 $p->code = 'entites_html(_request("recherche"))';
208 $p->interdire_scripts = false;
209 return $p;
210 }
211
212 // http://doc.spip.org/@balise_COMPTEUR_BOUCLE_dist
213 function balise_COMPTEUR_BOUCLE_dist($p) {
214 $b = $p->nom_boucle ? $p->nom_boucle : $p->descr['id_mere'];
215 if ($b === '') {
216 $msg = array('zbug_champ_hors_boucle',
217 array('champ' => '#COMPTEUR_BOUCLE')
218 );
219 erreur_squelette($msg, $p);
220 } else {
221 $p->code = "\$Numrows['$b']['compteur_boucle']";
222 $p->boucles[$b]->cptrows = true;
223 $p->interdire_scripts = false;
224 return $p;
225 }
226 }
227
228 // http://doc.spip.org/@balise_TOTAL_BOUCLE_dist
229 function balise_TOTAL_BOUCLE_dist($p) {
230 $b = $p->nom_boucle ? $p->nom_boucle : $p->descr['id_mere'];
231 if ($b === '' || !isset($p->boucles[$b])) {
232 $msg = array('zbug_champ_hors_boucle',
233 array('champ' => "#$b" . 'TOTAL_BOUCLE')
234 );
235 erreur_squelette($msg, $p);
236 } else {
237 $p->code = "\$Numrows['$b']['total']";
238 $p->boucles[$b]->numrows = true;
239 $p->interdire_scripts = false;
240 }
241 return $p;
242 }
243
244 // Si on est hors d'une boucle {recherche}, ne pas "prendre" cette balise
245 // http://doc.spip.org/@balise_POINTS_dist
246 function balise_POINTS_dist($p) {
247 return rindex_pile($p, 'points', 'recherche');
248 }
249
250 // http://doc.spip.org/@balise_POPULARITE_ABSOLUE_dist
251 function balise_POPULARITE_ABSOLUE_dist($p) {
252 $p->code = 'ceil(' .
253 champ_sql('popularite', $p) .
254 ')';
255 $p->interdire_scripts = false;
256 return $p;
257 }
258
259 // http://doc.spip.org/@balise_POPULARITE_SITE_dist
260 function balise_POPULARITE_SITE_dist($p) {
261 $p->code = 'ceil($GLOBALS["meta"][\'popularite_total\'])';
262 $p->interdire_scripts = false;
263 return $p;
264 }
265
266 // http://doc.spip.org/@balise_POPULARITE_MAX_dist
267 function balise_POPULARITE_MAX_dist($p) {
268 $p->code = 'ceil($GLOBALS["meta"][\'popularite_max\'])';
269 $p->interdire_scripts = false;
270 return $p;
271 }
272
273 // http://doc.spip.org/@balise_EXPOSE_dist
274 function balise_EXPOSE_dist($p) {
275 $on = "'on'";
276 $off= "''";
277 if (($v = interprete_argument_balise(1,$p))!==NULL){
278 $on = $v;
279 if (($v = interprete_argument_balise(2,$p))!==NULL)
280 $off = $v;
281
282 }
283 return calculer_balise_expose($p, $on, $off);
284 }
285
286 // #VALEUR renvoie le champ valeur
287 // #VALEUR{x} renvoie #VALEUR|table_valeur{x}
288 // #VALEUR{a/b} renvoie #VALEUR|table_valeur{a/b}
289 // http://doc.spip.org/@balise_VALEUR_dist
290 function balise_VALEUR_dist($p) {
291 $b = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
292 $p->code = index_pile($p->id_boucle, 'valeur', $p->boucles, $b);;
293 if (($v = interprete_argument_balise(1,$p))!==NULL){
294 $p->code = 'table_valeur('.$p->code.', '.$v.')';
295 }
296 $p->interdire_scripts = true;
297 return $p;
298 }
299
300 // http://doc.spip.org/@calculer_balise_expose
301 function calculer_balise_expose($p, $on, $off)
302 {
303 $b = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
304 $key = $p->boucles[$b]->primary;
305 $type = $p->boucles[$p->id_boucle]->primary;
306 $desc = $p->boucles[$b]->show;
307 $connect = sql_quote($p->boucles[$b]->sql_serveur);
308
309 if (!$key) {
310 $msg = array('zbug_champ_hors_boucle', array('champ' => '#EXPOSER'));
311 erreur_squelette($msg, $p);
312 }
313
314 // Ne pas utiliser champ_sql, on jongle avec le nom boucle explicite
315 $c = index_pile($p->id_boucle, $type, $p->boucles);
316
317 if (isset($desc['field']['id_parent'])) {
318 $parent = 0; // pour if (!$parent) dans calculer_expose
319 } elseif (isset($desc['field']['id_rubrique'])) {
320 $parent = index_pile($p->id_boucle, 'id_rubrique', $p->boucles, $b);
321 } elseif (isset($desc['field']['id_groupe'])) {
322 $parent = index_pile($p->id_boucle, 'id_groupe', $p->boucles, $b);
323 } else $parent = "''";
324
325 $p->code = "(calcul_exposer($c, '$type', \$Pile[0], $parent, '$key', $connect) ? $on : $off)";
326
327 $p->interdire_scripts = false;
328 return $p;
329 }
330
331
332 // Debut et fin de surlignage auto des mots de la recherche
333 // on insere une balise Span avec une classe sans spec:
334 // c'est transparent s'il n'y a pas de recherche,
335 // sinon elles seront remplacees par les fontions de inc_surligne
336
337 // http://doc.spip.org/@balise_DEBUT_SURLIGNE_dist
338 function balise_DEBUT_SURLIGNE_dist($p) {
339 include_spip('inc/surligne');
340 $p->code = "'<!-- " . MARQUEUR_SURLIGNE . " -->'";
341 return $p;
342 }
343 // http://doc.spip.org/@balise_FIN_SURLIGNE_dist
344 function balise_FIN_SURLIGNE_dist($p) {
345 include_spip('inc/surligne');
346 $p->code = "'<!-- " . MARQUEUR_FSURLIGNE . "-->'";
347 return $p;
348 }
349
350
351 // #INTRODUCTION
352 // #INTRODUCTION{longueur}
353 // http://www.spip.net/@introduction
354 // http://doc.spip.org/@balise_INTRODUCTION_dist
355 function balise_INTRODUCTION_dist($p) {
356
357 $type = $p->type_requete;
358
359 $_texte = champ_sql('texte', $p);
360 $_descriptif = ($type == 'articles' OR $type == 'rubriques') ? champ_sql('descriptif', $p) : "''";
361
362 if ($type == 'articles') {
363 $_chapo = champ_sql('chapo', $p);
364 $_texte = "(strlen($_descriptif))
365 ? ''
366 : $_chapo . \"\\n\\n\" . $_texte";
367 }
368
369 // longueur en parametre, ou valeur par defaut
370 if (($v = interprete_argument_balise(1,$p))!==NULL) {
371 $longueur = 'intval('.$v.')';
372 } else {
373 switch ($type) {
374 case 'articles':
375 $longueur = '500';
376 break;
377 case 'breves':
378 $longueur = '300';
379 break;
380 case 'rubriques':
381 default:
382 $longueur = '600';
383 break;
384 }
385 }
386
387 $f = chercher_filtre('introduction');
388 $p->code = "$f($_descriptif, $_texte, $longueur, \$connect)";
389
390 #$p->interdire_scripts = true;
391 $p->etoile = '*'; // propre est deja fait dans le calcul de l'intro
392 return $p;
393 }
394
395
396 // #LANG
397 // affiche la langue de l'objet (ou superieure), et a defaut la langue courante
398 // (celle du site ou celle qui a ete passee dans l'URL par le visiteur)
399 // #LANG* n'affiche rien si aucune langue n'est trouvee dans le sql/le contexte
400 // http://doc.spip.org/@balise_LANG_dist
401 function balise_LANG_dist ($p) {
402 $_lang = champ_sql('lang', $p);
403 if (!$p->etoile)
404 $p->code = "spip_htmlentities($_lang ? $_lang : \$GLOBALS['spip_lang'])";
405 else
406 $p->code = "spip_htmlentities($_lang)";
407 $p->interdire_scripts = false;
408 return $p;
409 }
410
411 // #LESAUTEURS
412 // les auteurs d'un objet
413 // http://www.spip.net/fr_article902.html
414 // http://www.spip.net/fr_article911.html
415 // http://doc.spip.org/@balise_LESAUTEURS_dist
416 function balise_LESAUTEURS_dist ($p) {
417 // Cherche le champ 'lesauteurs' dans la pile
418 $_lesauteurs = champ_sql('lesauteurs', $p, false);
419
420 // Si le champ n'existe pas (cas de spip_articles), on applique
421 // le modele lesauteurs.html en passant id_article dans le contexte;
422 // dans le cas contraire on prend le champ 'lesauteurs'
423 // (cf extension sites/)
424 if ($_lesauteurs
425 AND $_lesauteurs != '@$Pile[0][\'lesauteurs\']') {
426 $p->code = "safehtml($_lesauteurs)";
427 // $p->interdire_scripts = true;
428 } else {
429 if(!$p->id_boucle){
430 $connect = '';
431 $objet = 'article';
432 $id_table_objet = 'id_article';
433 }
434 else{
435 $b = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
436 $connect = $p->boucles[$b]->sql_serveur;
437 $type_boucle = $p->boucles[$b]->type_requete;
438 $objet = objet_type($type_boucle);
439 $id_table_objet = id_table_objet($type_boucle);
440 }
441 $c = memoriser_contexte_compil($p);
442
443 $p->code = sprintf(CODE_RECUPERER_FOND, "'modeles/lesauteurs'",
444 "array('objet'=>'".$objet.
445 "','id_objet' => ".champ_sql($id_table_objet, $p) .
446 ",'$id_table_objet' => ".champ_sql($id_table_objet, $p) .
447 ($objet=='article'?"":",'id_article' => ".champ_sql('id_article', $p)).
448 ")",
449 "'trim'=>true, 'compil'=>array($c)",
450 _q($connect));
451 $p->interdire_scripts = false; // securite apposee par recuperer_fond()
452 }
453
454 return $p;
455 }
456
457
458 /**
459 * #RANG
460 * affiche le "numero de l'objet" quand on l'a titre '1. Premier article';
461 * ceci est transitoire afin de preparer une migration vers un vrai systeme de
462 * tri des articles dans une rubrique (et plus si affinites)
463 * la balise permet d'extraire le numero masque par |supprimer_numero
464 * la balise recupere le champ declare dans la globale table_titre
465 * ou a defaut le champ 'titre'
466 *
467 * si un champ rang existe, il est pris en priorite
468 *
469 * http://doc.spip.org/@balise_RANG_dist
470 *
471 * @param object $p
472 * @return object
473 */
474 function balise_RANG_dist($p) {
475 $b = index_boucle($p);
476 if ($b === '') {
477 $msg = array(
478 'zbug_champ_hors_boucle',
479 array('champ' => '#RANG')
480 );
481 erreur_squelette($msg, $p);
482 } else {
483 // chercher d'abord un champ sql rang (mais pas dans le env : defaut '' si on trouve pas de champ sql)
484 // dans la boucle immediatement englobante uniquement
485 // sinon on compose le champ calcule
486 $_rang = champ_sql('rang', $p, '', false);
487
488 // si pas trouve de champ sql rang :
489 if (!$_rang) {
490 $boucle = &$p->boucles[$b];
491 $trouver_table = charger_fonction('trouver_table', 'base');
492 $desc = $trouver_table($boucle->id_table);
493 $_titre = ''; # où extraire le numero ?
494
495 if (isset($desc['titre'])) {
496 $t = $desc['titre'];
497 if (
498 // Soit on trouve avec la déclaration de la lang AVANT
499 preg_match(';(?:lang\s*,)\s*(.*?titre)\s*(,|$);', $t, $m)
500 // Soit on prend depuis le début
501 or preg_match(';^(.*?titre)\s*(,|$);', $t, $m)
502 ) {
503 $m = preg_replace(',as\s+titre$,i', '', $m[1]);
504 $m = trim($m);
505 if ($m != "''") {
506 if (!preg_match(",\W,", $m)) {
507 $m = $boucle->id_table . ".$m";
508 }
509
510 $m .= " AS titre_rang";
511
512 $boucle->select[] = $m;
513 $_titre = '$Pile[$SP][\'titre_rang\']';
514 }
515 }
516 }
517
518 // si on n'a rien trouvé, on utilise le champ titre classique
519 if (!$_titre) {
520 $_titre = champ_sql('titre', $p);
521 }
522
523 $_rang = "recuperer_numero($_titre)";
524 }
525
526 $p->code = $_rang;
527 $p->interdire_scripts = false;
528 }
529
530 return $p;
531 }
532
533
534 // #POPULARITE
535 // http://www.spip.net/fr_article1846.html
536 // http://doc.spip.org/@balise_POPULARITE_dist
537 function balise_POPULARITE_dist ($p) {
538 $_popularite = champ_sql('popularite', $p);
539 $p->code = "(ceil(min(100, 100 * $_popularite
540 / max(1 , 0 + \$GLOBALS['meta']['popularite_max']))))";
541 $p->interdire_scripts = false;
542 return $p;
543 }
544
545 // #PAGINATION
546 // Le code produit est trompeur, car les modeles ne fournissent pas Pile[0].
547 // On produit un appel a _request si on ne l'a pas, mais c'est inexact:
548 // l'absence peut etre due a une faute de frappe dans le contexte inclus.
549
550 define('CODE_PAGINATION',
551 '%s($Numrows["%s"]["grand_total"],
552 %s,
553 isset($Pile[0][%4$s])?$Pile[0][%4$s]:intval(_request(%4$s)),
554 %5$s, %6$s, %7$s, %8$s, array(%9$s))');
555
556 // http://www.spip.net/fr_article3367.html
557 // http://doc.spip.org/@balise_PAGINATION_dist
558 function balise_PAGINATION_dist($p, $liste='true') {
559 $b = $p->nom_boucle ? $p->nom_boucle : $p->descr['id_mere'];
560
561 // s'il n'y a pas de nom de boucle, on ne peut pas paginer
562 if ($b === '') {
563 $msg = array('zbug_champ_hors_boucle',
564 array('champ' => $liste ? 'PAGINATION' : 'ANCRE_PAGINATION')
565 );
566 erreur_squelette($msg, $p);
567 return $p;
568 }
569
570 // s'il n'y a pas de mode_partie, c'est qu'on se trouve
571 // dans un boucle recursive ou qu'on a oublie le critere {pagination}
572 if (!$p->boucles[$b]->mode_partie) {
573 if (!$p->boucles[$b]->table_optionnelle) {
574 $msg = array('zbug_pagination_sans_critere',
575 array('champ' => '#PAGINATION')
576 );
577 erreur_squelette($msg, $p);
578 }
579 return $p;
580 }
581
582 // a priori true
583 // si false, le compilo va bloquer sur des syntaxes avec un filtre sans argument qui suit la balise
584 // si true, les arguments simples (sans truc=chose) vont degager
585 $_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false, false);
586 if (count($_contexte)){
587 list($key,$val) = each($_contexte);
588 if (is_numeric($key)){
589 array_shift($_contexte);
590 $__modele = interprete_argument_balise(1,$p);
591 }
592 }
593
594 if (count($_contexte)){
595 $code_contexte = implode(',',$_contexte);
596 }
597 else
598 $code_contexte = '';
599
600 $connect = $p->boucles[$b]->sql_serveur;
601 $pas = $p->boucles[$b]->total_parties;
602 $f_pagination = chercher_filtre('pagination');
603 $type = $p->boucles[$b]->modificateur['debut_nom'];
604 $modif = ($type[0]!=="'") ? "'debut'.$type"
605 : ("'debut" .substr($type,1));
606
607 $p->code = sprintf(CODE_PAGINATION, $f_pagination, $b, $type, $modif, $pas, $liste, ((isset($__modele) and $__modele) ? $__modele : "''"), _q($connect), $code_contexte);
608
609 $p->boucles[$b]->numrows = true;
610 $p->interdire_scripts = false;
611 return $p;
612 }
613
614
615 // N'afficher que l'ancre de la pagination (au-dessus, par exemple, alors
616 // qu'on mettra les liens en-dessous de la liste paginee)
617 // http://doc.spip.org/@balise_ANCRE_PAGINATION_dist
618 function balise_ANCRE_PAGINATION_dist($p) {
619 if ($f = charger_fonction('PAGINATION', 'balise', true))
620 return $f($p, $liste='false');
621 else return NULL; // ou une erreur ?
622 }
623
624 // equivalent a #TOTAL_BOUCLE sauf pour les boucles paginees, ou elle
625 // indique le nombre total d'articles repondant aux criteres hors pagination
626 // http://doc.spip.org/@balise_GRAND_TOTAL_dist
627 function balise_GRAND_TOTAL_dist($p) {
628 $b = $p->nom_boucle ? $p->nom_boucle : $p->descr['id_mere'];
629 if ($b === '' || !isset($p->boucles[$b])) {
630 $msg = array('zbug_champ_hors_boucle',
631 array('champ' => "#$b" . 'TOTAL_BOUCLE')
632 );
633 erreur_squelette($msg, $p);
634 } else {
635 $p->code = "(isset(\$Numrows['$b']['grand_total'])
636 ? \$Numrows['$b']['grand_total'] : \$Numrows['$b']['total'])";
637 $p->boucles[$b]->numrows = true;
638 $p->interdire_scripts = false;
639 }
640 return $p;
641 }
642
643 // Reference a l'URL de la page courante
644 // Attention dans un INCLURE() ou une balise dynamique on n'a pas le droit de
645 // mettre en cache #SELF car il peut correspondre a une autre page (attaque XSS)
646 // (Dans ce cas faire <INCLURE{self=#SELF}> pour differencier les caches.)
647 // http://www.spip.net/@self
648 // http://doc.spip.org/@balise_SELF_dist
649 function balise_SELF_dist($p) {
650 $p->code = 'self()';
651 $p->interdire_scripts = false;
652 return $p;
653 }
654
655 //
656 // #CHEMIN{fichier} -> find_in_path(fichier)
657 //
658 // http://doc.spip.org/@balise_CHEMIN_dist
659 function balise_CHEMIN_dist($p) {
660 $arg = interprete_argument_balise(1,$p);
661 if (!$arg) {
662 $msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN'));
663 erreur_squelette($msg, $p);
664 } else
665 $p->code = 'find_in_path(' . $arg .')';
666
667 #$p->interdire_scripts = true;
668 return $p;
669 }
670
671 function balise_CHEMIN_IMAGE_dist($p) {
672 $arg = interprete_argument_balise(1,$p);
673 if (!$arg) {
674 $msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN_IMAGE'));
675 erreur_squelette($msg, $p);
676 } else $p->code = 'chemin_image(' . $arg .')';
677
678 #$p->interdire_scripts = true;
679 return $p;
680 }
681
682
683 /**
684 * La balise #ENV permet de recuperer
685 * le contexte d'environnement transmis au calcul d'un squelette,
686 * par exemple #ENV{id_rubrique}
687 *
688 * La syntaxe #ENV{toto, valeur par defaut}
689 * renverra 'valeur par defaut' si $toto est vide
690 *
691 * La recherche de la cle s'appuyant sur la fonction table_valeur
692 * il est possible de demander un sous element d'un tableau
693 * #ENV{toto/sous/element, valeur par defaut} retournera l'equivalent de
694 * #ENV{toto}|table_valeur{sous/element} c'est a dire en quelque sorte
695 * $env['toto']['sous']['element'] s'il existe, sinon la valeur par defaut.
696 *
697 * Si le tableau est vide on renvoie '' (utile pour #SESSION)
698 *
699 * Enfin, la balise utilisee seule #ENV retourne le tableau complet
700 * de l'environnement. A noter que ce tableau est retourne serialise.
701 *
702 *
703 * En standard est applique |entites_html, mais si l'etoile est
704 * utilisee pour desactiver les filtres par defaut, par exemple avec
705 * [(#ENV*{toto})] , il *faut* s'assurer de la securite
706 * anti-javascript, par exemple en filtrant avec |safehtml : [(#ENV*{toto}|safehtml)]
707 *
708 *
709 * @param Champ $p
710 * Pile ; arbre de syntaxe abstrait positionne au niveau de la balise.
711 *
712 * @param array $src
713 * Tableau dans lequel chercher la cle demandee en parametre de la balise.
714 * Par defaut prend dans le contexte du squelette.
715 *
716 * @return Champ $p
717 * Pile completee du code PHP d'execution de la balise
718 **/
719 function balise_ENV_dist($p, $src = NULL) {
720
721 // cle du tableau desiree
722 $_nom = interprete_argument_balise(1,$p);
723 // valeur par defaut
724 $_sinon = interprete_argument_balise(2,$p);
725
726 // $src est un tableau de donnees sources eventuellement transmis
727 // en absence, on utilise l'environnement du squelette $Pile[0]
728
729 if (!$_nom) {
730 // cas de #ENV sans argument : on retourne le serialize() du tableau
731 // une belle fonction [(#ENV|affiche_env)] serait pratique
732 if ($src) {
733 $p->code = '(is_array($a = ('.$src.')) ? serialize($a) : "")';
734 } else {
735 $p->code = '@serialize($Pile[0])';
736 }
737 } else {
738 if (!$src) {
739 $src = '@$Pile[0]';
740 }
741 if ($_sinon) {
742 $p->code = "sinon(table_valeur($src, (string)$_nom, null), $_sinon)";
743 } else {
744 $p->code = "table_valeur($src, (string)$_nom, null)";
745 }
746 }
747 #$p->interdire_scripts = true;
748
749 return $p;
750 }
751
752 /**
753 * #CONFIG retourne lire_config()
754 * les reglages du site
755 *
756 * Par exemple #CONFIG{gerer_trad} donne 'oui' ou 'non' selon le reglage
757 * Le 3eme argument permet de controler la serialisation du resultat
758 * (mais ne sert que pour le depot 'meta') qui doit parfois deserialiser
759 *
760 * ex: |in_array{#CONFIG{toto,#ARRAY,1}}.
761 *
762 * Ceci n'affecte pas d'autres depots et |in_array{#CONFIG{toto/,#ARRAY}} sera equivalent
763 * #CONFIG{/tablemeta/champ,defaut} lit la valeur de 'champ' dans la table des meta 'tablemeta'
764 *
765 * @param Object $p Arbre syntaxique du compilo
766 * @return Object
767 */
768 function balise_CONFIG_dist($p) {
769 if (!$arg = interprete_argument_balise(1,$p)) {
770 $arg = "''";
771 }
772 $_sinon = interprete_argument_balise(2,$p);
773 $_unserialize = sinon(interprete_argument_balise(3,$p),"false");
774
775 $p->code = '(include_spip(\'inc/config\')?lire_config(' . $arg . ',' .
776 ($_sinon && $_sinon != "''" ? $_sinon : 'null') . ',' . $_unserialize . "):'')";
777
778 return $p;
779 }
780
781
782 // http://doc.spip.org/@balise_CONNECT_dist
783 function balise_CONNECT_dist($p) {
784 $p->code = '($connect ? $connect : NULL)';
785 $p->interdire_scripts = false;
786 return $p;
787 }
788
789 //
790 // #SESSION
791 // Cette balise est un tableau des donnees du visiteur (nom, email etc)
792 // Si elle est invoquee, elle leve un drapeau dans le fichier cache, qui
793 // permet a public/cacher d'invalider le cache si le visiteur suivant n'a
794 // pas la meme session
795 // http://doc.spip.org/@balise_SESSION_dist
796 function balise_SESSION_dist($p) {
797 $p->descr['session'] = true;
798
799 $f = function_exists('balise_ENV')
800 ? 'balise_ENV'
801 : 'balise_ENV_dist';
802
803 $p = $f($p, '$GLOBALS["visiteur_session"]');
804 return $p;
805 }
806
807 //
808 // #SESSION_SET{x,y}
809 // Ajoute x=y dans la session du visiteur
810 // http://doc.spip.org/@balise_SESSION_SET_dist
811 function balise_SESSION_SET_dist($p) {
812 $_nom = interprete_argument_balise(1,$p);
813 $_val = interprete_argument_balise(2,$p);
814 if (!$_nom OR !$_val) {
815 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SESSION_SET'));
816 erreur_squelette($err_b_s_a, $p);
817 } else $p->code = '(include_spip("inc/session") AND session_set('.$_nom.','.$_val.'))';
818
819 $p->interdire_scripts = false;
820
821 return $p;
822 }
823
824
825
826
827 //
828 // #EVAL{...}
829 // evalue un code php ; a utiliser avec precaution :-)
830 //
831 // rq: #EVAL{code} produit eval('return code;')
832 // mais si le code est une expression sans balise, on se dispense
833 // de passer par une construction si compliquee, et le code est
834 // passe tel quel (entre parentheses, et protege par interdire_scripts)
835 // Exemples : #EVAL**{6+9} #EVAL**{_DIR_IMG_PACK} #EVAL{'date("Y-m-d")'}
836 // #EVAL{'str_replace("r","z", "roger")'} (attention les "'" sont interdits)
837 // http://doc.spip.org/@balise_EVAL_dist
838 function balise_EVAL_dist($p) {
839 $php = interprete_argument_balise(1,$p);
840 if ($php) {
841 # optimisation sur les #EVAL{une expression sans #BALISE}
842 # attention au commentaire "// x signes" qui precede
843 if (preg_match(",^([[:space:]]*//[^\n]*\n)'([^']+)'$,ms",
844 $php,$r))
845 $p->code = /* $r[1]. */'('.$r[2].')';
846 else
847 $p->code = "eval('return '.$php.';')";
848 } else {
849 $msg = array('zbug_balise_sans_argument', array('balise' => ' EVAL'));
850 erreur_squelette($msg, $p);
851 }
852
853 #$p->interdire_scripts = true;
854
855 return $p;
856 }
857
858 // #CHAMP_SQL{x} renvoie la valeur du champ sql 'x'
859 // permet de recuperer par exemple un champ notes dans une table sql externe
860 // (impossible via #NOTES qui est une balise calculee)
861 // ne permet pas de passer une expression pour x qui ne peut etre qu'un texte statique !
862 // http://doc.spip.org/@balise_CHAMP_SQL_dist
863 function balise_CHAMP_SQL_dist($p){
864
865 if ($p->param
866 AND isset($p->param[0][1][0])
867 AND $champ = ($p->param[0][1][0]->texte))
868 $p->code = champ_sql($champ, $p);
869 else {
870 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => ' CHAMP_SQL'));
871 erreur_squelette($err_b_s_a, $p);
872 }
873 #$p->interdire_scripts = true;
874 return $p;
875 }
876
877 // #VAL{x} renvoie 'x' (permet d'appliquer un filtre a une chaine)
878 // Attention #VAL{1,2} renvoie '1', indiquer #VAL{'1,2'}
879 // http://doc.spip.org/@balise_VAL_dist
880 function balise_VAL_dist($p){
881 $p->code = interprete_argument_balise(1,$p);
882 if (!strlen($p->code))
883 $p->code = "''";
884 $p->interdire_scripts = false;
885 return $p;
886 }
887 // #NOOP est un alias pour regler #948, ne pas documenter
888 // http://doc.spip.org/@balise_NOOP_dist
889 function balise_NOOP_dist($p) { return balise_VAL_dist($p); }
890
891 //
892 // #REM
893 // pour les remarques : renvoie toujours ''
894 //
895 // http://doc.spip.org/@balise_REM_dist
896 function balise_REM_dist($p) {
897 $p->code="''";
898 $p->interdire_scripts = false;
899 return $p;
900 }
901
902
903 //
904 // #HTTP_HEADER
905 // pour les entetes de retour http
906 // Ne fonctionne pas sur les INCLURE !
907 // #HTTP_HEADER{Content-Type: text/css}
908 //
909 // http://doc.spip.org/@balise_HTTP_HEADER_dist
910 function balise_HTTP_HEADER_dist($p) {
911
912 $header = interprete_argument_balise(1,$p);
913 if (!$header) {
914 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'HTTP_HEADER'));
915 erreur_squelette($err_b_s_a, $p);
916 } else $p->code = "'<'.'?php header(\"' . "
917 . $header
918 . " . '\"); ?'.'>'";
919 $p->interdire_scripts = false;
920 return $p;
921 }
922
923 // Filtre a appliquer a l'ensemble de la page une fois calculee
924 // (filtrage fait au niveau du squelette, et sans s'appliquer aux <INCLURE>)
925 // http://doc.spip.org/@balise_FILTRE_dist
926 function balise_FILTRE_dist($p) {
927 if ($p->param) {
928 $args = array();
929 foreach ($p->param as $i => $ignore)
930 $args[] = interprete_argument_balise($i+1,$p);
931 $p->code = "'<' . '"
932 .'?php header("X-Spip-Filtre: \'.'
933 .join('.\'|\'.', $args)
934 . " . '\"); ?'.'>'";
935
936 $p->interdire_scripts = false;
937 return $p;
938 }
939 }
940
941 //
942 // #CACHE
943 // definit la duree de vie ($delais) du squelette
944 // #CACHE{24*3600}
945 // parametre(s) supplementaire(s) :
946 // #CACHE{24*3600, cache-client} autorise gestion du IF_MODIFIED_SINCE
947 // #CACHE{24*3600, statique} ne respecte pas l'invalidation par modif de la base
948 // (mais s'invalide tout de meme a l'expiration du delai)
949 // par defaut cache-client => statique
950 // cf. ecrire/public/cacher.php
951 // http://doc.spip.org/@balise_CACHE_dist
952 function balise_CACHE_dist($p) {
953
954 if ($p->param) {
955 $duree = valeur_numerique($p->param[0][1][0]->texte);
956
957 // noter la duree du cache dans un entete proprietaire
958
959 $code = '\'<'.'?php header("X-Spip-Cache: '
960 . $duree
961 . '"); ?'.'>\'';
962
963 // Remplir le header Cache-Control
964 // cas #CACHE{0}
965 if ($duree == 0)
966 $code .= '.\'<'
967 .'?php header("Cache-Control: no-cache, must-revalidate"); ?'
968 .'><'
969 .'?php header("Pragma: no-cache"); ?'
970 .'>\'';
971
972 // recuperer les parametres suivants
973 $i = 1;
974 while (isset($p->param[0][++$i])) {
975 $pa = ($p->param[0][$i][0]->texte);
976
977 if ($pa == 'cache-client'
978 AND $duree > 0) {
979 $code .= '.\'<'.'?php header("Cache-Control: max-age='
980 . $duree
981 . '"); ?'.'>\'';
982 // il semble logique, si on cache-client, de ne pas invalider
983 $pa = 'statique';
984 }
985
986 if ($pa == 'statique'
987 AND $duree > 0)
988 $code .= '.\'<'.'?php header("X-Spip-Statique: oui"); ?'.'>\'';
989 }
990 } else $code = "''";
991 $p->code = $code;
992 $p->interdire_scripts = false;
993 return $p;
994 }
995
996
997 /**
998 * #INSERT_HEAD
999 * pour permettre aux plugins d'inserer des styles, js ou autre
1000 * dans l'entete sans modification du squelette
1001 * les css doivent etre inserees de preference par #INSERT_HEAD_CSS
1002 * pour en faciliter la surcharge
1003 *
1004 * on insere ici aussi un morceau de PHP qui verifiera a l'execution que le pipeline insert_head_css a bien ete vu
1005 * et dans le cas contraire l'appelera. Permet de ne pas oublier les css de #INSERT_HEAD_CSS meme si cette balise
1006 * n'est pas presente.
1007 * Il faut mettre ce php avant le insert_head car le compresseur y mets ensuite un php du meme type pour collecter
1008 * CSS et JS, et on ne veut pas qu'il rate les css inserees en fallback par insert_head_css_conditionnel
1009 *
1010 * http://doc.spip.org/@balise_INSERT_HEAD_dist
1011 *
1012 * @param object $p
1013 * @return object
1014 */
1015 function balise_INSERT_HEAD_dist($p) {
1016 $p->code = '\'<'
1017 .'?php header("X-Spip-Filtre: \'.'
1018 .'\'insert_head_css_conditionnel\''
1019 . " . '\"); ?'.'>'";
1020 $p->code .= ". pipeline('insert_head','<!-- insert_head -->')";
1021 $p->interdire_scripts = false;
1022 return $p;
1023 }
1024
1025 /**
1026 * homologue de #INSERT_HEAD pour les CSS
1027 * (et par extension pour le js inline qui doit preferentiellement etre insere avant les CSS car bloquant sinon)
1028 *
1029 * http://doc.spip.org/@balise_INSERT_HEAD_CSS_dist
1030 *
1031 * @param object $p
1032 * @return object
1033 */
1034 function balise_INSERT_HEAD_CSS_dist($p) {
1035 $p->code = "pipeline('insert_head_css','<!-- insert_head_css -->')";
1036 $p->interdire_scripts = false;
1037 return $p;
1038 }
1039 //
1040 // #INCLURE statique
1041 // l'inclusion est realisee au calcul du squelette, pas au service
1042 // ainsi le produit du squelette peut etre utilise en entree de filtres a suivre
1043 // on peut faire un #INCLURE{fichier} sans squelette
1044 // (Incompatible avec les balises dynamiques)
1045 // http://doc.spip.org/@balise_INCLUDE_dist
1046 function balise_INCLUDE_dist($p) {
1047 if(function_exists('balise_INCLURE'))
1048 return balise_INCLURE($p);
1049 else
1050 return balise_INCLURE_dist($p);
1051 }
1052 // http://doc.spip.org/@balise_INCLURE_dist
1053 function balise_INCLURE_dist($p) {
1054 $id_boucle = $p->id_boucle;
1055 // la lang n'est pas passe de facon automatique par argumenter
1056 // mais le sera pas recuperer_fond, sauf si etoile=>true est passe
1057 // en option
1058
1059 $_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $id_boucle, false, false);
1060
1061 // erreur de syntaxe = fond absent
1062 // (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
1063 if (!$_contexte) $contexte = array();
1064
1065 if (isset($_contexte['fond'])) {
1066
1067 $f = $_contexte['fond'];
1068 // toujours vrai :
1069 if (preg_match('/^.fond.\s*=>(.*)$/s', $f, $r)) {
1070 $f = $r[1];
1071 unset($_contexte['fond']);
1072 } else spip_log("compilation de #INCLURE a revoir");
1073
1074 // #INCLURE{doublons}
1075 if (isset($_contexte['doublons'])) {
1076 $_contexte['doublons'] = "'doublons' => \$doublons";
1077 }
1078
1079 // Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
1080 if (isset($_contexte['env'])
1081 || isset($_contexte['self'])
1082 ) {
1083 $flag_env = true;
1084 unset($_contexte['env']);
1085 } else $flag_env = false;
1086
1087 $_options = array();
1088 if (isset($_contexte['ajax'])) {
1089 $_options[] = preg_replace(",=>(.*)$,ims",'=> ($v=(\\1))?$v:true',$_contexte['ajax']);
1090 unset($_contexte['ajax']);
1091 }
1092 if ($p->etoile) $_options[] = "'etoile'=>true";
1093 $_options[] = "'compil'=>array(" . memoriser_contexte_compil($p) .")";
1094
1095 $_l = 'array(' . join(",\n\t", $_contexte) .')';
1096 if ($flag_env) $_l = "array_merge(\$Pile[0],$_l)";
1097
1098 $p->code = sprintf(CODE_RECUPERER_FOND, $f, $_l, join(',',$_options),"''");
1099
1100 } elseif (!isset($_contexte[1])) {
1101 $msg = array('zbug_balise_sans_argument', array('balise' => ' INCLURE'));
1102 erreur_squelette($msg, $p);
1103 } else $p->code = 'charge_scripts(' . $_contexte[1] . ',false)';
1104
1105 $p->interdire_scripts = false; // la securite est assuree par recuperer_fond
1106 return $p;
1107 }
1108
1109 // Inclure un modele : #MODELE{modele, params}
1110 // http://doc.spip.org/@balise_MODELE_dist
1111 function balise_MODELE_dist($p) {
1112
1113 $_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false);
1114
1115 // erreur de syntaxe = fond absent
1116 // (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
1117 if (!$_contexte) $contexte = array();
1118
1119 if (!isset($_contexte[1])) {
1120 $msg = array('zbug_balise_sans_argument', array('balise' => ' MODELE'));
1121 erreur_squelette($msg, $p);
1122 } else {
1123 $nom = $_contexte[1];
1124 unset($_contexte[1]);
1125
1126 if (preg_match("/^\s*'[^']*'/s", $nom))
1127 $nom = "'modeles/" . substr($nom,1);
1128 else $nom = "'modeles/' . $nom";
1129
1130 // Incoherence dans la syntaxe du contexte. A revoir.
1131 // Reserver la cle primaire de la boucle courante si elle existe
1132 if (isset($p->boucles[$p->id_boucle]->primary)) {
1133 $primary = $p->boucles[$p->id_boucle]->primary;
1134 if (!strpos($primary,',')) {
1135 $id = champ_sql($primary, $p);
1136 $_contexte[] = "'$primary'=>".$id;
1137 $_contexte[] = "'id'=>".$id;
1138 }
1139 }
1140 $_contexte[] = "'recurs'=>(++\$recurs)";
1141 $connect = '';
1142 if (isset($p->boucles[$p->id_boucle]))
1143 $connect = $p->boucles[$p->id_boucle]->sql_serveur;
1144
1145 $_options = memoriser_contexte_compil($p);
1146 $_options = "'compil'=>array($_options), 'trim'=>true";
1147 if (isset($_contexte['ajax'])){
1148 $_options .= ", ".preg_replace(",=>(.*)$,ims",'=> ($v=(\\1))?$v:true',$_contexte['ajax']);
1149 unset($_contexte['ajax']);
1150 }
1151
1152 $page = sprintf(CODE_RECUPERER_FOND, $nom, 'array(' . join(',', $_contexte) .')', $_options, _q($connect));
1153
1154 $p->code = "\n\t(((\$recurs=(isset(\$Pile[0]['recurs'])?\$Pile[0]['recurs']:0))>=5)? '' :\n\t$page)\n";
1155
1156 $p->interdire_scripts = false; // securite assuree par le squelette
1157 }
1158
1159 return $p;
1160 }
1161
1162 //
1163 // #SET
1164 // Affecte une variable locale au squelette
1165 // #SET{nom,valeur}
1166 // la balise renvoie la valeur
1167 // http://doc.spip.org/@balise_SET_dist
1168 function balise_SET_dist($p){
1169 $_nom = interprete_argument_balise(1,$p);
1170 $_val = interprete_argument_balise(2,$p);
1171
1172 if (!$_nom OR !$_val) {
1173 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SET'));
1174 erreur_squelette($err_b_s_a, $p);
1175 }
1176 // affectation $_zzz inutile, mais permet de contourner un bug OpCode cache sous PHP 5.5.4
1177 // cf https://bugs.php.net/bug.php?id=65845
1178 else $p->code = "vide(\$Pile['vars'][\$_zzz=(string)$_nom] = $_val)";
1179
1180 $p->interdire_scripts = false; // la balise ne renvoie rien
1181 return $p;
1182 }
1183
1184 //
1185 // #GET
1186 // Recupere une variable locale au squelette
1187 // #GET{nom,defaut} renvoie defaut si la variable nom n'a pas ete affectee
1188 //
1189 // http://doc.spip.org/@balise_GET_dist
1190 function balise_GET_dist($p) {
1191 $p->interdire_scripts = false; // le contenu vient de #SET, donc il est de confiance
1192 if (function_exists('balise_ENV'))
1193 return balise_ENV($p, '$Pile["vars"]');
1194 else
1195 return balise_ENV_dist($p, '$Pile["vars"]');
1196 }
1197
1198
1199 /**
1200 * Compile la balise #DOUBLONS
1201 *
1202 * #DOUBLONS{mots} ou #DOUBLONS{mots,famille}
1203 * donne l'etat des doublons (MOTS) a cet endroit
1204 * sous forme de tableau d'id_mot array(1,2,3,...)
1205 * #DOUBLONS tout seul donne la liste brute de tous les doublons
1206 * #DOUBLONS*{mots} donne la chaine brute ",1,2,3,..."
1207 * (changera si la gestion des doublons evolue)
1208 *
1209 * @param Champ $p
1210 * Pile au niveau de la balise
1211 * @return Champ
1212 * Pile complétée par le code à générer
1213 **/
1214 function balise_DOUBLONS_dist($p) {
1215 if ($type = interprete_argument_balise(1,$p)) {
1216 if ($famille = interprete_argument_balise(2,$p))
1217 $type .= '.' . $famille;
1218 $p->code = '$doublons['.$type.']';
1219 if (!$p->etoile)
1220 $p->code = 'array_filter(array_map("intval",explode(",",'
1221 . $p->code . ')))';
1222 }
1223 else
1224 $p->code = '$doublons';
1225
1226 $p->interdire_scripts = false;
1227
1228 return $p;
1229 }
1230
1231
1232 //
1233 // #PIPELINE
1234 // pour permettre aux plugins d'inserer des sorties de pipeline dans un squelette
1235 // #PIPELINE{insert_body}
1236 // #PIPELINE{insert_body,flux}
1237 //
1238 // http://doc.spip.org/@balise_PIPELINE_dist
1239 function balise_PIPELINE_dist($p) {
1240 $_pipe = interprete_argument_balise(1,$p);
1241 if (!$_pipe) {
1242 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'PIPELINE'));
1243 erreur_squelette($err_b_s_a, $p);
1244 } else {
1245 $_flux = interprete_argument_balise(2,$p);
1246 $_flux = $_flux?$_flux:"''";
1247 $p->code = "pipeline( $_pipe , $_flux )";
1248 $p->interdire_scripts = false;
1249 }
1250 return $p;
1251 }
1252
1253 //
1254 // #EDIT
1255 // une balise qui ne fait rien, pour surcharge par le plugin widgets
1256 //
1257 // http://doc.spip.org/@balise_EDIT_dist
1258 function balise_EDIT_dist($p) {
1259 $p->code = "''";
1260 $p->interdire_scripts = false;
1261 return $p;
1262 }
1263
1264
1265 //
1266 // #TOTAL_UNIQUE
1267 // pour recuperer le nombre d'elements affiches par l'intermediaire du filtre
1268 // |unique
1269 // usage:
1270 // #TOTAL_UNIQUE afiche le nombre de #BALISE|unique
1271 // #TOTAL_UNIQUE{famille} afiche le nombre de #BALISE|unique{famille}
1272 //
1273 // http://doc.spip.org/@balise_TOTAL_UNIQUE_dist
1274 function balise_TOTAL_UNIQUE_dist($p) {
1275 $_famille = interprete_argument_balise(1,$p);
1276 $_famille = $_famille ? $_famille : "''";
1277 $p->code = "unique('', $_famille, true)";
1278 return $p;
1279 }
1280
1281 //
1282 // #ARRAY
1283 // pour creer un array php a partir d'arguments calcules
1284 // #ARRAY{key1,val1,key2,val2 ...} retourne array(key1=>val1,...)
1285 //
1286 // http://doc.spip.org/@balise_ARRAY_dist
1287 function balise_ARRAY_dist($p) {
1288 $_code = array();
1289 $n=1;
1290 do {
1291 $_key = interprete_argument_balise($n++,$p);
1292 $_val = interprete_argument_balise($n++,$p);
1293 if ($_key AND $_val) $_code[] = "$_key => $_val";
1294 } while ($_key && $_val);
1295 $p->code = 'array(' . join(', ',$_code).')';
1296 $p->interdire_scripts = false;
1297 return $p;
1298 }
1299
1300 /**
1301 * #LISTE{a,b,c,d,e} cree un array avec les valeurs, sans preciser les cles
1302 *
1303 * @param <type> $p
1304 * @return <type>
1305 */
1306 function balise_LISTE_dist($p) {
1307 $_code = array();
1308 $n=1;
1309 while ($_val = interprete_argument_balise($n++,$p))
1310 $_code[] = $_val;
1311 $p->code = 'array(' . join(', ',$_code).')';
1312 $p->interdire_scripts = false;
1313 return $p;
1314 }
1315
1316 // Appelle la fonction autoriser et renvoie ' ' si OK, '' si niet
1317 // A noter : la priorite des operateurs exige && plutot que AND
1318 // Cette balise cree un cache par session
1319 // http://doc.spip.org/@balise_AUTORISER_dist
1320 function balise_AUTORISER_dist($p) {
1321 $_code = array();
1322 $p->descr['session'] = true; // faire un cache par session
1323
1324 $n=1;
1325 while ($_v = interprete_argument_balise($n++,$p))
1326 $_code[] = $_v;
1327
1328 $p->code = '((function_exists("autoriser")||include_spip("inc/autoriser"))&&autoriser(' . join(', ',$_code).')?" ":"")';
1329 $p->interdire_scripts = false;
1330 return $p;
1331 }
1332
1333 // Appelle la fonction info_plugin
1334 // Afficher des informations sur les plugins dans le site public
1335 // http://doc.spip.org/@balise_PLUGIN_dist
1336 function balise_PLUGIN_dist($p) {
1337 $plugin = interprete_argument_balise(1,$p);
1338 $plugin = isset($plugin) ? str_replace('\'', '"', $plugin) : '""';
1339 $type_info = interprete_argument_balise(2,$p);
1340 $type_info = isset($type_info) ? str_replace('\'', '"', $type_info) : '"est_actif"';
1341
1342 $f = chercher_filtre('info_plugin');
1343 $p->code = $f.'('.$plugin.', '.$type_info.')';
1344 return $p;
1345 }
1346
1347 // Appelle la fonction inc_aider_dist
1348 // http://doc.spip.org/@balise_AIDER_dist
1349 function balise_AIDER_dist($p) {
1350 $_motif = interprete_argument_balise(1,$p);
1351 $s = "'" . addslashes($p->descr['sourcefile']) . "'";
1352 $aider = charger_fonction('aider','inc');
1353 $p->code = "((\$aider=charger_fonction('aider','inc'))?\$aider($_motif,$s, \$Pile[0]):'')";
1354 return $p;
1355 }
1356
1357 // Insertion du contexte des formulaires charger/verifier/traiter
1358 // avec les hidden de l'url d'action
1359 // http://doc.spip.org/@balise_ACTION_FORMULAIRE
1360 function balise_ACTION_FORMULAIRE($p){
1361 if (!$_url = interprete_argument_balise(1,$p))
1362 $_url = "@\$Pile[0]['action']";
1363 if (!$_form = interprete_argument_balise(2,$p))
1364 $_form = "@\$Pile[0]['form']";
1365
1366 // envoyer le nom du formulaire que l'on traite
1367 // transmettre les eventuels args de la balise formulaire
1368 $p->code = " '<div>' .
1369 form_hidden($_url) .
1370 '<input name=\'formulaire_action\' type=\'hidden\'
1371 value=\'' . $_form . '\' />' .
1372 '<input name=\'formulaire_action_args\' type=\'hidden\'
1373 value=\'' . @\$Pile[0]['formulaire_args']. '\' />' .
1374 (@\$Pile[0]['_hidden']?@\$Pile[0]['_hidden']:'') .
1375 '</div>'";
1376
1377 $p->interdire_scripts = false;
1378 return $p;
1379 }
1380
1381
1382 /**
1383 * Generer un bouton d'action en post, ajaxable
1384 * a utiliser a la place des liens action_auteur, sous la forme
1385 * #BOUTON_ACTION{libelle,url}
1386 * ou
1387 * #BOUTON_ACTION{libelle,url,ajax} pour que l'action soit ajax comme un lien class='ajax'
1388 * ou
1389 * #BOUTON_ACTION{libelle,url,ajax,message_confirmation} pour utiliser un message de confirmation
1390 *
1391 * #BOUTON_ACTION{libelle[,url[,ajax[,message_confirmation[,title[,callback]]]]]}
1392 *
1393 * @param unknown_type $p
1394 * @return unknown
1395 */
1396 function balise_BOUTON_ACTION_dist($p){
1397
1398 $args = array();
1399 for ($k=1;$k<=6;$k++){
1400 $_a = interprete_argument_balise($k,$p);
1401 if (!$_a) $_a="''";
1402 $args[] = $_a;
1403 }
1404 // supprimer les args vides
1405 while(end($args)=="''" AND count($args)>2)
1406 array_pop($args);
1407 $args = implode(",",$args);
1408
1409 $bouton_action = chercher_filtre("bouton_action");
1410 $p->code = "$bouton_action($args)";
1411 $p->interdire_scripts = false;
1412 return $p;
1413 }
1414
1415
1416
1417 function balise_SLOGAN_SITE_SPIP_dist($p) {
1418 $p->code = "\$GLOBALS['meta']['slogan_site']";
1419 #$p->interdire_scripts = true;
1420 return $p;
1421 }
1422
1423 // #HTML5
1424 // Renvoie ' ' si le webmestre souhaite que SPIP genere du code (X)HTML5 sur
1425 // le site public, et '' si le code doit etre strictement compatible HTML4
1426 // http://doc.spip.org/@balise_HTML5_dist
1427 function balise_HTML5_dist($p) {
1428 $p->code = html5_permis() ? "' '" : "''";
1429 $p->interdire_scripts = false;
1430 return $p;
1431 }
1432
1433
1434
1435 /**
1436 * #TRI{champ[,libelle]}
1437 * champ prend > ou < pour afficher le lien de changement de sens
1438 * croissant ou decroissant (> < indiquent un sens par une fleche)
1439 *
1440 * @param unknown_type $p
1441 * @param unknown_type $liste
1442 * @return unknown
1443 */
1444 function balise_TRI_dist($p, $liste='true') {
1445 $b = $p->nom_boucle ? $p->nom_boucle : $p->descr['id_mere'];
1446
1447 // s'il n'y a pas de nom de boucle, on ne peut pas trier
1448 if ($b === '') {
1449 erreur_squelette(
1450 _T('zbug_champ_hors_boucle',
1451 array('champ' => '#TRI')
1452 ), $p->id_boucle);
1453 $p->code = "''";
1454 return $p;
1455 }
1456 $boucle = $p->boucles[$b];
1457
1458 // s'il n'y a pas de tri_champ, c'est qu'on se trouve
1459 // dans un boucle recursive ou qu'on a oublie le critere {tri}
1460 if (!isset($boucle->modificateur['tri_champ'])) {
1461 erreur_squelette(
1462 _T('zbug_tri_sans_critere',
1463 array('champ' => '#TRI')
1464 ), $p->id_boucle);
1465 $p->code = "''";
1466 return $p;
1467 }
1468
1469 $_champ = interprete_argument_balise(1,$p);
1470 // si pas de champ, renvoyer le critere de tri utilise
1471 if (!$_champ){
1472 $p->code = $boucle->modificateur['tri_champ'];
1473 return $p;
1474 }
1475 // forcer la jointure si besoin, et si le champ est statique
1476 if (preg_match(",^'([\w.]+)'$,i",$_champ,$m)){
1477 index_pile($b, $m[1], $p->boucles);
1478 }
1479
1480 $_libelle = interprete_argument_balise(2,$p);
1481 $_libelle = $_libelle?$_libelle:$_champ;
1482
1483 $_class = interprete_argument_balise(3,$p);
1484 // si champ = ">" c'est un lien vers le tri croissant : de gauche a droite ==> 1
1485 // si champ = "<" c'est un lien vers le tri decroissant : (sens inverse) == -1
1486 $_issens = "in_array($_champ,array('>','<'))";
1487 $_sens = "(strpos('< >',$_champ)-1)";
1488
1489 $_variable = "((\$s=$_issens)?'sens':'tri').".$boucle->modificateur['tri_nom'];
1490 $_url = "parametre_url(self(),$_variable,\$s?$_sens:$_champ)";
1491 $_on = "\$s?(".$boucle->modificateur['tri_sens']."==$_sens".'):('.$boucle->modificateur['tri_champ']."==$_champ)";
1492
1493 $p->code = "lien_ou_expose($_url,$_libelle,$_on".($_class?",$_class":"").")";
1494 //$p->code = "''";
1495 $p->interdire_scripts = false;
1496 return $p;
1497 }
1498
1499
1500 /**
1501 * #SAUTER{n} permet de sauter en avant n resultats dans une boucle
1502 * La balise modifie le compteur courant de la boucle, mais pas les autres
1503 * champs qui restent les valeurs de la boucle avant le saut. Il est donc
1504 * preferable d'utiliser la balise juste avant la fermeture </BOUCLE>
1505 *
1506 * L'argument n doit etre superieur a zero sinon la balise ne fait rien
1507 *
1508 * @param <type> $p
1509 * @return <type>
1510 */
1511 function balise_SAUTER_dist($p){
1512 $id_boucle = $p->id_boucle;
1513 $boucle = $p->boucles[$id_boucle];
1514
1515 if (!$boucle) {
1516 $msg = array('zbug_champ_hors_boucle', array('champ' => '#SAUTER'));
1517 erreur_squelette($msg, $p);
1518 }
1519 else {
1520 $_saut = interprete_argument_balise(1,$p);
1521 $_compteur = "\$Numrows['$id_boucle']['compteur_boucle']";
1522 $_total = "\$Numrows['$id_boucle']['total']";
1523
1524 $p->code = "vide($_compteur=\$iter->skip($_saut,$_total))";
1525 }
1526 $p->interdire_scripts = false;
1527 return $p;
1528 }
1529
1530
1531 /**
1532 * Savoir si on objet est publie ou non
1533 *
1534 * @param <type> $p
1535 * @return <type>
1536 */
1537 function balise_PUBLIE_dist($p) {
1538 if (!$_type = interprete_argument_balise(1,$p)){
1539 $_type = _q($p->type_requete);
1540 $_id = champ_sql($p->boucles[$p->id_boucle]->primary,$p);
1541 }
1542 else
1543 $_id = interprete_argument_balise(2,$p);
1544
1545 $connect = $p->boucles[$p->id_boucle]->sql_serveur;
1546
1547 $p->code = "(objet_test_si_publie(".$_type.",intval(".$_id."),"._q($connect).")?' ':'')";
1548 $p->interdire_scripts = false;
1549 return $p;
1550 }
1551
1552 /**
1553 * #PRODUIRE
1554 * generer un fichier statique a partir d'un squelette SPIP
1555 *
1556 * Le format du fichier sera extrait de la preextension du squelette (typo.css.html, messcripts.js.html)
1557 * ou par l'argument format=css ou format=js passe en argument.
1558 *
1559 * Si pas de format detectable, on utilise .html, comme pour les squelettes
1560 *
1561 * <link rel="stylesheet" type="text/css" href="#PRODUIRE{fond=css/macss.css,couleur=ffffff}" />
1562 * la syntaxe de la balise est la meme que celle de #INCLURE
1563 *
1564 * @param object $p
1565 * @return object
1566 */
1567 function balise_PRODUIRE_dist($p){
1568 $balise_inclure = charger_fonction('INCLURE','balise');
1569 $p = $balise_inclure($p);
1570
1571 $p->code = str_replace('recuperer_fond(','produire_fond_statique(',$p->code);
1572
1573 return $p;
1574 }
1575
1576 /**
1577 * Definir la largeur d'ecran dans l'espace prive
1578 * #LARGEUR_ECRAN{pleine_largeur}
1579 *
1580 * @param $p
1581 * @return
1582 */
1583 function balise_LARGEUR_ECRAN_dist($p){
1584 $_class = interprete_argument_balise(1,$p);
1585 if (!$_class) $_class='null';
1586 $p->code = "(is_string($_class)?vide(\$GLOBALS['largeur_ecran']=$_class):(isset(\$GLOBALS['largeur_ecran'])?\$GLOBALS['largeur_ecran']:''))";
1587 return $p;
1588 }
1589 ?>