9d01d219454853a73ea713c90cc431ca4b27d379
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2014 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
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 \***************************************************************************/
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
17 // elle recoit en entree un objet de classe CHAMP, le modifie et le retourne.
18 // Cette classe est definie dans public/interfaces
20 if (!defined('_ECRIRE_INC_VERSION')) return;
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],
33 // Definition des balises
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;
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;
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;
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;
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;
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;
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;
87 // http://doc.spip.org/@balise_PUCE_dist
88 function balise_PUCE_dist($p) {
89 $p->code
= "definir_puce()";
90 $p->interdire_scripts
= false;
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()";
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()";
115 $p->interdire_scripts
= false;
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;
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'] :
136 $p->interdire_scripts
= false;
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;
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;
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;
166 * Affiche le nom du site.
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.
171 * Cette balise interroge les colonnes 'nom_site' ou 'url_site'
172 * dans la boucle la plus proche.
176 * <a href="#URL_SITE">#NOM_SITE</a>
180 * Pile au niveau de la balise
182 * Pile complétée par le code à générer
184 function balise_NOM_SITE_dist($p) {
186 $p->code
= "supprimer_numero(calculer_url(" .
187 champ_sql('url_site',$p) ."," .
188 champ_sql('nom_site',$p) .
189 ", 'titre', \$connect, false))";
191 $p->code
= champ_sql('nom_site',$p);
193 $p->interdire_scripts
= true;
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;
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;
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'];
216 $msg = array('zbug_champ_hors_boucle',
217 array('champ' => '#COMPTEUR_BOUCLE')
219 erreur_squelette($msg, $p);
221 $p->code
= "\$Numrows['$b']['compteur_boucle']";
222 $p->boucles
[$b]->cptrows
= true;
223 $p->interdire_scripts
= false;
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')
235 erreur_squelette($msg, $p);
237 $p->code
= "\$Numrows['$b']['total']";
238 $p->boucles
[$b]->numrows
= true;
239 $p->interdire_scripts
= false;
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');
250 // http://doc.spip.org/@balise_POPULARITE_ABSOLUE_dist
251 function balise_POPULARITE_ABSOLUE_dist($p) {
253 champ_sql('popularite', $p) .
255 $p->interdire_scripts
= false;
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;
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;
273 // http://doc.spip.org/@balise_EXPOSE_dist
274 function balise_EXPOSE_dist($p) {
277 if (($v = interprete_argument_balise(1,$p))!==NULL){
279 if (($v = interprete_argument_balise(2,$p))!==NULL)
283 return calculer_balise_expose($p, $on, $off);
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.')';
296 $p->interdire_scripts
= true;
300 // http://doc.spip.org/@calculer_balise_expose
301 function calculer_balise_expose($p, $on, $off)
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
);
310 $msg = array('zbug_champ_hors_boucle', array('champ' => '#EXPOSER'));
311 erreur_squelette($msg, $p);
314 // Ne pas utiliser champ_sql, on jongle avec le nom boucle explicite
315 $c = index_pile($p->id_boucle
, $type, $p->boucles
);
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 = "''";
325 $p->code
= "(calcul_exposer($c, '$type', \$Pile[0], $parent, '$key', $connect) ? $on : $off)";
327 $p->interdire_scripts
= false;
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
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
. " -->'";
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
. "-->'";
352 // #INTRODUCTION{longueur}
353 // http://www.spip.net/@introduction
354 // http://doc.spip.org/@balise_INTRODUCTION_dist
355 function balise_INTRODUCTION_dist($p) {
357 $type = $p->type_requete
;
359 $_texte = champ_sql('texte', $p);
360 $_descriptif = ($type == 'articles' OR $type == 'rubriques') ?
champ_sql('descriptif', $p) : "''";
362 if ($type == 'articles') {
363 $_chapo = champ_sql('chapo', $p);
364 $_texte = "(strlen($_descriptif))
366 : $_chapo . \"\\n\\n\" . $_texte";
369 // longueur en parametre, ou valeur par defaut
370 if (($v = interprete_argument_balise(1,$p))!==NULL) {
371 $longueur = 'intval('.$v.')';
387 $f = chercher_filtre('introduction');
388 $p->code
= "$f($_descriptif, $_texte, $longueur, \$connect)";
390 #$p->interdire_scripts = true;
391 $p->etoile
= '*'; // propre est deja fait dans le calcul de l'intro
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);
404 $p->code
= "spip_htmlentities($_lang ? $_lang : \$GLOBALS['spip_lang'])";
406 $p->code
= "spip_htmlentities($_lang)";
407 $p->interdire_scripts
= false;
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);
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/)
425 AND $_lesauteurs != '@$Pile[0][\'lesauteurs\']') {
426 $p->code
= "safehtml($_lesauteurs)";
427 // $p->interdire_scripts = true;
432 $id_table_objet = 'id_article';
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);
441 $c = memoriser_contexte_compil($p);
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)).
449 "'trim'=>true, 'compil'=>array($c)",
451 $p->interdire_scripts
= false; // securite apposee par recuperer_fond()
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'
467 * si un champ rang existe, il est pris en priorite
469 * http://doc.spip.org/@balise_RANG_dist
474 function balise_RANG_dist($p) {
475 $b = index_boucle($p);
477 $msg = array('zbug_champ_hors_boucle',
478 array('champ' => '#RANG')
480 erreur_squelette($msg, $p);
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);
488 // si pas trouve de champ sql rang :
490 $boucle = &$p->boucles
[$b];
491 $trouver_table = charger_fonction('trouver_table','base');
492 $desc = $trouver_table($boucle->id_table
);
493 $_titre = ''; # champ dont on extrait le numero
494 if (isset($desc['titre'])){
496 if (preg_match(';(^|,)([^,]*titre)(,|$);',$t,$m)){
497 $m = preg_replace(",as\s+titre$,i","",$m[2]);
500 if (!preg_match(",\W,",$m))
501 $m = $boucle->id_table
. ".$m";
502 $m .= " AS titre_rang";
504 $boucle->select
[] = $m;
505 $_titre = '$Pile[$SP][\'titre_rang\']';
510 $_titre = champ_sql('titre', $p);
511 $_rang = "recuperer_numero($_titre)";
514 $p->interdire_scripts
= false;
521 // http://www.spip.net/fr_article1846.html
522 // http://doc.spip.org/@balise_POPULARITE_dist
523 function balise_POPULARITE_dist ($p) {
524 $_popularite = champ_sql('popularite', $p);
525 $p->code
= "(ceil(min(100, 100 * $_popularite
526 / max(1 , 0 + \$GLOBALS['meta']['popularite_max']))))";
527 $p->interdire_scripts
= false;
532 // Le code produit est trompeur, car les modeles ne fournissent pas Pile[0].
533 // On produit un appel a _request si on ne l'a pas, mais c'est inexact:
534 // l'absence peut etre due a une faute de frappe dans le contexte inclus.
536 define('CODE_PAGINATION',
537 '%s($Numrows["%s"]["grand_total"],
539 isset($Pile[0][%4$s])?$Pile[0][%4$s]:intval(_request(%4$s)),
540 %5$s, %6$s, %7$s, %8$s, array(%9$s))');
542 // http://www.spip.net/fr_article3367.html
543 // http://doc.spip.org/@balise_PAGINATION_dist
544 function balise_PAGINATION_dist($p, $liste='true') {
545 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->descr
['id_mere'];
547 // s'il n'y a pas de nom de boucle, on ne peut pas paginer
549 $msg = array('zbug_champ_hors_boucle',
550 array('champ' => $liste ?
'PAGINATION' : 'ANCRE_PAGINATION')
552 erreur_squelette($msg, $p);
556 // s'il n'y a pas de mode_partie, c'est qu'on se trouve
557 // dans un boucle recursive ou qu'on a oublie le critere {pagination}
558 if (!$p->boucles
[$b]->mode_partie
) {
559 if (!$p->boucles
[$b]->table_optionnelle
) {
560 $msg = array('zbug_pagination_sans_critere',
561 array('champ' => '#PAGINATION')
563 erreur_squelette($msg, $p);
569 // si false, le compilo va bloquer sur des syntaxes avec un filtre sans argument qui suit la balise
570 // si true, les arguments simples (sans truc=chose) vont degager
571 $_contexte = argumenter_inclure($p->param
, true, $p, $p->boucles
, $p->id_boucle
, false, false);
572 if (count($_contexte)){
573 list($key,$val) = each($_contexte);
574 if (is_numeric($key)){
575 array_shift($_contexte);
576 $__modele = interprete_argument_balise(1,$p);
580 if (count($_contexte)){
581 $code_contexte = implode(',',$_contexte);
586 $connect = $p->boucles
[$b]->sql_serveur
;
587 $pas = $p->boucles
[$b]->total_parties
;
588 $f_pagination = chercher_filtre('pagination');
589 $type = $p->boucles
[$b]->modificateur
['debut_nom'];
590 $modif = ($type[0]!=="'") ?
"'debut'.$type"
591 : ("'debut" .substr($type,1));
593 $p->code
= sprintf(CODE_PAGINATION
, $f_pagination, $b, $type, $modif, $pas, $liste, ((isset($__modele) and $__modele) ?
$__modele : "''"), _q($connect), $code_contexte);
595 $p->boucles
[$b]->numrows
= true;
596 $p->interdire_scripts
= false;
601 // N'afficher que l'ancre de la pagination (au-dessus, par exemple, alors
602 // qu'on mettra les liens en-dessous de la liste paginee)
603 // http://doc.spip.org/@balise_ANCRE_PAGINATION_dist
604 function balise_ANCRE_PAGINATION_dist($p) {
605 if ($f = charger_fonction('PAGINATION', 'balise', true))
606 return $f($p, $liste='false');
607 else return NULL; // ou une erreur ?
610 // equivalent a #TOTAL_BOUCLE sauf pour les boucles paginees, ou elle
611 // indique le nombre total d'articles repondant aux criteres hors pagination
612 // http://doc.spip.org/@balise_GRAND_TOTAL_dist
613 function balise_GRAND_TOTAL_dist($p) {
614 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->descr
['id_mere'];
615 if ($b === '' ||
!isset($p->boucles
[$b])) {
616 $msg = array('zbug_champ_hors_boucle',
617 array('champ' => "#$b" . 'TOTAL_BOUCLE')
619 erreur_squelette($msg, $p);
621 $p->code
= "(isset(\$Numrows['$b']['grand_total'])
622 ? \$Numrows['$b']['grand_total'] : \$Numrows['$b']['total'])";
623 $p->boucles
[$b]->numrows
= true;
624 $p->interdire_scripts
= false;
629 // Reference a l'URL de la page courante
630 // Attention dans un INCLURE() ou une balise dynamique on n'a pas le droit de
631 // mettre en cache #SELF car il peut correspondre a une autre page (attaque XSS)
632 // (Dans ce cas faire <INCLURE{self=#SELF}> pour differencier les caches.)
633 // http://www.spip.net/@self
634 // http://doc.spip.org/@balise_SELF_dist
635 function balise_SELF_dist($p) {
637 $p->interdire_scripts
= false;
642 // #CHEMIN{fichier} -> find_in_path(fichier)
644 // http://doc.spip.org/@balise_CHEMIN_dist
645 function balise_CHEMIN_dist($p) {
646 $arg = interprete_argument_balise(1,$p);
648 $msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN'));
649 erreur_squelette($msg, $p);
651 $p->code
= 'find_in_path(' . $arg .')';
653 #$p->interdire_scripts = true;
657 function balise_CHEMIN_IMAGE_dist($p) {
658 $arg = interprete_argument_balise(1,$p);
660 $msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN_IMAGE'));
661 erreur_squelette($msg, $p);
662 } else $p->code
= 'chemin_image(' . $arg .')';
664 #$p->interdire_scripts = true;
670 * La balise #ENV permet de recuperer
671 * le contexte d'environnement transmis au calcul d'un squelette,
672 * par exemple #ENV{id_rubrique}
674 * La syntaxe #ENV{toto, valeur par defaut}
675 * renverra 'valeur par defaut' si $toto est vide
677 * La recherche de la cle s'appuyant sur la fonction table_valeur
678 * il est possible de demander un sous element d'un tableau
679 * #ENV{toto/sous/element, valeur par defaut} retournera l'equivalent de
680 * #ENV{toto}|table_valeur{sous/element} c'est a dire en quelque sorte
681 * $env['toto']['sous']['element'] s'il existe, sinon la valeur par defaut.
683 * Si le tableau est vide on renvoie '' (utile pour #SESSION)
685 * Enfin, la balise utilisee seule #ENV retourne le tableau complet
686 * de l'environnement. A noter que ce tableau est retourne serialise.
689 * En standard est applique |entites_html, mais si l'etoile est
690 * utilisee pour desactiver les filtres par defaut, par exemple avec
691 * [(#ENV*{toto})] , il *faut* s'assurer de la securite
692 * anti-javascript, par exemple en filtrant avec |safehtml : [(#ENV*{toto}|safehtml)]
696 * Pile ; arbre de syntaxe abstrait positionne au niveau de la balise.
699 * Tableau dans lequel chercher la cle demandee en parametre de la balise.
700 * Par defaut prend dans le contexte du squelette.
703 * Pile completee du code PHP d'execution de la balise
705 function balise_ENV_dist($p, $src = NULL) {
707 // cle du tableau desiree
708 $_nom = interprete_argument_balise(1,$p);
710 $_sinon = interprete_argument_balise(2,$p);
712 // $src est un tableau de donnees sources eventuellement transmis
713 // en absence, on utilise l'environnement du squelette $Pile[0]
716 // cas de #ENV sans argument : on retourne le serialize() du tableau
717 // une belle fonction [(#ENV|affiche_env)] serait pratique
719 $p->code
= '(is_array($a = ('.$src.')) ? serialize($a) : "")';
721 $p->code
= '@serialize($Pile[0])';
728 $p->code
= "sinon(table_valeur($src, (string)$_nom, null), $_sinon)";
730 $p->code
= "table_valeur($src, (string)$_nom, null)";
733 #$p->interdire_scripts = true;
739 * #CONFIG retourne lire_config()
740 * les reglages du site
742 * Par exemple #CONFIG{gerer_trad} donne 'oui' ou 'non' selon le reglage
743 * Le 3eme argument permet de controler la serialisation du resultat
744 * (mais ne sert que pour le depot 'meta') qui doit parfois deserialiser
746 * ex: |in_array{#CONFIG{toto,#ARRAY,1}}.
748 * Ceci n'affecte pas d'autres depots et |in_array{#CONFIG{toto/,#ARRAY}} sera equivalent
749 * #CONFIG{/tablemeta/champ,defaut} lit la valeur de 'champ' dans la table des meta 'tablemeta'
751 * @param Object $p Arbre syntaxique du compilo
754 function balise_CONFIG_dist($p) {
755 if (!$arg = interprete_argument_balise(1,$p)) {
758 $_sinon = interprete_argument_balise(2,$p);
759 $_unserialize = sinon(interprete_argument_balise(3,$p),"false");
761 $p->code
= '(include_spip(\'inc/config\')?lire_config(' . $arg . ',' .
762 ($_sinon && $_sinon != "''" ?
$_sinon : 'null') . ',' . $_unserialize . "):'')";
768 // http://doc.spip.org/@balise_CONNECT_dist
769 function balise_CONNECT_dist($p) {
770 $p->code
= '($connect ? $connect : NULL)';
771 $p->interdire_scripts
= false;
777 // Cette balise est un tableau des donnees du visiteur (nom, email etc)
778 // Si elle est invoquee, elle leve un drapeau dans le fichier cache, qui
779 // permet a public/cacher d'invalider le cache si le visiteur suivant n'a
780 // pas la meme session
781 // http://doc.spip.org/@balise_SESSION_dist
782 function balise_SESSION_dist($p) {
783 $p->descr
['session'] = true;
785 $f = function_exists('balise_ENV')
789 $p = $f($p, '$GLOBALS["visiteur_session"]');
795 // Ajoute x=y dans la session du visiteur
796 // http://doc.spip.org/@balise_SESSION_SET_dist
797 function balise_SESSION_SET_dist($p) {
798 $_nom = interprete_argument_balise(1,$p);
799 $_val = interprete_argument_balise(2,$p);
800 if (!$_nom OR !$_val) {
801 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SESSION_SET'));
802 erreur_squelette($err_b_s_a, $p);
803 } else $p->code
= '(include_spip("inc/session") AND session_set('.$_nom.','.$_val.'))';
805 $p->interdire_scripts
= false;
815 // evalue un code php ; a utiliser avec precaution :-)
817 // rq: #EVAL{code} produit eval('return code;')
818 // mais si le code est une expression sans balise, on se dispense
819 // de passer par une construction si compliquee, et le code est
820 // passe tel quel (entre parentheses, et protege par interdire_scripts)
821 // Exemples : #EVAL**{6+9} #EVAL**{_DIR_IMG_PACK} #EVAL{'date("Y-m-d")'}
822 // #EVAL{'str_replace("r","z", "roger")'} (attention les "'" sont interdits)
823 // http://doc.spip.org/@balise_EVAL_dist
824 function balise_EVAL_dist($p) {
825 $php = interprete_argument_balise(1,$p);
827 # optimisation sur les #EVAL{une expression sans #BALISE}
828 # attention au commentaire "// x signes" qui precede
829 if (preg_match(",^([[:space:]]*//[^\n]*\n)'([^']+)'$,ms",
831 $p->code
= /* $r[1]. */'('.$r[2].')';
833 $p->code
= "eval('return '.$php.';')";
835 $msg = array('zbug_balise_sans_argument', array('balise' => ' EVAL'));
836 erreur_squelette($msg, $p);
839 #$p->interdire_scripts = true;
844 // #CHAMP_SQL{x} renvoie la valeur du champ sql 'x'
845 // permet de recuperer par exemple un champ notes dans une table sql externe
846 // (impossible via #NOTES qui est une balise calculee)
847 // ne permet pas de passer une expression pour x qui ne peut etre qu'un texte statique !
848 // http://doc.spip.org/@balise_CHAMP_SQL_dist
849 function balise_CHAMP_SQL_dist($p){
852 AND isset($p->param
[0][1][0])
853 AND $champ = ($p->param
[0][1][0]->texte
))
854 $p->code
= champ_sql($champ, $p);
856 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => ' URL_'));
857 erreur_squelette($err_b_s_a, $p);
859 #$p->interdire_scripts = true;
863 // #VAL{x} renvoie 'x' (permet d'appliquer un filtre a une chaine)
864 // Attention #VAL{1,2} renvoie '1', indiquer #VAL{'1,2'}
865 // http://doc.spip.org/@balise_VAL_dist
866 function balise_VAL_dist($p){
867 $p->code
= interprete_argument_balise(1,$p);
868 if (!strlen($p->code
))
870 $p->interdire_scripts
= false;
873 // #NOOP est un alias pour regler #948, ne pas documenter
874 // http://doc.spip.org/@balise_NOOP_dist
875 function balise_NOOP_dist($p) { return balise_VAL_dist($p); }
879 // pour les remarques : renvoie toujours ''
881 // http://doc.spip.org/@balise_REM_dist
882 function balise_REM_dist($p) {
884 $p->interdire_scripts
= false;
891 // pour les entetes de retour http
892 // Ne fonctionne pas sur les INCLURE !
893 // #HTTP_HEADER{Content-Type: text/css}
895 // http://doc.spip.org/@balise_HTTP_HEADER_dist
896 function balise_HTTP_HEADER_dist($p) {
898 $header = interprete_argument_balise(1,$p);
900 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'HTTP_HEADER'));
901 erreur_squelette($err_b_s_a, $p);
902 } else $p->code
= "'<'.'?php header(\"' . "
905 $p->interdire_scripts
= false;
909 // Filtre a appliquer a l'ensemble de la page une fois calculee
910 // (filtrage fait au niveau du squelette, et sans s'appliquer aux <INCLURE>)
911 // http://doc.spip.org/@balise_FILTRE_dist
912 function balise_FILTRE_dist($p) {
915 foreach ($p->param
as $i => $ignore)
916 $args[] = interprete_argument_balise($i+
1,$p);
918 .'?php header("X-Spip-Filtre: \'.'
919 .join('.\'|\'.', $args)
922 $p->interdire_scripts
= false;
929 // definit la duree de vie ($delais) du squelette
931 // parametre(s) supplementaire(s) :
932 // #CACHE{24*3600, cache-client} autorise gestion du IF_MODIFIED_SINCE
933 // #CACHE{24*3600, statique} ne respecte pas l'invalidation par modif de la base
934 // (mais s'invalide tout de meme a l'expiration du delai)
935 // par defaut cache-client => statique
936 // cf. ecrire/public/cacher.php
937 // http://doc.spip.org/@balise_CACHE_dist
938 function balise_CACHE_dist($p) {
941 $duree = valeur_numerique($p->param
[0][1][0]->texte
);
943 // noter la duree du cache dans un entete proprietaire
945 $code = '\'<'.'?php header("X-Spip-Cache: '
949 // Remplir le header Cache-Control
953 .'?php header("Cache-Control: no-cache, must-revalidate"); ?'
955 .'?php header("Pragma: no-cache"); ?'
958 // recuperer les parametres suivants
960 while (isset($p->param
[0][++
$i])) {
961 $pa = ($p->param
[0][$i][0]->texte
);
963 if ($pa == 'cache-client'
965 $code .= '.\'<'.'?php header("Cache-Control: max-age='
968 // il semble logique, si on cache-client, de ne pas invalider
972 if ($pa == 'statique'
974 $code .= '.\'<'.'?php header("X-Spip-Statique: oui"); ?'.'>\'';
978 $p->interdire_scripts
= false;
985 * pour permettre aux plugins d'inserer des styles, js ou autre
986 * dans l'entete sans modification du squelette
987 * les css doivent etre inserees de preference par #INSERT_HEAD_CSS
988 * pour en faciliter la surcharge
990 * on insere ici aussi un morceau de PHP qui verifiera a l'execution que le pipeline insert_head_css a bien ete vu
991 * et dans le cas contraire l'appelera. Permet de ne pas oublier les css de #INSERT_HEAD_CSS meme si cette balise
992 * n'est pas presente.
993 * Il faut mettre ce php avant le insert_head car le compresseur y mets ensuite un php du meme type pour collecter
994 * CSS et JS, et on ne veut pas qu'il rate les css inserees en fallback par insert_head_css_conditionnel
996 * http://doc.spip.org/@balise_INSERT_HEAD_dist
1001 function balise_INSERT_HEAD_dist($p) {
1003 .'?php header("X-Spip-Filtre: \'.'
1004 .'\'insert_head_css_conditionnel\''
1005 . " . '\"); ?'.'>'";
1006 $p->code
.= ". pipeline('insert_head','<!-- insert_head -->')";
1007 $p->interdire_scripts
= false;
1012 * homologue de #INSERT_HEAD pour les CSS
1013 * (et par extension pour le js inline qui doit preferentiellement etre insere avant les CSS car bloquant sinon)
1015 * http://doc.spip.org/@balise_INSERT_HEAD_CSS_dist
1020 function balise_INSERT_HEAD_CSS_dist($p) {
1021 $p->code
= "pipeline('insert_head_css','<!-- insert_head_css -->')";
1022 $p->interdire_scripts
= false;
1026 // #INCLURE statique
1027 // l'inclusion est realisee au calcul du squelette, pas au service
1028 // ainsi le produit du squelette peut etre utilise en entree de filtres a suivre
1029 // on peut faire un #INCLURE{fichier} sans squelette
1030 // (Incompatible avec les balises dynamiques)
1031 // http://doc.spip.org/@balise_INCLUDE_dist
1032 function balise_INCLUDE_dist($p) {
1033 if(function_exists('balise_INCLURE'))
1034 return balise_INCLURE($p);
1036 return balise_INCLURE_dist($p);
1038 // http://doc.spip.org/@balise_INCLURE_dist
1039 function balise_INCLURE_dist($p) {
1040 $id_boucle = $p->id_boucle
;
1041 // la lang n'est pas passe de facon automatique par argumenter
1042 // mais le sera pas recuperer_fond, sauf si etoile=>true est passe
1045 $_contexte = argumenter_inclure($p->param
, true, $p, $p->boucles
, $id_boucle, false, false);
1047 // erreur de syntaxe = fond absent
1048 // (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
1049 if (!$_contexte) $contexte = array();
1051 if (isset($_contexte['fond'])) {
1053 $f = $_contexte['fond'];
1055 if (preg_match('/^.fond.\s*=>(.*)$/s', $f, $r)) {
1057 unset($_contexte['fond']);
1058 } else spip_log("compilation de #INCLURE a revoir");
1060 // #INCLURE{doublons}
1061 if (isset($_contexte['doublons'])) {
1062 $_contexte['doublons'] = "'doublons' => \$doublons";
1065 // Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
1066 if (isset($_contexte['env'])
1067 ||
isset($_contexte['self'])
1070 unset($_contexte['env']);
1071 } else $flag_env = false;
1073 $_options = array();
1074 if (isset($_contexte['ajax'])) {
1075 $_options[] = preg_replace(",=>(.*)$,ims",'=> ($v=(\\1))?$v:true',$_contexte['ajax']);
1076 unset($_contexte['ajax']);
1078 if ($p->etoile
) $_options[] = "'etoile'=>true";
1079 $_options[] = "'compil'=>array(" . memoriser_contexte_compil($p) .")";
1081 $_l = 'array(' . join(",\n\t", $_contexte) .')';
1082 if ($flag_env) $_l = "array_merge(\$Pile[0],$_l)";
1084 $p->code
= sprintf(CODE_RECUPERER_FOND
, $f, $_l, join(',',$_options),"''");
1086 } elseif (!isset($_contexte[1])) {
1087 $msg = array('zbug_balise_sans_argument', array('balise' => ' INCLURE'));
1088 erreur_squelette($msg, $p);
1089 } else $p->code
= '(($c = find_in_path(' . $_contexte[1] . ')) ? spip_file_get_contents($c) : "")';
1091 $p->interdire_scripts
= false; // la securite est assuree par recuperer_fond
1095 // Inclure un modele : #MODELE{modele, params}
1096 // http://doc.spip.org/@balise_MODELE_dist
1097 function balise_MODELE_dist($p) {
1099 $_contexte = argumenter_inclure($p->param
, true, $p, $p->boucles
, $p->id_boucle
, false);
1101 // erreur de syntaxe = fond absent
1102 // (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
1103 if (!$_contexte) $contexte = array();
1105 if (!isset($_contexte[1])) {
1106 $msg = array('zbug_balise_sans_argument', array('balise' => ' MODELE'));
1107 erreur_squelette($msg, $p);
1109 $nom = $_contexte[1];
1110 unset($_contexte[1]);
1112 if (preg_match("/^\s*'[^']*'/s", $nom))
1113 $nom = "'modeles/" . substr($nom,1);
1114 else $nom = "'modeles/' . $nom";
1116 // Incoherence dans la syntaxe du contexte. A revoir.
1117 // Reserver la cle primaire de la boucle courante si elle existe
1118 if (isset($p->boucles
[$p->id_boucle
]->primary
)) {
1119 $primary = $p->boucles
[$p->id_boucle
]->primary
;
1120 if (!strpos($primary,',')) {
1121 $id = champ_sql($primary, $p);
1122 $_contexte[] = "'$primary'=>".$id;
1123 $_contexte[] = "'id'=>".$id;
1126 $_contexte[] = "'recurs'=>(++\$recurs)";
1128 if (isset($p->boucles
[$p->id_boucle
]))
1129 $connect = $p->boucles
[$p->id_boucle
]->sql_serveur
;
1131 $_options = memoriser_contexte_compil($p);
1132 $_options = "'compil'=>array($_options), 'trim'=>true";
1133 if (isset($_contexte['ajax'])){
1134 $_options .= ", ".preg_replace(",=>(.*)$,ims",'=> ($v=(\\1))?$v:true',$_contexte['ajax']);
1135 unset($_contexte['ajax']);
1138 $page = sprintf(CODE_RECUPERER_FOND
, $nom, 'array(' . join(',', $_contexte) .')', $_options, _q($connect));
1140 $p->code
= "\n\t(((\$recurs=(isset(\$Pile[0]['recurs'])?\$Pile[0]['recurs']:0))>=5)? '' :\n\t$page)\n";
1142 $p->interdire_scripts
= false; // securite assuree par le squelette
1150 // Affecte une variable locale au squelette
1152 // la balise renvoie la valeur
1153 // http://doc.spip.org/@balise_SET_dist
1154 function balise_SET_dist($p){
1155 $_nom = interprete_argument_balise(1,$p);
1156 $_val = interprete_argument_balise(2,$p);
1158 if (!$_nom OR !$_val) {
1159 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SET'));
1160 erreur_squelette($err_b_s_a, $p);
1162 // affectation $_zzz inutile, mais permet de contourner un bug OpCode cache sous PHP 5.5.4
1163 // cf https://bugs.php.net/bug.php?id=65845
1164 else $p->code
= "vide(\$Pile['vars'][\$_zzz=(string)$_nom] = $_val)";
1166 $p->interdire_scripts
= false; // la balise ne renvoie rien
1172 // Recupere une variable locale au squelette
1173 // #GET{nom,defaut} renvoie defaut si la variable nom n'a pas ete affectee
1175 // http://doc.spip.org/@balise_GET_dist
1176 function balise_GET_dist($p) {
1177 $p->interdire_scripts
= false; // le contenu vient de #SET, donc il est de confiance
1178 if (function_exists('balise_ENV'))
1179 return balise_ENV($p, '$Pile["vars"]');
1181 return balise_ENV_dist($p, '$Pile["vars"]');
1186 * Compile la balise #DOUBLONS
1188 * #DOUBLONS{mots} ou #DOUBLONS{mots,famille}
1189 * donne l'etat des doublons (MOTS) a cet endroit
1190 * sous forme de tableau d'id_mot array(1,2,3,...)
1191 * #DOUBLONS tout seul donne la liste brute de tous les doublons
1192 * #DOUBLONS*{mots} donne la chaine brute ",1,2,3,..."
1193 * (changera si la gestion des doublons evolue)
1196 * Pile au niveau de la balise
1198 * Pile complétée par le code à générer
1200 function balise_DOUBLONS_dist($p) {
1201 if ($type = interprete_argument_balise(1,$p)) {
1202 if ($famille = interprete_argument_balise(2,$p))
1203 $type .= '.' . $famille;
1204 $p->code
= '$doublons['.$type.']';
1206 $p->code
= 'array_filter(array_map("intval",explode(",",'
1210 $p->code
= '$doublons';
1212 $p->interdire_scripts
= false;
1220 // pour permettre aux plugins d'inserer des sorties de pipeline dans un squelette
1221 // #PIPELINE{insert_body}
1222 // #PIPELINE{insert_body,flux}
1224 // http://doc.spip.org/@balise_PIPELINE_dist
1225 function balise_PIPELINE_dist($p) {
1226 $_pipe = interprete_argument_balise(1,$p);
1228 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'PIPELINE'));
1229 erreur_squelette($err_b_s_a, $p);
1231 $_flux = interprete_argument_balise(2,$p);
1232 $_flux = $_flux?
$_flux:"''";
1233 $p->code
= "pipeline( $_pipe , $_flux )";
1234 $p->interdire_scripts
= false;
1241 // une balise qui ne fait rien, pour surcharge par le plugin widgets
1243 // http://doc.spip.org/@balise_EDIT_dist
1244 function balise_EDIT_dist($p) {
1246 $p->interdire_scripts
= false;
1253 // pour recuperer le nombre d'elements affiches par l'intermediaire du filtre
1256 // #TOTAL_UNIQUE afiche le nombre de #BALISE|unique
1257 // #TOTAL_UNIQUE{famille} afiche le nombre de #BALISE|unique{famille}
1259 // http://doc.spip.org/@balise_TOTAL_UNIQUE_dist
1260 function balise_TOTAL_UNIQUE_dist($p) {
1261 $_famille = interprete_argument_balise(1,$p);
1262 $_famille = $_famille ?
$_famille : "''";
1263 $p->code
= "unique('', $_famille, true)";
1269 // pour creer un array php a partir d'arguments calcules
1270 // #ARRAY{key1,val1,key2,val2 ...} retourne array(key1=>val1,...)
1272 // http://doc.spip.org/@balise_ARRAY_dist
1273 function balise_ARRAY_dist($p) {
1277 $_key = interprete_argument_balise($n++
,$p);
1278 $_val = interprete_argument_balise($n++
,$p);
1279 if ($_key AND $_val) $_code[] = "$_key => $_val";
1280 } while ($_key && $_val);
1281 $p->code
= 'array(' . join(', ',$_code).')';
1282 $p->interdire_scripts
= false;
1287 * #LISTE{a,b,c,d,e} cree un array avec les valeurs, sans preciser les cles
1292 function balise_LISTE_dist($p) {
1295 while ($_val = interprete_argument_balise($n++
,$p))
1297 $p->code
= 'array(' . join(', ',$_code).')';
1298 $p->interdire_scripts
= false;
1302 // Appelle la fonction autoriser et renvoie ' ' si OK, '' si niet
1303 // A noter : la priorite des operateurs exige && plutot que AND
1304 // Cette balise cree un cache par session
1305 // http://doc.spip.org/@balise_AUTORISER_dist
1306 function balise_AUTORISER_dist($p) {
1308 $p->descr
['session'] = true; // faire un cache par session
1311 while ($_v = interprete_argument_balise($n++
,$p))
1314 $p->code
= '((function_exists("autoriser")||include_spip("inc/autoriser"))&&autoriser(' . join(', ',$_code).')?" ":"")';
1315 $p->interdire_scripts
= false;
1319 // Appelle la fonction info_plugin
1320 // Afficher des informations sur les plugins dans le site public
1321 // http://doc.spip.org/@balise_PLUGIN_dist
1322 function balise_PLUGIN_dist($p) {
1323 $plugin = interprete_argument_balise(1,$p);
1324 $plugin = isset($plugin) ?
str_replace('\'', '"', $plugin) : '""';
1325 $type_info = interprete_argument_balise(2,$p);
1326 $type_info = isset($type_info) ?
str_replace('\'', '"', $type_info) : '"est_actif"';
1328 $f = chercher_filtre('info_plugin');
1329 $p->code
= $f.'('.$plugin.', '.$type_info.')';
1333 // Appelle la fonction inc_aider_dist
1334 // http://doc.spip.org/@balise_AIDER_dist
1335 function balise_AIDER_dist($p) {
1336 $_motif = interprete_argument_balise(1,$p);
1337 $s = "'" . addslashes($p->descr
['sourcefile']) . "'";
1338 $aider = charger_fonction('aider','inc');
1339 $p->code
= "((\$aider=charger_fonction('aider','inc'))?\$aider($_motif,$s, \$Pile[0]):'')";
1343 // Insertion du contexte des formulaires charger/verifier/traiter
1344 // avec les hidden de l'url d'action
1345 // http://doc.spip.org/@balise_ACTION_FORMULAIRE
1346 function balise_ACTION_FORMULAIRE($p){
1347 if (!$_url = interprete_argument_balise(1,$p))
1348 $_url = "@\$Pile[0]['action']";
1349 if (!$_form = interprete_argument_balise(2,$p))
1350 $_form = "@\$Pile[0]['form']";
1352 // envoyer le nom du formulaire que l'on traite
1353 // transmettre les eventuels args de la balise formulaire
1354 $p->code
= " '<div>' .
1355 form_hidden($_url) .
1356 '<input name=\'formulaire_action\' type=\'hidden\'
1357 value=\'' . $_form . '\' />' .
1358 '<input name=\'formulaire_action_args\' type=\'hidden\'
1359 value=\'' . @\$Pile[0]['formulaire_args']. '\' />' .
1360 (@\$Pile[0]['_hidden']?@\$Pile[0]['_hidden']:'') .
1363 $p->interdire_scripts
= false;
1369 * Generer un bouton d'action en post, ajaxable
1370 * a utiliser a la place des liens action_auteur, sous la forme
1371 * #BOUTON_ACTION{libelle,url}
1373 * #BOUTON_ACTION{libelle,url,ajax} pour que l'action soit ajax comme un lien class='ajax'
1375 * #BOUTON_ACTION{libelle,url,ajax,message_confirmation} pour utiliser un message de confirmation
1377 * #BOUTON_ACTION{libelle[,url[,ajax[,message_confirmation[,title[,callback]]]]]}
1379 * @param unknown_type $p
1382 function balise_BOUTON_ACTION_dist($p){
1385 for ($k=1;$k<=6;$k++
){
1386 $_a = interprete_argument_balise($k,$p);
1390 // supprimer les args vides
1391 while(end($args)=="''" AND count($args)>2)
1393 $args = implode(",",$args);
1395 $bouton_action = chercher_filtre("bouton_action");
1396 $p->code
= "$bouton_action($args)";
1397 $p->interdire_scripts
= false;
1403 function balise_SLOGAN_SITE_SPIP_dist($p) {
1404 $p->code
= "\$GLOBALS['meta']['slogan_site']";
1405 #$p->interdire_scripts = true;
1410 // Renvoie ' ' si le webmestre souhaite que SPIP genere du code (X)HTML5 sur
1411 // le site public, et '' si le code doit etre strictement compatible HTML4
1412 // http://doc.spip.org/@balise_HTML5_dist
1413 function balise_HTML5_dist($p) {
1414 $p->code
= html5_permis() ?
"' '" : "''";
1415 $p->interdire_scripts
= false;
1422 * #TRI{champ[,libelle]}
1423 * champ prend > ou < pour afficher le lien de changement de sens
1424 * croissant ou decroissant (> < indiquent un sens par une fleche)
1426 * @param unknown_type $p
1427 * @param unknown_type $liste
1430 function balise_TRI_dist($p, $liste='true') {
1431 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->descr
['id_mere'];
1433 // s'il n'y a pas de nom de boucle, on ne peut pas trier
1436 _T('zbug_champ_hors_boucle',
1437 array('champ' => '#TRI')
1442 $boucle = $p->boucles
[$b];
1444 // s'il n'y a pas de tri_champ, c'est qu'on se trouve
1445 // dans un boucle recursive ou qu'on a oublie le critere {tri}
1446 if (!isset($boucle->modificateur
['tri_champ'])) {
1448 _T('zbug_tri_sans_critere',
1449 array('champ' => '#TRI')
1455 $_champ = interprete_argument_balise(1,$p);
1456 // si pas de champ, renvoyer le critere de tri utilise
1458 $p->code
= $boucle->modificateur
['tri_champ'];
1461 // forcer la jointure si besoin, et si le champ est statique
1462 if (preg_match(",^'([\w.]+)'$,i",$_champ,$m)){
1463 index_pile($b, $m[1], $p->boucles
);
1466 $_libelle = interprete_argument_balise(2,$p);
1467 $_libelle = $_libelle?
$_libelle:$_champ;
1469 $_class = interprete_argument_balise(3,$p);
1470 // si champ = ">" c'est un lien vers le tri croissant : de gauche a droite ==> 1
1471 // si champ = "<" c'est un lien vers le tri decroissant : (sens inverse) == -1
1472 $_issens = "in_array($_champ,array('>','<'))";
1473 $_sens = "(strpos('< >',$_champ)-1)";
1475 $_variable = "((\$s=$_issens)?'sens':'tri').".$boucle->modificateur
['tri_nom'];
1476 $_url = "parametre_url(self(),$_variable,\$s?$_sens:$_champ)";
1477 $_on = "\$s?(".$boucle->modificateur
['tri_sens']."==$_sens".'):('.$boucle->modificateur
['tri_champ']."==$_champ)";
1479 $p->code
= "lien_ou_expose($_url,$_libelle,$_on".($_class?
",$_class":"").")";
1481 $p->interdire_scripts
= false;
1487 * #SAUTER{n} permet de sauter en avant n resultats dans une boucle
1488 * La balise modifie le compteur courant de la boucle, mais pas les autres
1489 * champs qui restent les valeurs de la boucle avant le saut. Il est donc
1490 * preferable d'utiliser la balise juste avant la fermeture </BOUCLE>
1492 * L'argument n doit etre superieur a zero sinon la balise ne fait rien
1497 function balise_SAUTER_dist($p){
1498 $id_boucle = $p->id_boucle
;
1499 $boucle = $p->boucles
[$id_boucle];
1502 $msg = array('zbug_champ_hors_boucle', array('champ' => '#SAUTER'));
1503 erreur_squelette($msg, $p);
1506 $_saut = interprete_argument_balise(1,$p);
1507 $_compteur = "\$Numrows['$id_boucle']['compteur_boucle']";
1508 $_total = "\$Numrows['$id_boucle']['total']";
1510 $p->code
= "vide($_compteur=\$iter->skip($_saut,$_total))";
1512 $p->interdire_scripts
= false;
1518 * Savoir si on objet est publie ou non
1523 function balise_PUBLIE_dist($p) {
1524 if (!$_type = interprete_argument_balise(1,$p)){
1525 $_type = _q($p->type_requete
);
1526 $_id = champ_sql($p->boucles
[$p->id_boucle
]->primary
,$p);
1529 $_id = interprete_argument_balise(2,$p);
1531 $connect = $p->boucles
[$p->id_boucle
]->sql_serveur
;
1533 $p->code
= "(objet_test_si_publie(".$_type.",intval(".$_id."),"._q($connect).")?' ':'')";
1534 $p->interdire_scripts
= false;
1540 * generer un fichier statique a partir d'un squelette SPIP
1542 * Le format du fichier sera extrait de la preextension du squelette (typo.css.html, messcripts.js.html)
1543 * ou par l'argument format=css ou format=js passe en argument.
1545 * Si pas de format detectable, on utilise .html, comme pour les squelettes
1547 * <link rel="stylesheet" type="text/css" href="#PRODUIRE{fond=css/macss.css,couleur=ffffff}" />
1548 * la syntaxe de la balise est la meme que celle de #INCLURE
1553 function balise_PRODUIRE_dist($p){
1554 $balise_inclure = charger_fonction('INCLURE','balise');
1555 $p = $balise_inclure($p);
1557 $p->code
= str_replace('recuperer_fond(','produire_fond_statique(',$p->code
);
1563 * Definir la largeur d'ecran dans l'espace prive
1564 * #LARGEUR_ECRAN{pleine_largeur}
1569 function balise_LARGEUR_ECRAN_dist($p){
1570 $_class = interprete_argument_balise(1,$p);
1571 if (!$_class) $_class='null';
1572 $p->code
= "(is_string($_class)?vide(\$GLOBALS['largeur_ecran']=$_class):(isset(\$GLOBALS['largeur_ecran'])?\$GLOBALS['largeur_ecran']:''))";