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 * Définition des noeuds de l'arbre de syntaxe abstraite
16 * @package SPIP\Core\Compilateur\AST
19 if (!defined('_ECRIRE_INC_VERSION')) {
25 * Description d'un contexte de compilation
27 * Objet simple pour stocker le nom du fichier, la ligne, la boucle
28 * permettant entre autre de localiser le lieu d'une erreur de compilation.
29 * Cette structure est nécessaire au traitement d'erreur à l'exécution.
31 * Le champ code est inutilisé dans cette classe seule, mais harmonise
32 * le traitement d'erreurs.
34 * @package SPIP\Core\Compilateur\AST
38 * Description du squelette
40 * Sert pour la gestion d'erreur et la production de code dependant du contexte
42 * Peut contenir les index :
44 * - nom : Nom du fichier de cache
45 * - gram : Nom de la grammaire du squelette (détermine le phraseur à utiliser)
46 * - sourcefile : Chemin du squelette
47 * - squelette : Code du squelette
48 * - id_mere : Identifiant de la boucle parente
49 * - documents : Pour embed et img dans les textes
50 * - session : Pour un cache sessionné par auteur
51 * - niv : Niveau de tabulation
55 public $descr = array();
58 * Identifiant de la boucle
62 public $id_boucle = '';
65 * Numéro de ligne dans le code source du squelette
79 * Résultat de la compilation: toujours une expression PHP
88 * Description d'un texte
90 * @package SPIP\Core\Compilateur\AST
98 public $type = 'texte';
108 * Contenu avant le texte.
110 * Vide ou apostrophe simple ou double si le texte en était entouré
117 * Contenu après le texte.
119 * Vide ou apostrophe simple ou double si le texte en était entouré
126 * Numéro de ligne dans le code source du squelette
134 * Description d'une inclusion de squelette
136 * @package SPIP\Core\Compilateur\AST
144 public $type = 'include';
147 * Nom d'un fichier inclu
149 * - Objet Texte si inclusion d'un autre squelette
150 * - chaîne si inclusion d'un fichier PHP directement
157 * Inutilisé, propriété générique de l'AST
164 * Inutilisé, propriété générique de l'AST
171 * Numéro de ligne dans le code source du squelette
178 * Valeurs des paramètres
182 public $param = array();
187 * Description d'une boucle
189 * @package SPIP\Core\Compilateur\AST
197 public $type = 'boucle';
200 * Identifiant de la boucle
207 * Identifiant de la boucle parente
211 public $id_parent = '';
214 * Partie optionnelle avant
221 * Pour chaque élément
228 * Partie optionnelle après
235 * Partie alternative, si pas de résultat dans la boucle
242 * La boucle doit-elle sélectionner la langue ?
249 * Alias de table d'application de la requête ou nom complet de la table SQL
253 public $type_requete;
256 * La table est elle optionnelle ?
258 * Si oui, aucune erreur ne sera générée si la table demandée n'est pas présente
262 public $table_optionnelle = false;
265 * Nom du fichier de connexion
269 public $sql_serveur = '';
272 * Paramètres de la boucle
274 * Description des paramètres passés à la boucle, qui servent ensuite
275 * au calcul des critères
279 public $param = array();
282 * Critères de la boucle
286 public $criteres = array();
289 * Textes insérés entre 2 éléments de boucle (critère inter)
293 public $separateur = array();
296 * Liste des jointures possibles avec cette table
298 * Les jointures par défaut de la table sont complétées en priorité
299 * des jointures déclarées explicitement sur la boucle
301 * @see base_trouver_table_dist()
304 public $jointures = array();
307 * Jointures explicites avec cette table
309 * Ces jointures sont utilisées en priorité par rapport aux jointures
310 * normales possibles pour retrouver les colonnes demandées extérieures
315 public $jointures_explicites = false;
318 * Nom de la variable PHP stockant le noms de doublons utilisés "$doublons_index"
325 * Code PHP ajouté au début de chaque itération de boucle.
327 * Utilisé entre autre par les critères {pagination}, {n-a,b}, {a/b}...
334 * Nombre de divisions de la boucle, d'éléments à afficher,
335 * ou de soustractions d'éléments à faire
337 * Dans les critères limitant le nombre d'éléments affichés
338 * {a,b}, {a,n-b}, {a/b}, {pagination b}, b est affecté à total_parties.
342 public $total_parties = "";
345 * Code PHP ajouté avant l'itération de boucle.
347 * Utilisé entre autre par les critères {pagination}, {a,b}, {a/b}
348 * pour initialiser les variables de début et de fin d'itération.
352 public $mode_partie = '';
355 * Identifiant d'une boucle qui appelle celle-ci de manière récursive
357 * Si une boucle est appelée de manière récursive quelque part par
358 * une autre boucle comme <BOUCLE_rec(boucle_identifiant) />, cette
359 * boucle (identifiant) reçoit dans cette propriété l'identifiant
360 * de l'appelant (rec)
364 public $externe = '';
366 // champs pour la construction de la requete SQL
369 * Liste des champs à récupérer par la boucle
371 * Expression 'table.nom_champ' ou calculée 'nom_champ AS x'
375 public $select = array();
378 * Liste des alias / tables SQL utilisées dans la boucle
380 * L'index est un identifiant (xx dans spip_xx assez souvent) qui servira
381 * d'alias au nom de la table ; la valeur est le nom de la table SQL désirée.
383 * L'index 0 peut définir le type de sources de données de l'itérateur DATA
387 public $from = array();
390 * Liste des alias / type de jointures utilisées dans la boucle
392 * L'index est le nom d'alias (comme pour la propriété $from), et la valeur
393 * un type de jointure parmi 'INNER', 'LEFT', 'RIGHT', 'OUTER'.
395 * Lorsque le type n'est pas déclaré pour un alias, c'est 'INNER'
396 * qui sera utilisé par défaut (créant donc un INNER JOIN).
400 public $from_type = array();
403 * Liste des conditions WHERE de la boucle
405 * Permet de restreindre les éléments retournés par une boucle
406 * en fonctions des conditions transmises dans ce tableau.
408 * Ce tableau peut avoir plusieurs niveaux de profondeur.
410 * Les éléments du premier niveau sont reliés par des AND, donc
411 * chaque élément ajouté directement au where par
412 * $boucle->where[] = array(...) ou $boucle->where[] = "'expression'"
413 * est une condition AND en plus.
415 * Par contre, lorsqu'on indique un tableau, il peut décrire des relations
416 * internes différentes. Soit $expr un tableau d'expressions quelconques de 3 valeurs :
417 * $expr = array(operateur, val1, val2)
419 * Ces 3 valeurs sont des expressions PHP. L'index 0 désigne l'opérateur
420 * à réaliser tel que :
422 * - "'='" , "'>='", "'<'", "'IN'", "'REGEXP'", "'LIKE'", ... :
423 * val1 et val2 sont des champs et valeurs à utiliser dans la comparaison
424 * suivant cet ordre : "val1 operateur val2".
425 * Exemple : $boucle->where[] = array("'='", "'articles.statut'", "'\"publie\"'");
426 * - "'AND'", "'OR'", "'NOT'" :
427 * dans ce cas val1 et val2 sont également des expressions
428 * de comparaison complètes, et peuvent être eux-même des tableaux comme $expr
430 * $boucle->where[] = array("'OR'", $expr1, $expr2);
431 * $boucle->where[] = array("'NOT'", $expr); // val2 n'existe pas avec NOT
433 * D'autres noms sont possibles pour l'opérateur (le nombre de valeurs diffère) :
434 * - "'SELF'", "'SUBSELECT'" : indiquent des sous requêtes
435 * - "'?'" : indique une condition à faire évaluer (val1 ? val2 : val3)
439 public $where = array();
441 public $join = array();
442 public $having = array();
444 public $group = array();
445 public $order = array();
446 public $default_order = array();
447 public $date = 'date';
450 public $sous_requete = false;
453 * Code PHP qui sera ajouté en tout début de la fonction de boucle
455 * Il sert à insérer le code calculant une hierarchie
459 public $hierarchie = '';
462 * Indique la présence d'un critère sur le statut
464 * @deprecated Remplacé par $boucle->modificateur['criteres']['statut']
467 public $statut = false;
469 // champs pour la construction du corps PHP
472 * Description des sources de données de la boucle
474 * Description des données de la boucle issu de trouver_table
475 * dans le cadre de l'itérateur SQL et contenant au moins l'index 'field'.
477 * @see base_trouver_table_dist()
480 public $show = array();
483 * Nom de la table SQL principale de la boucle, sans son préfixe
490 * Nom de la clé primaire de la table SQL principale de la boucle
497 * Code PHP compilé de la boucle
503 public $numrows = false;
504 public $cptrows = false;
507 * Description du squelette
509 * Sert pour la gestion d'erreur et la production de code dependant du contexte
511 * Peut contenir les index :
513 * - nom : Nom du fichier de cache
514 * - gram : Nom de la grammaire du squelette (détermine le phraseur à utiliser)
515 * - sourcefile : Chemin du squelette
516 * - squelette : Code du squelette
517 * - id_mere : Identifiant de la boucle parente
518 * - documents : Pour embed et img dans les textes
519 * - session : Pour un cache sessionné par auteur
520 * - niv : Niveau de tabulation
524 public $descr = array();
527 * Numéro de ligne dans le code source du squelette
534 public $modificateur = array(); // table pour stocker les modificateurs de boucle tels que tout, plat ..., utilisable par les plugins egalement
537 * Type d'itérateur utilisé pour cette boucle
539 * - 'SQL' dans le cadre d'une boucle sur une table SQL
540 * - 'DATA' pour l'itérateur DATA, ...
544 public $iterateur = ''; // type d'iterateur
547 * Index de la boucle dont le champ présent dans cette boucle est originaire,
548 * notamment si le champ a été trouve dans une boucle parente
550 * Tableau nom du champ => index de boucle
552 * @var array $index_champ
554 public $index_champ = [];
556 // obsoletes, conserves provisoirement pour compatibilite
557 public $tout = false;
558 public $plat = false;
559 public $lien = false;
563 * Description d'un critère de boucle
565 * Sous-noeud de Boucle
567 * @package SPIP\Core\Compilateur\AST
575 public $type = 'critere';
578 * Opérateur (>, <, >=, IN, ...)
585 * Présence d'une négation (truc !op valeur)
592 * Présence d'une exclusion (!truc op valeur)
599 * Présence d'une condition dans le critère (truc ?)
603 public $cond = false;
606 * Paramètres du critère
607 * - $param[0] : élément avant l'opérateur
608 * - $param[1..n] : éléments après l'opérateur
612 public $param = array();
615 * Numéro de ligne dans le code source du squelette
623 * Description d'un champ (balise SPIP)
625 * @package SPIP\Core\Compilateur\AST
633 public $type = 'champ';
636 * Nom du champ demandé. Exemple 'ID_ARTICLE'
643 * Identifiant de la boucle parente si explicité
647 public $nom_boucle = '';
650 * Partie optionnelle avant
652 * @var null|string|array
657 * Partie optionnelle après
659 * @var null|string|array
664 * Étoiles : annuler des automatismes
666 * - '*' annule les filtres automatiques
667 * - '**' annule en plus les protections de scripts
674 * Arguments et filtres explicites sur la balise
676 * - $param[0] contient les arguments de la balise
677 * - $param[1..n] contient les filtres à appliquer à la balise
681 public $param = array();
684 * Source des filtres (compatibilité) (?)
688 public $fonctions = array();
691 * Identifiant de la boucle
695 public $id_boucle = '';
698 * AST du squelette, liste de toutes les boucles
705 * Alias de table d'application de la requête ou nom complet de la table SQL
709 public $type_requete;
712 * Résultat de la compilation: toujours une expression PHP
719 * Interdire les scripts
721 * false si on est sûr de cette balise
723 * @see interdire_scripts()
726 public $interdire_scripts = true;
729 * Description du squelette
731 * Sert pour la gestion d'erreur et la production de code dependant du contexte
733 * Peut contenir les index :
735 * - nom : Nom du fichier de cache
736 * - gram : Nom de la grammaire du squelette (détermine le phraseur à utiliser)
737 * - sourcefile : Chemin du squelette
738 * - squelette : Code du squelette
739 * - id_mere : Identifiant de la boucle parente
740 * - documents : Pour embed et img dans les textes
741 * - session : Pour un cache sessionné par auteur
742 * - niv : Niveau de tabulation
746 public $descr = array();
749 * Numéro de ligne dans le code source du squelette
756 * Drapeau pour reperer les balises calculées par une fonction explicite
760 public $balise_calculee = false;
765 * Description d'une chaîne de langue
773 public $type = 'idiome';
776 * Clé de traduction demandée. Exemple 'item_oui'
780 public $nom_champ = "";
783 * Module de langue où chercher la clé de traduction. Exemple 'medias'
790 * Arguments à passer à la chaîne
794 public $arg = array();
797 * Filtres à appliquer au résultat
801 public $param = array();
804 * Source des filtres (compatibilité) (?)
808 public $fonctions = array();
811 * Inutilisé, propriété générique de l'AST
818 * Inutilisé, propriété générique de l'AST
825 * Identifiant de la boucle
829 public $id_boucle = '';
832 * AST du squelette, liste de toutes les boucles
839 * Alias de table d'application de la requête ou nom complet de la table SQL
843 public $type_requete;
846 * Résultat de la compilation: toujours une expression PHP
853 * Interdire les scripts
855 * @see interdire_scripts()
858 public $interdire_scripts = false;
861 * Description du squelette
863 * Sert pour la gestion d'erreur et la production de code dependant du contexte
865 * Peut contenir les index :
866 * - nom : Nom du fichier de cache
867 * - gram : Nom de la grammaire du squelette (détermine le phraseur à utiliser)
868 * - sourcefile : Chemin du squelette
869 * - squelette : Code du squelette
870 * - id_mere : Identifiant de la boucle parente
871 * - documents : Pour embed et img dans les textes
872 * - session : Pour un cache sessionné par auteur
873 * - niv : Niveau de tabulation
877 public $descr = array();
880 * Numéro de ligne dans le code source du squelette
888 * Description d'un texte polyglotte (<multi>)
890 * @package SPIP\Core\Compilateur\AST
898 public $type = 'polyglotte';
901 * Tableau des traductions possibles classées par langue
903 * Tableau code de langue => texte
907 public $traductions = array();
910 * Numéro de ligne dans le code source du squelette
918 global $table_criteres_infixes;
919 $table_criteres_infixes = array('<', '>', '<=', '>=', '==', '===', '!=', '!==', '<>', '?');
921 global $exception_des_connect;
922 $exception_des_connect[] = ''; // ne pas transmettre le connect='' par les inclure
926 * Déclarer les interfaces de la base pour le compilateur
928 * On utilise une fonction qui initialise les valeurs,
929 * sans écraser d'eventuelles prédéfinition dans mes_options
930 * et les envoie dans un pipeline
933 * @link http://code.spip.net/@declarer_interfaces
937 function declarer_interfaces() {
939 $GLOBALS['table_des_tables']['articles'] = 'articles';
940 $GLOBALS['table_des_tables']['auteurs'] = 'auteurs';
941 $GLOBALS['table_des_tables']['rubriques'] = 'rubriques';
942 $GLOBALS['table_des_tables']['hierarchie'] = 'rubriques';
944 // definition des statuts de publication
945 $GLOBALS['table_statut'] = array();
948 // tableau des tables de jointures
949 // Ex: gestion du critere {id_mot} dans la boucle(ARTICLES)
950 $GLOBALS['tables_jointures'] = array();
951 $GLOBALS['tables_jointures']['spip_jobs'][] = 'jobs_liens';
953 // $GLOBALS['exceptions_des_jointures']['titre_mot'] = array('spip_mots', 'titre'); // pour exemple
954 $GLOBALS['exceptions_des_jointures']['profondeur'] = array('spip_rubriques', 'profondeur');
957 if (!defined('_TRAITEMENT_TYPO')) {
958 define('_TRAITEMENT_TYPO', 'typo(%s, "TYPO", $connect, $Pile[0])');
960 if (!defined('_TRAITEMENT_RACCOURCIS')) {
961 define('_TRAITEMENT_RACCOURCIS', 'propre(%s, $connect, $Pile[0])');
963 if (!defined('_TRAITEMENT_TYPO_SANS_NUMERO')) {
964 define('_TRAITEMENT_TYPO_SANS_NUMERO', 'supprimer_numero(typo(%s, "TYPO", $connect, $Pile[0]))');
966 $GLOBALS['table_des_traitements']['BIO'][] = 'safehtml('._TRAITEMENT_RACCOURCIS
.')';
967 $GLOBALS['table_des_traitements']['NOM_SITE']['spip_auteurs'] = 'entites_html(%s)';
968 $GLOBALS['table_des_traitements']['NOM']['spip_auteurs'] = 'safehtml(%s)';
969 $GLOBALS['table_des_traitements']['CHAPO'][] = _TRAITEMENT_RACCOURCIS
;
970 $GLOBALS['table_des_traitements']['DATE'][] = 'normaliser_date(%s)';
971 $GLOBALS['table_des_traitements']['DATE_REDAC'][] = 'normaliser_date(%s)';
972 $GLOBALS['table_des_traitements']['DATE_MODIF'][] = 'normaliser_date(%s)';
973 $GLOBALS['table_des_traitements']['DATE_NOUVEAUTES'][] = 'normaliser_date(%s)';
974 $GLOBALS['table_des_traitements']['DESCRIPTIF'][] = _TRAITEMENT_RACCOURCIS
;
975 $GLOBALS['table_des_traitements']['INTRODUCTION'][] = _TRAITEMENT_RACCOURCIS
;
976 $GLOBALS['table_des_traitements']['NOM_SITE_SPIP'][] = _TRAITEMENT_TYPO
;
977 $GLOBALS['table_des_traitements']['NOM'][] = _TRAITEMENT_TYPO_SANS_NUMERO
;
978 $GLOBALS['table_des_traitements']['AUTEUR'][] = _TRAITEMENT_TYPO
;
979 $GLOBALS['table_des_traitements']['PS'][] = _TRAITEMENT_RACCOURCIS
;
980 $GLOBALS['table_des_traitements']['SOURCE'][] = _TRAITEMENT_TYPO
;
981 $GLOBALS['table_des_traitements']['SOUSTITRE'][] = _TRAITEMENT_TYPO
;
982 $GLOBALS['table_des_traitements']['SURTITRE'][] = _TRAITEMENT_TYPO
;
983 $GLOBALS['table_des_traitements']['TAGS'][] = '%s';
984 $GLOBALS['table_des_traitements']['TEXTE'][] = _TRAITEMENT_RACCOURCIS
;
985 $GLOBALS['table_des_traitements']['TITRE'][] = _TRAITEMENT_TYPO_SANS_NUMERO
;
986 $GLOBALS['table_des_traitements']['TYPE'][] = _TRAITEMENT_TYPO
;
987 $GLOBALS['table_des_traitements']['DESCRIPTIF_SITE_SPIP'][] = _TRAITEMENT_RACCOURCIS
;
988 $GLOBALS['table_des_traitements']['SLOGAN_SITE_SPIP'][] = _TRAITEMENT_TYPO
;
989 $GLOBALS['table_des_traitements']['ENV'][] = 'entites_html(%s,true)';
991 // valeur par defaut pour les balises non listees ci-dessus
992 $GLOBALS['table_des_traitements']['*'][] = false; // pas de traitement, mais permet au compilo de trouver la declaration suivante
993 // toujours securiser les DATA
994 $GLOBALS['table_des_traitements']['*']['DATA'] = 'safehtml(%s)';
995 // expliciter pour VALEUR qui est un champ calcule et ne sera pas protege par le catch-all *
996 $GLOBALS['table_des_traitements']['VALEUR']['DATA'] = 'safehtml(%s)';
999 // gerer l'affectation en 2 temps car si le pipe n'est pas encore declare, on ecrase les globales
1000 $interfaces = pipeline('declarer_tables_interfaces',
1002 'table_des_tables' => $GLOBALS['table_des_tables'],
1003 'exceptions_des_tables' => $GLOBALS['exceptions_des_tables'],
1004 'table_date' => $GLOBALS['table_date'],
1005 'table_titre' => $GLOBALS['table_titre'],
1006 'tables_jointures' => $GLOBALS['tables_jointures'],
1007 'exceptions_des_jointures' => $GLOBALS['exceptions_des_jointures'],
1008 'table_des_traitements' => $GLOBALS['table_des_traitements'],
1009 'table_statut' => $GLOBALS['table_statut'],
1012 $GLOBALS['table_des_tables'] = $interfaces['table_des_tables'];
1013 $GLOBALS['exceptions_des_tables'] = $interfaces['exceptions_des_tables'];
1014 $GLOBALS['table_date'] = $interfaces['table_date'];
1015 $GLOBALS['table_titre'] = $interfaces['table_titre'];
1016 $GLOBALS['tables_jointures'] = $interfaces['tables_jointures'];
1017 $GLOBALS['exceptions_des_jointures'] = $interfaces['exceptions_des_jointures'];
1018 $GLOBALS['table_des_traitements'] = $interfaces['table_des_traitements'];
1019 $GLOBALS['table_statut'] = $interfaces['table_statut'];
1023 declarer_interfaces();