3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2019 *
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 \***************************************************************************/
14 * Ce fichier regroupe la quasi totalité des définitions de `#BALISES` de SPIP.
16 * Pour chaque balise, il est possible de surcharger, dans son fichier
17 * mes_fonctions.php, la fonction `balise_TOTO_dist()` par une fonction
18 * `balise_TOTO()` respectant la même API : elle reçoit en entrée un objet
19 * de classe `Champ`, le modifie et le retourne. Cette classe est définie
20 * dans public/interfaces.
22 * Des balises dites «dynamiques» sont également déclarées dans le
23 * répertoire ecrire/balise/
25 * @package SPIP\Core\Compilateur\Balises
28 if (!defined('_ECRIRE_INC_VERSION')) {
33 * Retourne le code PHP d'un argument de balise s'il est présent
35 * @uses calculer_liste()
38 * // Retourne le premier argument de la balise
39 * // #BALISE{premier,deuxieme}
40 * $arg = interprete_argument_balise(1,$p);
44 * Numéro de l'argument
46 * Pile au niveau de la balise
48 * Code PHP si cet argument est présent, sinon null
50 function interprete_argument_balise($n, $p) {
51 if (($p->param
) && (!$p->param
[0][0]) && (count($p->param
[0]) > $n)) {
52 return calculer_liste($p->param
[0][$n],
63 // Définition des balises
67 * Compile la balise `#NOM_SITE_SPIP` retournant le nom du site
70 * @link http://www.spip.net/4622
73 * Pile au niveau de la balise
75 * Pile complétée par le code à générer
77 function balise_NOM_SITE_SPIP_dist($p) {
78 $p->code
= "\$GLOBALS['meta']['nom_site']";
80 #$p->interdire_scripts = true;
85 * Compile la balise `#EMAIL_WEBMASTER` retournant l'adresse courriel
89 * @link http://www.spip.net/4586
92 * Pile au niveau de la balise
94 * Pile complétée par le code à générer
96 function balise_EMAIL_WEBMASTER_dist($p) {
97 $p->code
= "\$GLOBALS['meta']['email_webmaster']";
99 #$p->interdire_scripts = true;
104 * Compile la balise `#DESCRIPTIF_SITE_SPIP` qui retourne le descriptif
108 * @link http://www.spip.net/4338
111 * Pile au niveau de la balise
113 * Pile complétée par le code à générer
115 function balise_DESCRIPTIF_SITE_SPIP_dist($p) {
116 $p->code
= "\$GLOBALS['meta']['descriptif_site']";
118 #$p->interdire_scripts = true;
124 * Compile la balise `#CHARSET` qui retourne le nom du jeu de caractères
125 * utilisé par le site tel que `utf-8`
128 * @link http://www.spip.net/4331
131 * <meta http-equiv="Content-Type" content="text/html; charset=#CHARSET" />
135 * Pile au niveau de la balise
137 * Pile complétée par le code à générer
139 function balise_CHARSET_dist($p) {
140 $p->code
= "\$GLOBALS['meta']['charset']";
142 #$p->interdire_scripts = true;
147 * Compile la balise `#LANG_LEFT` retournant 'left' si la langue s'écrit
148 * de gauche à droite, sinon 'right'
151 * Peut servir à l'écriture de code CSS dans un squelette, mais
152 * pour inclure un fichier css, il vaut mieux utiliser le filtre
153 * `direction_css` si on le souhaite sensible à la langue utilisé.
156 * @link http://www.spip.net/4625
158 * @see balise_LANG_RIGHT_dist()
159 * @see balise_LANG_DIR_dist()
160 * @see direction_css()
163 * Pile au niveau de la balise
165 * Pile complétée par le code à générer
167 function balise_LANG_LEFT_dist($p) {
168 $_lang = champ_sql('lang', $p);
169 $p->code
= "lang_dir($_lang, 'left','right')";
170 $p->interdire_scripts
= false;
176 * Compile la balise `#LANG_RIGHT` retournant 'right' si la langue s'écrit
177 * de gauche à droite, sinon 'left'
180 * @link http://www.spip.net/4625
182 * @see balise_LANG_LEFT_dist()
183 * @see balise_LANG_DIR_dist()
184 * @see direction_css()
187 * Pile au niveau de la balise
189 * Pile complétée par le code à générer
191 function balise_LANG_RIGHT_dist($p) {
192 $_lang = champ_sql('lang', $p);
193 $p->code
= "lang_dir($_lang, 'right','left')";
194 $p->interdire_scripts
= false;
200 * Compile la balise `#LANG_DIR` retournant 'ltr' si la langue s'écrit
201 * de gauche à droite, sinon 'rtl'
204 * @link http://www.spip.net/4625
206 * @see balise_LANG_LEFT_dist()
207 * @see balise_LANG_RIGHT_dist()
210 * <html dir="#LANG_DIR" lang="#LANG"
211 * xmlns="http://www.w3.org/1999/xhtml"
212 * xml:lang="#LANG" class="[(#LANG_DIR)][ (#LANG)] no-js">
216 * Pile au niveau de la balise
218 * Pile complétée par le code à générer
220 function balise_LANG_DIR_dist($p) {
221 $_lang = champ_sql('lang', $p);
222 $p->code
= "lang_dir($_lang, 'ltr','rtl')";
223 $p->interdire_scripts
= false;
230 * Compile la balise `#PUCE` affichant une puce
233 * @link http://www.spip.net/4628
234 * @see definir_puce()
237 * Pile au niveau de la balise
239 * Pile complétée par le code à générer
241 function balise_PUCE_dist($p) {
242 $p->code
= "definir_puce()";
243 $p->interdire_scripts
= false;
250 * Compile la balise `#DATE` qui retourne la date de mise en ligne
252 * Cette balise retourne soit le champ `date` d'une table si elle est
253 * utilisée dans une boucle, sinon la date de calcul du squelette.
256 * @link http://www.spip.net/4336 Balise DATE
257 * @link http://www.spip.net/1971 La gestion des dates
260 * <td>[(#DATE|affdate_jourcourt)]</td>
264 * Pile au niveau de la balise.
266 * Pile completée du code PHP d'exécution de la balise
268 function balise_DATE_dist($p) {
269 $d = champ_sql('date', $p);
270 # if ($d === "@\$Pile[0]['date']")
271 # $d = "isset(\$Pile[0]['date']) ? $d : time()";
279 * Compile la balise `#DATE_REDAC` qui retourne la date de première publication
281 * Cette balise retourne le champ `date_redac` d'une table
284 * @link http://www.spip.net/3858 Balises DATE_MODIF et DATE_REDAC
285 * @link http://www.spip.net/1971 La gestion des dates
286 * @see balise_DATE_MODIF_dist()
289 * Pile au niveau de la balise.
291 * Pile completée du code PHP d'exécution de la balise
293 function balise_DATE_REDAC_dist($p) {
294 $d = champ_sql('date_redac', $p);
295 # if ($d === "@\$Pile[0]['date_redac']")
296 # $d = "isset(\$Pile[0]['date_redac']) ? $d : time()";
298 $p->interdire_scripts
= false;
304 * Compile la balise `#DATE_MODIF` qui retourne la date de dernière modification
306 * Cette balise retourne le champ `date_modif` d'une table
309 * @link http://www.spip.net/3858 Balises DATE_MODIF et DATE_REDAC
310 * @link http://www.spip.net/1971 La gestion des dates
311 * @see balise_DATE_REDAC_dist()
314 * Pile au niveau de la balise.
316 * Pile completée du code PHP d'exécution de la balise
318 function balise_DATE_MODIF_dist($p) {
319 $p->code
= champ_sql('date_modif', $p);
320 $p->interdire_scripts
= false;
326 * Compile la balise `#DATE_NOUVEAUTES` indiquant la date de dernier envoi
327 * du mail de nouveautés
330 * @link http://www.spip.net/4337 Balise DATE_NOUVEAUTES
331 * @link http://www.spip.net/1971 La gestion des dates
332 * @see balise_DATE_REDAC_dist()
335 * Pile au niveau de la balise.
337 * Pile completée du code PHP d'exécution de la balise
339 function balise_DATE_NOUVEAUTES_dist($p) {
340 $p->code
= "((\$GLOBALS['meta']['quoi_de_neuf'] == 'oui'
341 AND isset(\$GLOBALS['meta']['dernier_envoi_neuf'])) ?
342 \$GLOBALS['meta']['dernier_envoi_neuf'] :
344 $p->interdire_scripts
= false;
351 * Compile la balise `#DOSSIER_SQUELETTE` retournant le chemin vers le
352 * répertoire de squelettes actuellement utilisé
355 * @deprecated Utiliser `#CHEMIN`
356 * @link http://www.spip.net/4627
357 * @see balise_CHEMIN_dist()
360 * Pile au niveau de la balise.
362 * Pile completée du code PHP d'exécution de la balise
364 function balise_DOSSIER_SQUELETTE_dist($p) {
365 $code = substr(addslashes(dirname($p->descr
['sourcefile'])), strlen(_DIR_RACINE
));
366 $p->code
= "_DIR_RACINE . '$code'" .
367 $p->interdire_scripts
= false;
373 * Compile la balise `#SQUELETTE` retournant le chemin du squelette courant
376 * @link http://www.spip.net/4027
379 * Pile au niveau de la balise.
381 * Pile completée du code PHP d'exécution de la balise
383 function balise_SQUELETTE_dist($p) {
384 $code = addslashes($p->descr
['sourcefile']);
385 $p->code
= "'$code'" .
386 $p->interdire_scripts
= false;
392 * Compile la balise `#SPIP_VERSION` qui affiche la version de SPIP
395 * @see spip_version()
398 * <meta name="generator" content="SPIP[ (#SPIP_VERSION)]" />
402 * Pile au niveau de la balise.
404 * Pile completée du code PHP d'exécution de la balise
406 function balise_SPIP_VERSION_dist($p) {
407 $p->code
= "spip_version()";
408 $p->interdire_scripts
= false;
415 * Compile la balise `#NOM_SITE` qui affiche le nom du site.
417 * Affiche le nom du site ou sinon l'URL ou le titre de l'objet
418 * Utiliser `#NOM_SITE*` pour avoir le nom du site ou rien.
420 * Cette balise interroge les colonnes `nom_site` ou `url_site`
421 * dans la boucle la plus proche.
424 * @see calculer_url()
427 * <a href="#URL_SITE">#NOM_SITE</a>
431 * Pile au niveau de la balise
433 * Pile complétée par le code à générer
435 function balise_NOM_SITE_dist($p) {
437 $p->code
= "supprimer_numero(calculer_url(" .
438 champ_sql('url_site', $p) . "," .
439 champ_sql('nom_site', $p) .
440 ", 'titre', \$connect, false))";
442 $p->code
= champ_sql('nom_site', $p);
445 $p->interdire_scripts
= true;
452 * Compile la balise `#NOTE` qui affiche les notes de bas de page
455 * @link http://www.spip.net/3964
456 * @see calculer_notes()
459 * Pile au niveau de la balise
461 * Pile complétée par le code à générer
463 function balise_NOTES_dist($p) {
464 // Recuperer les notes
465 $p->code
= 'calculer_notes()';
467 #$p->interdire_scripts = true;
473 * Compile la balise `#RECHERCHE` qui retourne le terme de recherche demandé
475 * Retourne un terme demandé en recherche, en le prenant dans _request()
476 * sous la clé `recherche`.
481 * <h3>Recherche de : #RECHERCHE</h3>
485 * Pile au niveau de la balise
487 * Pile complétée par le code à générer
489 function balise_RECHERCHE_dist($p) {
490 $p->code
= 'entites_html(_request("recherche"))';
491 $p->interdire_scripts
= false;
498 * Compile la balise `#COMPTEUR_BOUCLE` qui retourne le numéro de l’itération
499 * actuelle de la boucle
502 * @link http://www.spip.net/4333
503 * @see balise_TOTAL_BOUCLE_dist()
506 * Pile au niveau de la balise
508 * Pile complétée par le code à générer
510 function balise_COMPTEUR_BOUCLE_dist($p) {
511 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->descr
['id_mere'];
514 'zbug_champ_hors_boucle',
515 array('champ' => '#COMPTEUR_BOUCLE')
517 erreur_squelette($msg, $p);
519 $p->code
= "\$Numrows['$b']['compteur_boucle']";
520 $p->boucles
[$b]->cptrows
= true;
521 $p->interdire_scripts
= false;
528 * Compile la balise `#TOTAL_BOUCLE` qui retourne le nombre de résultats
529 * affichés par la boucle
532 * @link http://www.spip.net/4334
533 * @see balise_COMPTEUR_BOUCLE_dist()
534 * @see balise_GRAND_TOTAL_dist()
537 * Pile au niveau de la balise
539 * Pile complétée par le code à générer
541 function balise_TOTAL_BOUCLE_dist($p) {
542 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->descr
['id_mere'];
543 if ($b === '' ||
!isset($p->boucles
[$b])) {
545 'zbug_champ_hors_boucle',
546 array('champ' => "#$b" . 'TOTAL_BOUCLE')
548 erreur_squelette($msg, $p);
550 $p->code
= "\$Numrows['$b']['total']";
551 $p->boucles
[$b]->numrows
= true;
552 $p->interdire_scripts
= false;
560 * Compile la balise `#POINTS` qui affiche la pertinence des résultats
562 * Retourne le calcul `points` réalisé par le critère `recherche`.
563 * Cette balise nécessite donc la présence de ce critère.
566 * @link http://www.spip.net/903 Boucles et balises de recherche
567 * @see critere_recherche_dist()
570 * Pile au niveau de la balise
572 * Pile complétée par le code à générer
574 function balise_POINTS_dist($p) {
575 return rindex_pile($p, 'points', 'recherche');
580 * Compile la balise `#POPULARITE_ABSOLUE` qui affiche la popularité absolue
582 * Cela correspond à la popularité quotidienne de l'article
585 * @link http://www.spip.net/1846 La popularité
586 * @see balise_POPULARITE_dist()
587 * @see balise_POPULARITE_MAX_dist()
588 * @see balise_POPULARITE_SITE_dist()
591 * Pile au niveau de la balise
593 * Pile complétée par le code à générer
595 function balise_POPULARITE_ABSOLUE_dist($p) {
597 champ_sql('popularite', $p) .
599 $p->interdire_scripts
= false;
605 * Compile la balise `#POPULARITE_SITE` qui affiche la popularité du site
607 * La popularité du site est la somme de toutes les popularités absolues.
610 * @link http://www.spip.net/1846 La popularité
611 * @see balise_POPULARITE_ABSOLUE_dist()
612 * @see balise_POPULARITE_dist()
613 * @see balise_POPULARITE_MAX_dist()
616 * Pile au niveau de la balise
618 * Pile complétée par le code à générer
620 function balise_POPULARITE_SITE_dist($p) {
621 $p->code
= 'ceil($GLOBALS["meta"][\'popularite_total\'])';
622 $p->interdire_scripts
= false;
628 * Compile la balise `#POPULARITE_MAX` qui affiche la popularité maximum
629 * parmis les popularités des articles
631 * Cela correspond à la popularité quotidienne de l'article
634 * @link http://www.spip.net/1846 La popularité
635 * @see balise_POPULARITE_ABSOLUE_dist()
636 * @see balise_POPULARITE_dist()
637 * @see balise_POPULARITE_SITE_dist()
640 * Pile au niveau de la balise
642 * Pile complétée par le code à générer
644 function balise_POPULARITE_MAX_dist($p) {
645 $p->code
= 'ceil($GLOBALS["meta"][\'popularite_max\'])';
646 $p->interdire_scripts
= false;
653 * Compile la balise `#VALEUR` retournant le champ `valeur`
655 * Utile dans une boucle DATA pour retourner une valeur.
658 * @link http://www.spip.net/5546 #CLE et #VALEUR
659 * @see table_valeur()
662 * #VALEUR renvoie le champ valeur
663 * #VALEUR{x} renvoie #VALEUR|table_valeur{x},
664 * équivalent à #X (si X n'est pas une balise spécifique à SPIP)
665 * #VALEUR{a/b} renvoie #VALEUR|table_valeur{a/b}
669 * Pile au niveau de la balise
671 * Pile complétée par le code à générer
673 function balise_VALEUR_dist($p) {
674 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->id_boucle
;
675 $p->code
= index_pile($p->id_boucle
, 'valeur', $p->boucles
, $b);;
676 if (($v = interprete_argument_balise(1, $p)) !== null) {
677 $p->code
= 'table_valeur(' . $p->code
. ', ' . $v . ')';
679 $p->interdire_scripts
= true;
685 * Compile la balise `#EXPOSE` qui met en évidence l'élément sur lequel
688 * Expose dans une boucle l'élément de la page sur laquelle on se trouve,
689 * en retournant `on` si l'élément correspond à la page, une chaîne vide sinon.
691 * On peut passer les paramètres à faire retourner par la balise.
695 * <a href="#URL_ARTICLE"[ class="(#EXPOSE)"]>
696 * <a href="#URL_ARTICLE"[ class="(#EXPOSE{actif})"]>
697 * <a href="#URL_ARTICLE"[ class="(#EXPOSE{on,off})"]>
701 * @link http://www.spip.net/2319 Exposer un article
702 * @uses calculer_balise_expose()
705 * Pile au niveau de la balise
707 * Pile complétée par le code à générer
709 function balise_EXPOSE_dist($p) {
712 if (($v = interprete_argument_balise(1, $p)) !== null) {
714 if (($v = interprete_argument_balise(2, $p)) !== null) {
720 return calculer_balise_expose($p, $on, $off);
724 * Calcul de la balise expose
726 * @see calcul_exposer()
729 * Pile au niveau de la balise
731 * Texte à afficher si l'élément est exposé (code à écrire tel que "'on'")
733 * Texte à afficher si l'élément n'est pas exposé (code à écrire tel que "''")
735 * Pile complétée par le code à générer
737 function calculer_balise_expose($p, $on, $off) {
738 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->id_boucle
;
739 if (empty($p->boucles
[$b]->primary
)) {
740 $msg = array('zbug_champ_hors_boucle', array('champ' => '#EXPOSER'));
741 erreur_squelette($msg, $p);
744 $key = $p->boucles
[$b]->primary
;
745 $type = $p->boucles
[$p->id_boucle
]->primary
;
746 $desc = $p->boucles
[$b]->show
;
747 $connect = sql_quote($p->boucles
[$b]->sql_serveur
);
749 // Ne pas utiliser champ_sql, on jongle avec le nom boucle explicite
750 $c = index_pile($p->id_boucle
, $type, $p->boucles
);
752 if (isset($desc['field']['id_parent'])) {
753 $parent = 0; // pour if (!$parent) dans calculer_expose
754 } elseif (isset($desc['field']['id_rubrique'])) {
755 $parent = index_pile($p->id_boucle
, 'id_rubrique', $p->boucles
, $b);
756 } elseif (isset($desc['field']['id_groupe'])) {
757 $parent = index_pile($p->id_boucle
, 'id_groupe', $p->boucles
, $b);
762 $p->code
= "(calcul_exposer($c, '$type', \$Pile[0], $parent, '$key', $connect) ? $on : $off)";
765 $p->interdire_scripts
= false;
772 * Compile la balise `#DEBUT_SURLIGNE` qui permettait le surlignage
773 * des mots d'une recherche
776 * Cette balise n'a plus d'effet depuis r9343
779 * @see balise_FIN_SURLIGNE_dist()
780 * @deprecated Utiliser les classes CSS `surlignable` ou `pas_surlignable`
783 * Pile au niveau de la balise
785 * Pile complétée par le code à générer
787 function balise_DEBUT_SURLIGNE_dist($p) {
788 include_spip('inc/surligne');
789 $p->code
= "'<!-- " . MARQUEUR_SURLIGNE
. " -->'";
796 * Compile la balise `#FIN_SURLIGNE` qui arrêtait le surlignage
797 * des mots d'une recherche
800 * Cette balise n'a plus d'effet depuis r9343
803 * @see balise_DEBUT_SURLIGNE_dist()
804 * @deprecated Utiliser les classes CSS `surlignable` ou `pas_surlignable`
807 * Pile au niveau de la balise
809 * Pile complétée par le code à générer
811 function balise_FIN_SURLIGNE_dist($p) {
812 include_spip('inc/surligne');
813 $p->code
= "'<!-- " . MARQUEUR_FSURLIGNE
. "-->'";
820 * Compile la balise `#INTRODUCTION`
822 * Retourne une introduction d'un objet éditorial, c'est à dire les 600
823 * premiers caractères environ du champ 'texte' de l'objet ou le contenu
824 * indiqué entre `<intro>` et `</intro>` de ce même champ.
826 * Pour les articles, l'introduction utilisée est celle du champ `descriptif`
827 * s'il est renseigné, sinon il est pris dans les champs `chapo` et `texte` et
828 * est par défaut limité à 500 caractères.
830 * Pour les rubriques, l'introduction utilisée est celle du champ `descriptif`
831 * s'il est renseigné, sinon du champ texte.
833 * La balise accèpte 1 paramètre indiquant la longueur en nombre de caractères
836 * @see filtre_introduction_dist()
844 * @link http://www.spip.net/@introduction
847 * Pile au niveau de la balise
849 * Pile complétée par le code à générer
851 function balise_INTRODUCTION_dist($p) {
853 $type = $p->type_requete
;
855 $_texte = champ_sql('texte', $p);
856 $_descriptif = ($type == 'articles' or $type == 'rubriques') ?
champ_sql('descriptif', $p) : "''";
858 if ($type == 'articles') {
859 $_chapo = champ_sql('chapo', $p);
860 $_texte = "(strlen($_descriptif))
862 : $_chapo . \"\\n\\n\" . $_texte";
865 // longueur en parametre, ou valeur par defaut
866 $longueur_defaut = objet_info($type, 'introduction_longueur');
867 if (!$longueur_defaut) {
868 $longueur_defaut = 600;
872 $_longueur = $longueur_defaut;
873 if (($v = interprete_argument_balise(1, $p)) !== null) {
874 $_longueur = 'is_numeric(' . $v . ')?intval(' . $v . '):' . $longueur_defaut;
875 $_suite = '!is_numeric(' . $v . ')?' . $v . ':null';
877 if (($v2 = interprete_argument_balise(2, $p)) !== null) {
881 $f = chercher_filtre('introduction');
882 $p->code
= "$f($_descriptif, $_texte, $_longueur, \$connect, $_suite)";
884 #$p->interdire_scripts = true;
885 $p->etoile
= '*'; // propre est deja fait dans le calcul de l'intro
891 * Compile la balise `#LANG` qui affiche la langue de l'objet (ou d'une boucle supérieure),
892 * et à defaut la langue courante
894 * La langue courante est celle du site ou celle qui a été passée dans l'URL par le visiteur.
895 * L'étoile `#LANG*` n'affiche rien si aucune langue n'est trouvée dans le SQL ou le contexte.
898 * @link http://www.spip.net/3864
901 * Pile au niveau de la balise
903 * Pile complétée par le code à générer
905 function balise_LANG_dist($p) {
906 $_lang = champ_sql('lang', $p);
908 $p->code
= "spip_htmlentities($_lang ? $_lang : \$GLOBALS['spip_lang'])";
910 $p->code
= "spip_htmlentities($_lang)";
912 $p->interdire_scripts
= false;
918 * Compile la balise `#LESAUTEURS` chargée d'afficher la liste des auteurs d'un objet
920 * - Soit le champ `lesauteurs` existe dans la table et à ce moment là,
921 * la balise retourne son contenu,
922 * - soit la balise appelle le modele `lesauteurs.html` en lui passant
923 * le couple `objet` et `id_objet` dans son environnement.
926 * @link http://www.spip.net/3966 Description de la balise
927 * @link http://www.spip.net/902 Description de la boucle ARTICLES
928 * @link http://www.spip.net/911 Description de la boucle SYNDIC_ARTICLES
931 * Pile au niveau de la balise
933 * Pile complétée par le code à générer
935 function balise_LESAUTEURS_dist($p) {
936 // Cherche le champ 'lesauteurs' dans la pile
937 $_lesauteurs = champ_sql('lesauteurs', $p, false);
939 // Si le champ n'existe pas (cas de spip_articles), on applique
940 // le modele lesauteurs.html en passant id_article dans le contexte;
941 // dans le cas contraire on prend le champ 'lesauteurs'
942 // (cf extension sites/)
944 and $_lesauteurs != '@$Pile[0][\'lesauteurs\']'
946 $p->code
= "safehtml($_lesauteurs)";
947 // $p->interdire_scripts = true;
949 if (!$p->id_boucle
) {
952 $id_table_objet = 'id_article';
954 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->id_boucle
;
955 $connect = $p->boucles
[$b]->sql_serveur
;
956 $type_boucle = $p->boucles
[$b]->type_requete
;
957 $objet = objet_type($type_boucle);
958 $id_table_objet = id_table_objet($type_boucle);
960 $c = memoriser_contexte_compil($p);
962 $p->code
= sprintf(CODE_RECUPERER_FOND
, "'modeles/lesauteurs'",
963 "array('objet'=>'" . $objet .
964 "','id_objet' => " . champ_sql($id_table_objet, $p) .
965 ",'$id_table_objet' => " . champ_sql($id_table_objet, $p) .
966 ($objet == 'article' ?
"" : ",'id_article' => " . champ_sql('id_article', $p)) .
968 "'trim'=>true, 'compil'=>array($c)",
970 $p->interdire_scripts
= false; // securite apposee par recuperer_fond()
978 * Compile la balise `#RANG` chargée d'afficher le numéro de l'objet
980 * Affiche le « numero de l'objet ». Soit `1` quand on a un titre `1. Premier article`.
982 * Ceci est transitoire afin de préparer une migration vers un vrai système de
983 * tri des articles dans une rubrique (et plus si affinités).
984 * La balise permet d'extraire le numero masqué par le filtre `supprimer_numero`.
986 * La balise recupère le champ declaré dans la définition `table_titre`
987 * de l'objet, ou à defaut du champ `titre`
989 * Si un champ `rang` existe, il est pris en priorité.
992 * @link http://www.spip.net/5495
995 * Pile au niveau de la balise
997 * Pile complétée par le code à générer
999 function balise_RANG_dist($p) {
1000 $b = index_boucle($p);
1003 'zbug_champ_hors_boucle',
1004 array('champ' => '#RANG')
1006 erreur_squelette($msg, $p);
1008 // chercher d'abord un champ sql rang (mais pas dans le env : defaut '' si on trouve pas de champ sql)
1009 // dans la boucle immediatement englobante uniquement
1010 // sinon on compose le champ calcule
1011 $_rang = champ_sql('rang', $p, '', false);
1013 // si pas trouve de champ sql rang :
1014 if (!$_rang or $_rang == "''") {
1015 $boucle = &$p->boucles
[$b];
1016 $trouver_table = charger_fonction('trouver_table', 'base');
1017 $desc = $trouver_table($boucle->id_table
);
1018 $_titre = ''; # où extraire le numero ?
1020 if (isset($desc['titre'])) {
1021 $t = $desc['titre'];
1023 // Soit on trouve avec la déclaration de la lang AVANT
1024 preg_match(';(?:lang\s*,)\s*(.*?titre)\s*(,|$);', $t, $m)
1025 // Soit on prend depuis le début
1026 or preg_match(';^(.*?titre)\s*(,|$);', $t, $m)
1028 $m = preg_replace(',as\s+titre$,i', '', $m[1]);
1031 if (!preg_match(",\W,", $m)) {
1032 $m = $boucle->id_table
. ".$m";
1035 $m .= " AS titre_rang";
1037 $boucle->select
[] = $m;
1038 $_titre = '$Pile[$SP][\'titre_rang\']';
1043 // si on n'a rien trouvé, on utilise le champ titre classique
1045 $_titre = champ_sql('titre', $p);
1048 $_rang = "recuperer_numero($_titre)";
1052 $p->interdire_scripts
= false;
1060 * Compile la balise `#POPULARITE` qui affiche la popularité relative.
1062 * C'est à dire le pourcentage de la fréquentation de l'article
1063 * (la popularité absolue) par rapport à la popularité maximum.
1066 * @link http://www.spip.net/1846 La popularité
1067 * @see balise_POPULARITE_ABSOLUE_dist()
1068 * @see balise_POPULARITE_MAX_dist()
1069 * @see balise_POPULARITE_SITE_dist()
1072 * Pile au niveau de la balise
1074 * Pile complétée par le code à générer
1076 function balise_POPULARITE_dist($p) {
1077 $_popularite = champ_sql('popularite', $p);
1078 $p->code
= "(ceil(min(100, 100 * $_popularite
1079 / max(1 , 0 + \$GLOBALS['meta']['popularite_max']))))";
1080 $p->interdire_scripts
= false;
1086 * Code de compilation pour la balise `#PAGINATION`
1088 * Le code produit est trompeur, car les modèles ne fournissent pas Pile[0].
1089 * On produit un appel à `_request` si on ne l'a pas, mais c'est inexact:
1090 * l'absence peut-être due à une faute de frappe dans le contexte inclus.
1092 define('CODE_PAGINATION',
1093 '%s($Numrows["%s"]["grand_total"],
1095 isset($Pile[0][%4$s])?$Pile[0][%4$s]:intval(_request(%4$s)),
1096 %5$s, %6$s, %7$s, %8$s, array(%9$s))');
1099 * Compile la balise `#PAGINATION` chargée d'afficher une pagination
1101 * Elle charge le modèle `pagination.html` (par défaut), mais un paramètre
1102 * permet d'indiquer d'autres modèles. `#PAGINATION{nom}` utilisera le
1103 * modèle `pagination_nom.html`.
1105 * Cette balise nécessite le critère `pagination` sur la boucle où elle
1109 * @link http://www.spip.net/3367 Le système de pagination
1110 * @see filtre_pagination_dist()
1111 * @see critere_pagination_dist()
1112 * @see balise_ANCRE_PAGINATION_dist()
1115 * [<p class="pagination">(#PAGINATION{prive})</p>]
1119 * Pile au niveau de la balise
1120 * @param string $liste
1121 * Afficher ou non les liens de pagination (variable de type `string`
1122 * car code à faire écrire au compilateur) :
1123 * - `true` pour les afficher
1124 * - `false` pour afficher uniquement l'ancre.
1126 * Pile complétée par le code à générer
1128 function balise_PAGINATION_dist($p, $liste = 'true') {
1129 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->descr
['id_mere'];
1131 // s'il n'y a pas de nom de boucle, on ne peut pas paginer
1134 'zbug_champ_hors_boucle',
1135 array('champ' => $liste ?
'PAGINATION' : 'ANCRE_PAGINATION')
1137 erreur_squelette($msg, $p);
1142 // s'il n'y a pas de mode_partie, c'est qu'on se trouve
1143 // dans un boucle recursive ou qu'on a oublie le critere {pagination}
1144 if (!$p->boucles
[$b]->mode_partie
) {
1145 if (!$p->boucles
[$b]->table_optionnelle
) {
1147 'zbug_pagination_sans_critere',
1148 array('champ' => '#PAGINATION')
1150 erreur_squelette($msg, $p);
1157 // si false, le compilo va bloquer sur des syntaxes avec un filtre sans argument qui suit la balise
1158 // si true, les arguments simples (sans truc=chose) vont degager
1159 $_contexte = argumenter_inclure($p->param
, true, $p, $p->boucles
, $p->id_boucle
, false, false);
1160 if (count($_contexte)) {
1161 $key = key($_contexte);
1162 if (is_numeric($key)) {
1163 array_shift($_contexte);
1164 $__modele = interprete_argument_balise(1, $p);
1168 if (count($_contexte)) {
1169 $code_contexte = implode(',', $_contexte);
1171 $code_contexte = '';
1174 $connect = $p->boucles
[$b]->sql_serveur
;
1175 $pas = $p->boucles
[$b]->total_parties
;
1176 $f_pagination = chercher_filtre('pagination');
1177 $type = $p->boucles
[$b]->modificateur
['debut_nom'];
1178 $modif = ($type[0] !== "'") ?
"'debut'.$type"
1179 : ("'debut" . substr($type, 1));
1181 $p->code
= sprintf(CODE_PAGINATION
, $f_pagination, $b, $type, $modif, $pas, $liste,
1182 ((isset($__modele) and $__modele) ?
$__modele : "''"), _q($connect), $code_contexte);
1184 $p->boucles
[$b]->numrows
= true;
1185 $p->interdire_scripts
= false;
1192 * Compile la balise `#ANCRE_PAGINATION` chargée d'afficher l'ancre
1195 * Cette ancre peut ainsi être placée au-dessus la liste des éléments
1196 * de la boucle alors qu'on mettra les liens de pagination en-dessous de
1197 * cette liste paginée.
1199 * Cette balise nécessite le critère `pagination` sur la boucle où elle
1203 * @link http://www.spip.net/3367 Le système de pagination
1204 * @link http://www.spip.net/4328 Balise ANCRE_PAGINATION
1205 * @see critere_pagination_dist()
1206 * @see balise_PAGINATION_dist()
1209 * Pile au niveau de la balise
1211 * Pile complétée par le code à générer
1213 function balise_ANCRE_PAGINATION_dist($p) {
1214 if ($f = charger_fonction('PAGINATION', 'balise', true)) {
1215 return $f($p, $liste = 'false');
1218 } // ou une erreur ?
1223 * Compile la balise `#GRAND_TOTAL` qui retourne le nombre total de résultats
1226 * Cette balise set équivalente à `#TOTAL_BOUCLE` sauf pour les boucles paginées.
1227 * Dans ce cas elle indique le nombre total d'éléments répondant aux critères
1231 * @see balise_GRAND_TOTAL_dist()
1234 * Pile au niveau de la balise
1236 * Pile complétée par le code à générer
1238 function balise_GRAND_TOTAL_dist($p) {
1239 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->descr
['id_mere'];
1240 if ($b === '' ||
!isset($p->boucles
[$b])) {
1242 'zbug_champ_hors_boucle',
1243 array('champ' => "#$b" . 'TOTAL_BOUCLE')
1245 erreur_squelette($msg, $p);
1247 $p->code
= "(isset(\$Numrows['$b']['grand_total'])
1248 ? \$Numrows['$b']['grand_total'] : \$Numrows['$b']['total'])";
1249 $p->boucles
[$b]->numrows
= true;
1250 $p->interdire_scripts
= false;
1258 * Compile la balise `#SELF` qui retourne l’URL de la page appelée.
1260 * Cette URL est nettoyée des variables propres à l’exécution de SPIP
1261 * tel que `var_mode`.
1264 * Attention dans un `INCLURE()` ou une balise dynamique, on n'a pas le droit de
1265 * mettre en cache `#SELF` car il peut correspondre à une autre page (attaque XSS)
1266 * (Dans ce cas faire <INCLURE{self=#SELF}> pour différencier les caches.)
1269 * @link http://www.spip.net/4574
1272 * <a href="[(#SELF|parametre_url{id_mot,#ID_MOT})]">...
1276 * Pile au niveau de la balise
1278 * Pile complétée par le code à générer
1280 function balise_SELF_dist($p) {
1281 $p->code
= 'self()';
1282 $p->interdire_scripts
= false;
1289 * Compile la balise `#CHEMIN` qui cherche un fichier dans les chemins
1290 * connus de SPIP et retourne son chemin complet depuis la racine
1292 * Signature : `#CHEMIN{chemin/vers/fichier.ext}`
1294 * Retourne une chaîne vide si le fichier n'est pas trouvé.
1297 * @link http://www.spip.net/4332
1298 * @see find_in_path() Recherche de chemin
1301 * [<script type="text/javascript" src="(#CHEMIN{javascript/jquery.flot.js})"></script>]
1302 * [<link rel="stylesheet" href="(#CHEMIN{css/perso.css}|direction_css)" type="text/css" />]
1306 * Pile au niveau de la balise
1308 * Pile complétée par le code à générer
1310 function balise_CHEMIN_dist($p) {
1311 $arg = interprete_argument_balise(1, $p);
1313 $msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN'));
1314 erreur_squelette($msg, $p);
1316 $p->code
= 'find_in_path(' . $arg . ')';
1319 $p->interdire_scripts
= false;
1325 * Compile la balise `#CHEMIN_IMAGE` qui cherche une image dans le thème
1326 * de l'espace privé utilisé par SPIP et retourne son chemin complet depuis
1329 * Signature : `#CHEMIN_IMAGE{image.png}`
1331 * Retourne une chaîne vide si le fichier n'est pas trouvé.
1334 * @see chemin_image()
1337 * #CHEMIN_IMAGE{article-24.png}
1341 * Pile au niveau de la balise
1343 * Pile complétée par le code à générer
1345 function balise_CHEMIN_IMAGE_dist($p) {
1346 $arg = interprete_argument_balise(1, $p);
1348 $msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN_IMAGE'));
1349 erreur_squelette($msg, $p);
1351 $p->code
= 'chemin_image(' . $arg . ')';
1354 #$p->interdire_scripts = true;
1360 * Compile la balise `#ENV` qui permet de récupérer le contexte d'environnement
1361 * transmis à un squelette.
1363 * La syntaxe `#ENV{toto, valeur par defaut}`
1364 * renverra `valeur par defaut` si `$toto` est vide.
1366 * La recherche de la clé s'appuyant sur la fonction `table_valeur`
1367 * il est possible de demander un sous élément d'un tableau :
1368 * `#ENV{toto/sous/element, valeur par defaut}` retournera l'équivalent de
1369 * `#ENV{toto}|table_valeur{sous/element}` c'est-à-dire en quelque sorte
1370 * `$env['toto']['sous']['element']` s'il existe, sinon la valeur par défaut.
1372 * Si le tableau est vide on renvoie `''` (utile pour `#SESSION`)
1374 * Enfin, la balise utilisée seule `#ENV` retourne le tableau complet
1375 * de l'environnement. À noter que ce tableau est retourné sérialisé.
1377 * En standard est appliqué le filtre `entites_html`, mais si l'étoile est
1378 * utilisée pour désactiver les filtres par défaut, par exemple avec
1379 * `[(#ENV*{toto})]` , il *faut* s'assurer de la sécurité
1380 * anti-javascript, par exemple en filtrant avec `safehtml` : `[(#ENV*{toto}|safehtml)]`
1384 * Pile ; arbre de syntaxe abstrait positionné au niveau de la balise.
1386 * Tableau dans lequel chercher la clé demandée en paramètre de la balise.
1387 * Par defaut prend dans le contexte du squelette.
1389 * Pile completée du code PHP d'exécution de la balise
1391 function balise_ENV_dist($p, $src = null) {
1393 // cle du tableau desiree
1394 $_nom = interprete_argument_balise(1, $p);
1395 // valeur par defaut
1396 $_sinon = interprete_argument_balise(2, $p);
1398 // $src est un tableau de donnees sources eventuellement transmis
1399 // en absence, on utilise l'environnement du squelette $Pile[0]
1402 // cas de #ENV sans argument : on retourne le serialize() du tableau
1403 // une belle fonction [(#ENV|affiche_env)] serait pratique
1405 $p->code
= '(is_array($a = (' . $src . ')) ? serialize($a) : "")';
1407 $p->code
= '@serialize($Pile[0])';
1414 $p->code
= "sinon(table_valeur($src, (string)$_nom, null), $_sinon)";
1416 $p->code
= "table_valeur($src, (string)$_nom, null)";
1420 #$p->interdire_scripts = true;
1426 * Compile la balise `#CONFIG` qui retourne une valeur de configuration
1428 * Cette balise appelle la fonction `lire_config()` pour obtenir les
1429 * configurations du site.
1431 * Par exemple `#CONFIG{gerer_trad}` donne 'oui ou 'non' selon le réglage.
1433 * Le 3ème argument permet de contrôler la sérialisation du résultat
1434 * (mais ne sert que pour le dépot `meta`) qui doit parfois désérialiser,
1435 * par exemple avec `|in_array{#CONFIG{toto,#ARRAY,1}}`. Ceci n'affecte
1436 * pas d'autres dépots et `|in_array{#CONFIG{toto/,#ARRAY}}` sera
1439 * Òn peut appeler d'autres tables que `spip_meta` avec un
1440 * `#CONFIG{/infos/champ,defaut}` qui lit la valeur de `champ`
1441 * dans une table des meta qui serait `spip_infos`
1444 * @link http://www.spip.net/4335
1447 * Pile au niveau de la balise.
1449 * Pile completée du code PHP d'exécution de la balise
1451 function balise_CONFIG_dist($p) {
1452 if (!$arg = interprete_argument_balise(1, $p)) {
1455 $_sinon = interprete_argument_balise(2, $p);
1456 $_unserialize = sinon(interprete_argument_balise(3, $p), "false");
1458 $p->code
= '(include_spip(\'inc/config\')?lire_config(' . $arg . ',' .
1459 ($_sinon && $_sinon != "''" ?
$_sinon : 'null') . ',' . $_unserialize . "):'')";
1466 * Compile la balise `#CONNECT` qui retourne le nom du connecteur
1467 * de base de données
1469 * Retourne le nom du connecteur de base de données utilisé (le nom
1470 * du fichier `config/xx.php` sans l'extension, utilisé pour calculer
1471 * les données du squelette).
1473 * Retourne `NULL` si le connecteur utilisé est celui par défaut de SPIP
1474 * (connect.php), sinon retourne son nom.
1479 * Pile au niveau de la balise.
1481 * Pile completée du code PHP d'exécution de la balise
1483 function balise_CONNECT_dist($p) {
1484 $p->code
= '($connect ? $connect : NULL)';
1485 $p->interdire_scripts
= false;
1492 * Compile la balise `#SESSION` qui permet d’accéder aux informations
1493 * liées au visiteur authentifié et de différencier automatiquement
1494 * le cache en fonction du visiteur.
1496 * Cette balise est un tableau des données du visiteur (nom, email etc).
1497 * Si elle est invoquée, elle lève un drapeau dans le fichier cache, qui
1498 * permet à public/cacher de créer un cache différent par visiteur
1501 * @link http://www.spip.net/3979
1502 * @see balise_AUTORISER_dist()
1503 * @see balise_SESSION_SET_dist()
1510 * Pile au niveau de la balise.
1512 * Pile completée du code PHP d'exécution de la balise
1514 function balise_SESSION_dist($p) {
1515 $p->descr
['session'] = true;
1517 $f = function_exists('balise_ENV')
1519 : 'balise_ENV_dist';
1521 $p = $f($p, '$GLOBALS["visiteur_session"]');
1528 * Compile la balise `#SESSION_SET` qui d’insérer dans la session
1529 * des données supplémentaires
1532 * @link http://www.spip.net/3984
1533 * @see balise_AUTORISER_dist()
1534 * @see balise_SESSION_SET_dist()
1537 * #SESSION_SET{x,y} ajoute x=y dans la session du visiteur
1541 * Pile au niveau de la balise.
1543 * Pile completée du code PHP d'exécution de la balise
1545 function balise_SESSION_SET_dist($p) {
1546 $_nom = interprete_argument_balise(1, $p);
1547 $_val = interprete_argument_balise(2, $p);
1548 if (!$_nom or !$_val) {
1549 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SESSION_SET'));
1550 erreur_squelette($err_b_s_a, $p);
1552 $p->code
= '(include_spip("inc/session") AND session_set(' . $_nom . ',' . $_val . '))';
1555 $p->interdire_scripts
= false;
1562 * Compile la balise `#EVAL` qui évalue un code PHP
1564 * À utiliser avec précautions !
1567 * @link http://www.spip.net/4587
1571 * #EVAL{'date("Y-m-d")'}
1572 * #EVAL{$_SERVER['REQUEST_URI']}
1573 * #EVAL{'str_replace("r","z", "roger")'} (attention les "'" sont interdits)
1577 * `#EVAL{code}` produit `eval('return code;')`
1578 * mais si le code est une expression sans balise, on se dispense
1579 * de passer par une construction si compliquée, et le code est
1580 * passé tel quel (entre parenthèses, et protégé par interdire_scripts)
1583 * Pile au niveau de la balise.
1585 * Pile completée du code PHP d'exécution de la balise
1587 function balise_EVAL_dist($p) {
1588 $php = interprete_argument_balise(1, $p);
1590 # optimisation sur les #EVAL{une expression sans #BALISE}
1591 # attention au commentaire "// x signes" qui precede
1592 if (preg_match(",^([[:space:]]*//[^\n]*\n)'([^']+)'$,ms",
1594 $p->code
= /* $r[1]. */
1597 $p->code
= "eval('return '.$php.';')";
1600 $msg = array('zbug_balise_sans_argument', array('balise' => ' EVAL'));
1601 erreur_squelette($msg, $p);
1604 #$p->interdire_scripts = true;
1611 * Compile la balise `#CHAMP_SQL` qui renvoie la valeur d'un champ SQL
1613 * Signature : `#CHAMP_SQL{champ}`
1615 * Cette balise permet de récupérer par exemple un champ `notes` dans une table
1616 * SQL externe (impossible avec la balise `#NOTES` qui est une balise calculée).
1618 * Ne permet pas de passer une expression comme argument, qui ne peut
1619 * être qu'un texte statique !
1622 * @link http://www.spip.net/4041
1630 * Pile au niveau de la balise
1632 * Pile complétée par le code à générer
1634 function balise_CHAMP_SQL_dist($p) {
1637 and isset($p->param
[0][1][0])
1638 and $champ = ($p->param
[0][1][0]->texte
)
1640 $p->code
= champ_sql($champ, $p);
1642 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => ' CHAMP_SQL'));
1643 erreur_squelette($err_b_s_a, $p);
1646 #$p->interdire_scripts = true;
1651 * Compile la balise `#VAL` qui retourne simplement le premier argument
1652 * qui lui est transmis
1654 * Cela permet d'appliquer un filtre à une chaîne de caractère
1657 * @link http://www.spip.net/4026
1661 * #VAL{x} retourne 'x'
1662 * #VAL{1,2} renvoie '1' (2 est considéré comme un autre paramètre)
1663 * #VAL{'1,2'} renvoie '1,2'
1664 * [(#VAL{a_suivre}|bouton_spip_rss)]
1668 * Pile au niveau de la balise
1670 * Pile complétée par le code à générer
1672 function balise_VAL_dist($p) {
1673 $p->code
= interprete_argument_balise(1, $p);
1674 if (!strlen($p->code
)) {
1677 $p->interdire_scripts
= false;
1683 * Compile la balise `#NOOP`, alias (déprécié) de `#VAL`
1685 * Alias pour regler #948. Ne plus utiliser.
1688 * @see balise_VAL_dist()
1689 * @deprecated Utiliser #VAL
1692 * Pile au niveau de la balise
1694 * Pile complétée par le code à générer
1696 function balise_NOOP_dist($p) { return balise_VAL_dist($p); }
1700 * Compile la balise `#REM` servant à commenter du texte
1702 * Retourne toujours une chaîne vide.
1705 * @link http://www.spip.net/4578
1709 * Ceci est une remarque ou un commentaire,
1710 * non affiché dans le code généré
1715 * La balise `#REM` n'empêche pas l'exécution des balises SPIP contenues
1716 * dedans (elle ne sert pas à commenter du code pour empêcher son
1720 * Pile au niveau de la balise
1722 * Pile complétée par le code à générer
1724 function balise_REM_dist($p) {
1726 $p->interdire_scripts
= false;
1732 * Une balise #NULL quand on a besoin de passer un argument null sur l'appel d'un filtre ou formulaire
1733 * (evite un #EVAL{null})
1737 function balise_NULL_dist($p) {
1739 $p->interdire_scripts
= false;
1746 * Compile la balise `#HTTP_HEADER` envoyant des entêtes de retour HTTP
1748 * Doit être placée en tête de fichier et ne fonctionne pas dans une
1752 * @link http://www.spip.net/4631
1755 * #HTTP_HEADER{Content-Type: text/csv; charset=#CHARSET}
1759 * Pile au niveau de la balise
1761 * Pile complétée par le code à générer
1763 function balise_HTTP_HEADER_dist($p) {
1765 $header = interprete_argument_balise(1, $p);
1767 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'HTTP_HEADER'));
1768 erreur_squelette($err_b_s_a, $p);
1770 $p->code
= "'<'.'?php header(' . _q("
1774 $p->interdire_scripts
= false;
1781 * Compile la balise `#FILTRE` qui exécute un filtre à l'ensemble du squelette
1784 * Le filtrage se fait au niveau du squelette, sans s'appliquer aux `<INCLURE>`.
1785 * Plusieurs filtres peuvent être indiqués, séparés par des barres verticales `|`
1788 * @link http://www.spip.net/4894
1791 * #FILTRE{compacte_head}
1792 * #FILTRE{supprimer_tags|filtrer_entites|trim}
1796 * Pile au niveau de la balise
1798 * Pile complétée par le code à générer
1800 function balise_FILTRE_dist($p) {
1803 foreach ($p->param
as $i => $ignore) {
1804 $args[] = interprete_argument_balise($i +
1, $p);
1806 $p->code
= "'<' . '"
1807 . '?php header("X-Spip-Filtre: \'.'
1808 . join('.\'|\'.', $args)
1809 . " . '\"); ?'.'>'";
1811 $p->interdire_scripts
= false;
1819 * Compile la balise `#CACHE` definissant la durée de validité du cache du squelette
1821 * Signature : `#CACHE{duree[,type]}`
1823 * Le premier argument est la durée en seconde du cache. Le second
1824 * (par défaut `statique`) indique le type de cache :
1826 * - `cache-client` autorise gestion du IF_MODIFIED_SINCE
1827 * - `statique` ne respecte pas l'invalidation par modif de la base
1828 * (mais s'invalide tout de même à l'expiration du delai)
1831 * @see ecrire/public/cacher.php
1832 * @link http://www.spip.net/4330
1836 * #CACHE{24*3600, cache-client}
1837 * #CACHE{0} pas de cache
1840 * En absence de cette balise la durée est du cache est donné
1841 * par la constante `_DUREE_CACHE_DEFAUT`
1844 * Pile au niveau de la balise
1846 * Pile complétée par le code à générer
1848 function balise_CACHE_dist($p) {
1851 $duree = valeur_numerique($p->param
[0][1][0]->texte
);
1853 // noter la duree du cache dans un entete proprietaire
1855 $code = "'<'.'" . '?php header("X-Spip-Cache: '
1857 . '"); ?' . "'.'>'";
1859 // Remplir le header Cache-Control
1863 . '?php header("Cache-Control: no-cache, must-revalidate"); ?'
1865 . '?php header("Pragma: no-cache"); ?'
1869 // recuperer les parametres suivants
1871 while (isset($p->param
[0][++
$i])) {
1872 $pa = ($p->param
[0][$i][0]->texte
);
1874 if ($pa == 'cache-client'
1877 $code .= ".'<'.'" . '?php header("Cache-Control: max-age='
1879 . '"); ?' . "'.'>'";
1880 // il semble logique, si on cache-client, de ne pas invalider
1884 if ($pa == 'statique'
1887 $code .= ".'<'.'" . '?php header("X-Spip-Statique: oui"); ?' . "'.'>'";
1894 $p->interdire_scripts
= false;
1901 * Compile la balise `#INSERT_HEAD` permettant d'insérer du contenu dans
1902 * le `<head>` d'une page HTML
1904 * La balise permet aux plugins d'insérer des styles, js ou autre
1905 * dans l'entête sans modification du squelette.
1906 * Les css doivent être inserées de préférence par `#INSERT_HEAD_CSS`
1907 * pour en faciliter la surcharge.
1909 * On insère ici aussi un morceau de PHP qui verifiera à l'exécution
1910 * que le pipeline `insert_head_css` a bien été vu
1911 * et dans le cas contraire l'appelera. Ceal permet de ne pas oublier
1912 * les css de `#INSERT_HEAD_CSS` même si cette balise n'est pas presente.
1914 * Il faut mettre ce php avant le `insert_head` car le compresseur y mets
1915 * ensuite un php du meme type pour collecter
1916 * CSS et JS, et on ne veut pas qu'il rate les css insérées en fallback
1917 * par `insert_head_css_conditionnel`.
1919 * @link http://www.spip.net/4629
1920 * @see balise_INSERT_HEAD_CSS_dist()
1923 * Pile au niveau de la balise
1925 * Pile complétée par le code à générer
1927 function balise_INSERT_HEAD_dist($p) {
1929 . '?php header("X-Spip-Filtre: insert_head_css_conditionnel"); ?'
1931 $p->code
.= ". pipeline('insert_head','<!-- insert_head -->')";
1932 $p->interdire_scripts
= false;
1938 * Compile la balise `#INSERT_HEAD_CSS` homologue de `#INSERT_HEAD` pour les CSS
1940 * Et par extension pour le JS inline qui doit préférentiellement
1941 * être inséré avant les CSS car bloquant sinon.
1943 * @link http://www.spip.net/4605
1944 * @see balise_INSERT_HEAD_dist()
1947 * Pile au niveau de la balise
1949 * Pile complétée par le code à générer
1951 function balise_INSERT_HEAD_CSS_dist($p) {
1952 $p->code
= "pipeline('insert_head_css','<!-- insert_head_css -->')";
1953 $p->interdire_scripts
= false;
1959 * Compile la balise `#INCLUDE` alias de `#INCLURE`
1962 * @see balise_INCLURE_dist()
1965 * Pile au niveau de la balise
1967 * Pile complétée par le code à générer
1969 function balise_INCLUDE_dist($p) {
1970 if (function_exists('balise_INCLURE')) {
1971 return balise_INCLURE($p);
1973 return balise_INCLURE_dist($p);
1978 * Compile la balise `#INCLURE` qui inclut un résultat de squelette
1980 * Signature : `[(#INCLURE{fond=nom_du_squelette, argument, argument=xx})]`
1982 * L'argument `env` permet de transmettre tout l'environnement du squelette
1983 * en cours au squelette inclus.
1985 * On parle d’inclusion « statique » car le résultat de compilation est
1986 * ajouté au squelette en cours, dans le même fichier de cache.
1987 * Cette balise est donc différente d’une inclusion « dynamique » avec
1988 * `<INCLURE.../>` qui, elle, crée un fichier de cache séparé
1989 * (avec une durée de cache qui lui est propre).
1991 * L'inclusion est realisée au calcul du squelette, pas au service
1992 * ainsi le produit du squelette peut être utilisé en entrée de filtres
1993 * à suivre. On peut faire un `#INCLURE{fichier}` sans squelette
1994 * (Incompatible avec les balises dynamiques).
1999 * [(#INCLURE{fond=inclure/documents,id_article, env})]
2003 * Pile au niveau de la balise
2005 * Pile complétée par le code à générer
2007 function balise_INCLURE_dist($p) {
2008 $id_boucle = $p->id_boucle
;
2009 // la lang n'est pas passe de facon automatique par argumenter
2010 // mais le sera pas recuperer_fond, sauf si etoile=>true est passe
2013 $_contexte = argumenter_inclure($p->param
, true, $p, $p->boucles
, $id_boucle, false, false);
2015 // erreur de syntaxe = fond absent
2016 // (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
2018 $contexte = array();
2021 if (isset($_contexte['fond'])) {
2023 $f = $_contexte['fond'];
2025 if (preg_match('/^.fond.\s*=>(.*)$/s', $f, $r)) {
2027 unset($_contexte['fond']);
2029 spip_log("compilation de #INCLURE a revoir");
2032 // #INCLURE{doublons}
2033 if (isset($_contexte['doublons'])) {
2034 $_contexte['doublons'] = "'doublons' => \$doublons";
2037 // Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
2039 if (isset($_contexte['env']) or isset($_contexte['self'])) {
2041 unset($_contexte['env']);
2044 $_options = array();
2045 if (isset($_contexte['ajax'])) {
2046 $_options[] = preg_replace(",=>(.*)$,ims", '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
2047 unset($_contexte['ajax']);
2050 $_options[] = "'etoile'=>true";
2052 $_options[] = "'compil'=>array(" . memoriser_contexte_compil($p) . ")";
2054 $_l = 'array(' . join(",\n\t", $_contexte) . ')';
2056 $_l = "array_merge(\$Pile[0],$_l)";
2059 $p->code
= sprintf(CODE_RECUPERER_FOND
, $f, $_l, join(',', $_options), "_request('connect')");
2061 } elseif (!isset($_contexte[1])) {
2062 $msg = array('zbug_balise_sans_argument', array('balise' => ' INCLURE'));
2063 erreur_squelette($msg, $p);
2065 $p->code
= 'charge_scripts(' . $_contexte[1] . ',false)';
2068 $p->interdire_scripts
= false; // la securite est assuree par recuperer_fond
2074 * Compile la balise `#MODELE` qui inclut un résultat de squelette de modèle
2076 * `#MODELE{nom}` insère le résultat d’un squelette contenu dans le
2077 * répertoire `modeles/`. L’identifiant de la boucle parente est transmis
2078 * par défaut avec le paramètre `id` à cette inclusion.
2080 * Des arguments supplémentaires peuvent être transmis :
2081 * `[(#MODELE{nom, argument=xx, argument})]`
2084 * @see balise_INCLURE_dist()
2087 * #MODELE{article_traductions}
2091 * Pile au niveau de la balise
2093 * Pile complétée par le code à générer
2095 function balise_MODELE_dist($p) {
2097 $_contexte = argumenter_inclure($p->param
, true, $p, $p->boucles
, $p->id_boucle
, false);
2099 // erreur de syntaxe = fond absent
2100 // (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
2102 $contexte = array();
2105 if (!isset($_contexte[1])) {
2106 $msg = array('zbug_balise_sans_argument', array('balise' => ' MODELE'));
2107 erreur_squelette($msg, $p);
2109 $nom = $_contexte[1];
2110 unset($_contexte[1]);
2112 if (preg_match("/^\s*'[^']*'/s", $nom)) {
2113 $nom = "'modeles/" . substr($nom, 1);
2115 $nom = "'modeles/' . $nom";
2119 if (isset($_contexte['env'])) {
2121 unset($_contexte['env']);
2124 // Incoherence dans la syntaxe du contexte. A revoir.
2125 // Reserver la cle primaire de la boucle courante si elle existe
2126 if (isset($p->boucles
[$p->id_boucle
]->primary
)) {
2127 $primary = $p->boucles
[$p->id_boucle
]->primary
;
2128 if (!strpos($primary, ',')) {
2129 $id = champ_sql($primary, $p);
2130 $_contexte[] = "'$primary'=>" . $id;
2131 $_contexte[] = "'id'=>" . $id;
2134 $_contexte[] = "'recurs'=>(++\$recurs)";
2136 if (isset($p->boucles
[$p->id_boucle
])) {
2137 $connect = $p->boucles
[$p->id_boucle
]->sql_serveur
;
2140 $_options = memoriser_contexte_compil($p);
2141 $_options = "'compil'=>array($_options), 'trim'=>true";
2142 if (isset($_contexte['ajax'])) {
2143 $_options .= ", " . preg_replace(",=>(.*)$,ims", '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
2144 unset($_contexte['ajax']);
2147 $_l = 'array(' . join(",\n\t", $_contexte) . ')';
2149 $_l = "array_merge(\$Pile[0],$_l)";
2152 $page = sprintf(CODE_RECUPERER_FOND
, $nom, $_l, $_options, _q($connect));
2154 $p->code
= "\n\t(((\$recurs=(isset(\$Pile[0]['recurs'])?\$Pile[0]['recurs']:0))>=5)? '' :\n\t$page)\n";
2156 $p->interdire_scripts
= false; // securite assuree par le squelette
2164 * Compile la balise `#SET` qui affecte une variable locale au squelette
2166 * Signature : `#SET{cle,valeur}`
2169 * @link http://www.spip.net/3990 Balises #SET et #GET
2170 * @see balise_GET_dist()
2174 * #GET{nb} // affiche 5
2178 * Pile au niveau de la balise
2180 * Pile complétée par le code à générer
2182 function balise_SET_dist($p) {
2183 $_nom = interprete_argument_balise(1, $p);
2184 $_val = interprete_argument_balise(2, $p);
2186 if (!$_nom or !$_val) {
2187 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SET'));
2188 erreur_squelette($err_b_s_a, $p);
2190 // affectation $_zzz inutile, mais permet de contourner un bug OpCode cache sous PHP 5.5.4
2191 // cf https://bugs.php.net/bug.php?id=65845
2193 $p->code
= "vide(\$Pile['vars'][\$_zzz=(string)$_nom] = $_val)";
2196 $p->interdire_scripts
= false; // la balise ne renvoie rien
2202 * Compile la balise `#GET` qui récupère une variable locale au squelette
2204 * Signature : `#GET{cle[,defaut]}`
2206 * La clé peut obtenir des sous clés séparés par des `/`
2209 * @link http://www.spip.net/3990 Balises #SET et #GET
2210 * @see balise_SET_dist()
2214 * #GET{nb} affiche 5
2215 * #GET{nb,3} affiche la valeur de nb, sinon 3
2217 * #SET{nb,#ARRAY{boucles,3}}
2218 * #GET{nb/boucles} affiche 3, équivalent à #GET{nb}|table_valeur{boucles}
2222 * Pile au niveau de la balise
2224 * Pile complétée par le code à générer
2226 function balise_GET_dist($p) {
2227 $p->interdire_scripts
= false; // le contenu vient de #SET, donc il est de confiance
2228 if (function_exists('balise_ENV')) {
2229 return balise_ENV($p, '$Pile["vars"]');
2231 return balise_ENV_dist($p, '$Pile["vars"]');
2237 * Compile la balise `#DOUBLONS` qui redonne les doublons enregistrés
2239 * - `#DOUBLONS{mots}` ou `#DOUBLONS{mots,famille}`
2240 * donne l'état des doublons `(MOTS)` à cet endroit
2241 * sous forme de tableau d'id_mot comme `array(1,2,3,...)`
2242 * - `#DOUBLONS` tout seul donne la liste brute de tous les doublons
2243 * - `#DOUBLONS*{mots}` donne la chaine brute `,1,2,3,...`
2244 * (changera si la gestion des doublons evolue)
2247 * @link http://www.spip.net/4123
2250 * Pile au niveau de la balise
2252 * Pile complétée par le code à générer
2254 function balise_DOUBLONS_dist($p) {
2255 if ($type = interprete_argument_balise(1, $p)) {
2256 if ($famille = interprete_argument_balise(2, $p)) {
2257 $type .= '.' . $famille;
2259 $p->code
= '(isset($doublons[' . $type . ']) ? $doublons[' . $type . '] : "")';
2261 $p->code
= 'array_filter(array_map("intval",explode(",",'
2265 $p->code
= '$doublons';
2268 $p->interdire_scripts
= false;
2275 * Compile la balise `#PIPELINE` pour permettre d'insérer des sorties de
2276 * pipeline dans un squelette
2283 * #PIPELINE{nom,données}
2284 * #PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{type,rubrique,id,#ENV{id_rubrique}}}}
2288 * Pile au niveau de la balise
2290 * Pile complétée par le code à générer
2292 function balise_PIPELINE_dist($p) {
2293 $_pipe = interprete_argument_balise(1, $p);
2295 $err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'PIPELINE'));
2296 erreur_squelette($err_b_s_a, $p);
2298 $_flux = interprete_argument_balise(2, $p);
2299 $_flux = $_flux ?
$_flux : "''";
2300 $p->code
= "pipeline( $_pipe , $_flux )";
2301 $p->interdire_scripts
= false;
2309 * Compile la balise `#EDIT` qui ne fait rien dans SPIP
2311 * Cette balise ne retourne rien mais permet d'indiquer, pour certains plugins
2312 * qui redéfinissent cette balise, le nom du champ SQL (ou le nom d'un contrôleur)
2313 * correspondant à ce qui est édité. Cela sert particulièrement au plugin Crayons.
2314 * Ainsi en absence du plugin, la balise est toujours reconnue (mais n'a aucune action).
2317 * @link http://www.spip.net/4584
2320 * [<div class="#EDIT{texte} texte">(#TEXTE)</div>]
2324 * Pile au niveau de la balise
2326 * Pile complétée par le code à générer
2328 function balise_EDIT_dist($p) {
2330 $p->interdire_scripts
= false;
2337 * Compile la balise `#TOTAL_UNIQUE` qui récupère le nombre d'éléments
2338 * différents affichés par le filtre `unique`
2341 * @link http://www.spip.net/4374
2345 * #TOTAL_UNIQUE affiche le nombre de #BALISE|unique
2346 * #TOTAL_UNIQUE{famille} afiche le nombre de #BALISE|unique{famille}
2350 * Pile au niveau de la balise
2352 * Pile complétée par le code à générer
2354 function balise_TOTAL_UNIQUE_dist($p) {
2355 $_famille = interprete_argument_balise(1, $p);
2356 $_famille = $_famille ?
$_famille : "''";
2357 $p->code
= "unique('', $_famille, true)";
2363 * Compile la balise `#ARRAY` créant un tableau PHP associatif
2365 * Crée un `array` PHP à partir d'arguments calculés.
2366 * Chaque paire d'arguments représente la clé et la valeur du tableau.
2369 * @link http://www.spip.net/4009
2372 * #ARRAY{key1,val1,key2,val2 ...} retourne
2373 * array( key1 => val1, key2 => val2, ...)
2377 * Pile au niveau de la balise
2379 * Pile complétée par le code à générer
2381 function balise_ARRAY_dist($p) {
2385 $_key = interprete_argument_balise($n++
, $p);
2386 $_val = interprete_argument_balise($n++
, $p);
2387 if ($_key and $_val) {
2388 $_code[] = "$_key => $_val";
2390 } while ($_key && $_val);
2391 $p->code
= 'array(' . join(', ', $_code) . ')';
2392 $p->interdire_scripts
= false;
2398 * Compile la balise `#LISTE` qui crée un tableau PHP avec les valeurs, sans préciser les clés
2401 * @link http://www.spip.net/5547
2408 * Pile au niveau de la balise
2410 * Pile complétée par le code à générer
2412 function balise_LISTE_dist($p) {
2415 while ($_val = interprete_argument_balise($n++
, $p)) {
2418 $p->code
= 'array(' . join(', ', $_code) . ')';
2419 $p->interdire_scripts
= false;
2426 * Compile la balise `#AUTORISER` qui teste une autorisation
2428 * Appelle la fonction `autoriser()` avec les mêmes arguments,
2429 * et renvoie un espace ' ' si OK (l'action est autorisée),
2430 * sinon une chaine vide '' (l'action n'est pas autorisée).
2432 * Cette balise créée un cache par session.
2434 * Signature : `#AUTORISER{faire[,type[,id[,auteur[,options]]]}`
2437 * La priorité des opérateurs exige && plutot que AND
2440 * @link http://www.spip.net/3896
2442 * @see sinon_interdire_acces()
2445 * [(#AUTORISER{modifier,rubrique,#ID_RUBRIQUE}) ... ]
2446 * [(#AUTORISER{voir,rubrique,#ID_RUBRIQUE}|sinon_interdire_acces)]
2450 * Pile au niveau de la balise
2452 * Pile complétée par le code à générer
2454 function balise_AUTORISER_dist($p) {
2456 $p->descr
['session'] = true; // faire un cache par session
2459 while ($_v = interprete_argument_balise($n++
, $p)) {
2463 $p->code
= '((function_exists("autoriser")||include_spip("inc/autoriser"))&&autoriser(' . join(', ',
2464 $_code) . ')?" ":"")';
2465 $p->interdire_scripts
= false;
2472 * Compile la balise `#PLUGIN` qui permet d’afficher les informations d'un plugin actif
2475 * @see filtre_info_plugin_dist()
2476 * @link http://www.spip.net/4591
2479 * #PLUGIN Retourne la liste sérialisée des préfixes de plugins actifs
2480 * #PLUGIN{prefixe} Renvoie true si le plugin avec ce préfixe est actif
2481 * #PLUGIN{prefixe, x} Renvoie l'information x du plugin (s'il est actif)
2482 * #PLUGIN{prefixe, tout} Renvoie toutes les informations du plugin (s'il est actif)
2486 * Pile au niveau de la balise
2488 * Pile complétée par le code à générer
2490 function balise_PLUGIN_dist($p) {
2491 $plugin = interprete_argument_balise(1, $p);
2492 $plugin = isset($plugin) ?
str_replace('\'', '"', $plugin) : '""';
2493 $type_info = interprete_argument_balise(2, $p);
2494 $type_info = isset($type_info) ?
str_replace('\'', '"', $type_info) : '"est_actif"';
2496 $f = chercher_filtre('info_plugin');
2497 $p->code
= $f . '(' . $plugin . ', ' . $type_info . ')';
2503 * Compile la balise `#AIDER` qui permet d’afficher l’icone de l’aide
2504 * au sein des squelettes.
2507 * @see inc_aide_dist()
2508 * @link http://www.spip.net/4733
2515 * Pile au niveau de la balise
2517 * Pile complétée par le code à générer
2519 function balise_AIDER_dist($p) {
2520 $_motif = interprete_argument_balise(1, $p);
2521 $s = "'" . addslashes($p->descr
['sourcefile']) . "'";
2522 $p->code
= "((\$aider=charger_fonction('aide','inc',true))?\$aider($_motif,$s, \$Pile[0]):'')";
2528 * Compile la balise `#ACTION_FORMULAIRE` qui insère le contexte
2529 * des formulaires charger / vérifier / traiter avec les hidden de
2532 * Accèpte 2 arguments optionnels :
2533 * - L'url de l'action (par défaut `#ENV{action}`
2534 * - Le nom du formulaire (par défaut `#ENV{form}`
2537 * @see form_hidden()
2540 * <form method='post' action='#ENV{action}'><div>
2541 * #ACTION_FORMULAIRE
2545 * Pile au niveau de la balise
2547 * Pile complétée par le code à générer
2549 function balise_ACTION_FORMULAIRE($p) {
2550 if (!$_url = interprete_argument_balise(1, $p)) {
2551 $_url = "@\$Pile[0]['action']";
2553 if (!$_form = interprete_argument_balise(2, $p)) {
2554 $_form = "@\$Pile[0]['form']";
2557 // envoyer le nom du formulaire que l'on traite
2558 // transmettre les eventuels args de la balise formulaire
2559 $p->code
= " '<div>' .
2560 form_hidden($_url) .
2561 '<input name=\'formulaire_action\' type=\'hidden\'
2562 value=\'' . $_form . '\' />' .
2563 '<input name=\'formulaire_action_args\' type=\'hidden\'
2564 value=\'' . @\$Pile[0]['formulaire_args']. '\' />' .
2565 (!empty(\$Pile[0]['_hidden']) ? @\$Pile[0]['_hidden'] : '') .
2568 $p->interdire_scripts
= false;
2575 * Compile la balise `#BOUTON_ACTION` qui génère un bouton d'action en post, ajaxable
2577 * Cette balise s'utilise à la place des liens `action_auteur`, sous la forme
2579 * - `#BOUTON_ACTION{libelle,url}`
2580 * - ou `#BOUTON_ACTION{libelle,url,ajax}` pour que l'action soit ajax comme un lien `class='ajax'`
2581 * - ou `#BOUTON_ACTION{libelle,url,ajax,message_confirmation}` pour utiliser un message de confirmation
2582 * - ou encore `#BOUTON_ACTION{libelle[,url[,ajax[,message_confirmation[,title[,callback]]]]]}`
2585 * @link http://www.spip.net/4583
2588 * [(#AUTORISER{reparer,base})
2589 * [(#BOUTON_ACTION{<:bouton_tenter_recuperation:>,#URL_ECRIRE{base_repair}})]
2594 * Pile au niveau de la balise
2596 * Pile complétée par le code à générer
2598 function balise_BOUTON_ACTION_dist($p) {
2601 for ($k = 1; $k <= 6; $k++
) {
2602 $_a = interprete_argument_balise($k, $p);
2608 // supprimer les args vides
2609 while (end($args) == "''" and count($args) > 2) {
2612 $args = implode(",", $args);
2614 $bouton_action = chercher_filtre("bouton_action");
2615 $p->code
= "$bouton_action($args)";
2616 $p->interdire_scripts
= false;
2623 * Compile la balise `#SLOGAN_SITE_SPIP` qui retourne le slogan du site
2628 * [<p id="slogan">(#SLOGAN_SITE_SPIP)</p>]
2632 * Pile au niveau de la balise
2634 * Pile complétée par le code à générer
2636 function balise_SLOGAN_SITE_SPIP_dist($p) {
2637 $p->code
= "\$GLOBALS['meta']['slogan_site']";
2639 #$p->interdire_scripts = true;
2645 * Compile la balise `#HTML5` indiquant si l'espace public peut utiliser du HTML5
2647 * Renvoie `' '` si le webmestre souhaite que SPIP génère du code (X)HTML5 sur
2648 * le site public, et `''` si le code doit être strictement compatible HTML4
2651 * @uses html5_permis()
2654 * [(#HTML5) required="required"]
2655 * <input[ (#HTML5|?{type="email",type="text"})] ... />
2659 * Pile au niveau de la balise
2661 * Pile complétée par le code à générer
2663 function balise_HTML5_dist($p) {
2664 $p->code
= html5_permis() ?
"' '" : "''";
2665 $p->interdire_scripts
= false;
2672 * Compile la balise `#TRI` permettant d'afficher un lien de changement d'ordre de tri
2673 * d'une colonne de la boucle
2675 * La balise `#TRI{champ[,libelle]}` champ prend `>` ou `<` pour afficher
2676 * le lien de changement de sens croissant ou decroissant (`>` `<` indiquent
2677 * un sens par une flèche)
2682 * <th>[(#TRI{titre,<:info_titre:>,ajax})]</th>
2686 * Pile au niveau de la balise
2687 * @param string $liste
2690 * Pile complétée par le code à générer
2692 function balise_TRI_dist($p, $liste = 'true') {
2693 $b = $p->nom_boucle ?
$p->nom_boucle
: $p->descr
['id_mere'];
2695 // s'il n'y a pas de nom de boucle, on ne peut pas trier
2698 _T('zbug_champ_hors_boucle',
2699 array('champ' => '#TRI')
2705 $boucle = $p->boucles
[$b];
2707 // s'il n'y a pas de tri_champ, c'est qu'on se trouve
2708 // dans un boucle recursive ou qu'on a oublie le critere {tri}
2709 if (!isset($boucle->modificateur
['tri_champ'])) {
2711 _T('zbug_tri_sans_critere',
2712 array('champ' => '#TRI')
2719 $_champ = interprete_argument_balise(1, $p);
2720 // si pas de champ, renvoyer le critere de tri utilise
2722 $p->code
= $boucle->modificateur
['tri_champ'];
2726 // forcer la jointure si besoin, et si le champ est statique
2727 if (preg_match(",^'([\w.]+)'$,i", $_champ, $m)) {
2728 index_pile($b, $m[1], $p->boucles
, '', null, true, false);
2731 $_libelle = interprete_argument_balise(2, $p);
2732 $_libelle = $_libelle ?
$_libelle : $_champ;
2734 $_class = interprete_argument_balise(3, $p);
2735 // si champ = ">" c'est un lien vers le tri croissant : de gauche a droite ==> 1
2736 // si champ = "<" c'est un lien vers le tri decroissant : (sens inverse) == -1
2737 $_issens = "in_array($_champ,array('>','<'))";
2738 $_sens = "(strpos('< >',$_champ)-1)";
2740 $_variable = "((\$s=$_issens)?'sens':'tri')." . $boucle->modificateur
['tri_nom'];
2741 $_url = "parametre_url(self(),$_variable,\$s?$_sens:$_champ)";
2742 $_url = "parametre_url($_url,'var_memotri',strncmp(" . $boucle->modificateur
['tri_nom'] . ",'session',7)==0?$_variable:'')";
2743 $_on = "\$s?(" . $boucle->modificateur
['tri_sens'] . "==$_sens" . '):(' . $boucle->modificateur
['tri_champ'] . "==$_champ)";
2745 $p->code
= "lien_ou_expose($_url,$_libelle,$_on" . ($_class ?
",$_class" : "") . ")";
2747 $p->interdire_scripts
= false;
2754 * Compile la balise `#SAUTER{n}` qui permet de sauter en avant n resultats dans une boucle
2756 * La balise modifie le compteur courant de la boucle, mais pas les autres
2757 * champs qui restent les valeurs de la boucle avant le saut. Il est donc
2758 * preferable d'utiliser la balise juste avant la fermeture `</BOUCLE>`
2760 * L'argument `n` doit être supérieur à zéro sinon la balise ne fait rien
2765 * Pile au niveau de la balise
2767 * Pile complétée par le code à générer
2769 function balise_SAUTER_dist($p) {
2770 $id_boucle = $p->id_boucle
;
2772 if (empty($p->boucles
[$id_boucle])) {
2773 $msg = array('zbug_champ_hors_boucle', array('champ' => '#SAUTER'));
2774 erreur_squelette($msg, $p);
2776 $boucle = $p->boucles
[$id_boucle];
2777 $_saut = interprete_argument_balise(1, $p);
2778 $_compteur = "\$Numrows['$id_boucle']['compteur_boucle']";
2779 $_total = "\$Numrows['$id_boucle']['total']";
2781 $p->code
= "vide($_compteur=\$iter->skip($_saut,$_total))";
2783 $p->interdire_scripts
= false;
2790 * Compile la balise `#PUBLIE` qui indique si un objet est publié ou non
2793 * @link http://www.spip.net/5545
2794 * @see objet_test_si_publie()
2797 * #PUBLIE : porte sur la boucle en cours
2798 * [(#PUBLIE{article, 3}|oui) ... ] : pour l'objet indiqué
2802 * Pile au niveau de la balise
2804 * Pile complétée par le code à générer
2806 function balise_PUBLIE_dist($p) {
2807 if (!$_type = interprete_argument_balise(1, $p)) {
2808 $_type = _q($p->type_requete
);
2809 $_id = champ_sql($p->boucles
[$p->id_boucle
]->primary
, $p);
2811 $_id = interprete_argument_balise(2, $p);
2815 if (isset($p->boucles
[$p->id_boucle
])) {
2816 $connect = $p->boucles
[$p->id_boucle
]->sql_serveur
;
2819 $p->code
= "(objet_test_si_publie(" . $_type . ",intval(" . $_id . ")," . _q($connect) . ")?' ':'')";
2820 $p->interdire_scripts
= false;
2826 * Compile la balise `#PRODUIRE` qui génère un fichier statique à partir
2827 * d'un squelette SPIP
2829 * Le format du fichier sera extrait de la pre-extension du squelette
2830 * (typo.css.html, messcripts.js.html)
2831 * ou par l'argument `format=css` ou `format=js` passé en argument.
2833 * S'il n'y a pas de format détectable, on utilise `.html`, comme pour les squelettes.
2835 * La syntaxe de la balise est la même que celle de `#INCLURE`.
2838 * @see balise_INCLURE_dist()
2839 * @link http://www.spip.net/5505
2842 * <link rel="stylesheet" type="text/css" href="#PRODUIRE{fond=css/macss.css,couleur=ffffff}" />
2846 * Pile au niveau de la balise
2848 * Pile complétée par le code à générer
2850 function balise_PRODUIRE_dist($p) {
2851 $balise_inclure = charger_fonction('INCLURE', 'balise');
2852 $p = $balise_inclure($p);
2854 $p->code
= str_replace('recuperer_fond(', 'produire_fond_statique(', $p->code
);
2860 * Compile la balise `#LARGEUR_ECRAN` qui définit la largeur d'écran
2861 * dans l'espace privé
2866 * #LARGEUR_ECRAN{pleine_largeur}
2870 * Pile au niveau de la balise
2872 * Pile complétée par le code à générer
2874 function balise_LARGEUR_ECRAN_dist($p) {
2875 $_class = interprete_argument_balise(1, $p);
2879 $p->code
= "(is_string($_class)?vide(\$GLOBALS['largeur_ecran']=$_class):(isset(\$GLOBALS['largeur_ecran'])?\$GLOBALS['largeur_ecran']:''))";
2886 * Compile la balise `#CONST` qui retourne la valeur de la constante passée en argument
2889 * @example `#CONST{_DIR_IMG}`
2892 * Pile au niveau de la balise
2894 * Pile complétée par le code à générer
2896 function balise_CONST_dist($p) {
2897 $_const = interprete_argument_balise(1, $p);
2898 if (!strlen($_const)) {
2902 $p->code
= "(defined($_const)?constant($_const):'')";
2904 $p->interdire_scripts
= false;