Ignore:
Timestamp:
Jan 28, 2019, 12:36:57 PM (20 months ago)
Author:
jluc@…
Message:

Refactoring du calcul des arguments calculés pour #_AUTORISER et aussi désormais pour #_SESSION
Les arguments des filtres utilisés par #_SESSION peuvent être des valeurs de l'environnement, des #GET{variable} et des #CHAMPS de la boucle courante.
Si un post-traitements est associé à un #CHAMP de boucle, il faut l'enlever avec une étoile #CHAMP* (le traitement de sécu reste). S'il y a besoin du traitement, il faut faire un #SET préalable, puis utiliser le #GET.
( Maieul : on peut surement faire #_SESSION_SI{id_auteur,==,#ID_AUTEUR} ... #_SESSION_FIN )

File:
1 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/macrosession/trunk/macrosession_options.php

    r113627 r113654  
    22
    33/**
    4  * Outils SPIP supplémentaires pour une gestion efficace pour l'hébergement
    5  * des accés aux données de la _session courant
     4 * Outils SPIP supplémentaires pour une gestion efficace des accés aux données de la _session courant
    65 * et pour l'accès à des données de session étendue
    76 *
    87 * Balises #_SESSION, #_SESSION_SI, #_SESSION_SINON, #_SESSION_FIN
     8 * #_AUTORISER_SI, #_AUTORISER_SINON, #_AUTORISER_FIN
    99 *
    10  * @copyright   2016, 2017
     10 * @copyright   2016, 2017, 2018, 2019
    1111 * @author              JLuc
    1212 * @credit              Marcimat
     
    1616
    1717include_spip('inc/session');
    18 include_spip ('inc/filtres');
    19 
    20 // TODO : ne charger inc/autoriser qu'au besoin, dans le code inséré à la place de chaque appel de balise
    21 include_spip ('inc/autoriser');
    22 
    23 unset($_GET['debug']); // commenter pour permettre l'analyse et debug
     18include_spip ('inc/filtres');
     19include_spip('inc/autoriser');
    2420
    2521// on utilise nobreak quand il n'y a pas de break entre 2 cases d'un switch,
     
    2723if (!defined('nobreak'))
    2824        define('nobreak', '');
    29 
    30 //
    31 // FIXME : appeler appliquer_filtre dans le code compilé est une somptuosité superfétatoire
    32 // Au lieu de cela, appeler chercher_filtre à la compilation pour savoir quelle est la fonction appelée par le filtre et insérer dans le code compilé un appel direct à cette fonction
    33 // Comme ça plus besoin d'inclure inc/filtres dans mes_options
    34 
    35 //
    36 // Accés étendu aux données de session des visiteurs
    37 //
    38 // Aucun test n'est fait en amont sur la présence ou non d'une session :
    39 // le pipeline session_get peut être défini par ailleurs (autre plugin...)
    40 // Il reçoit un tableau avec 2 arguments : 'champ' contient le champ recherché,
    41 // et 'visiteur_session' contient la session en cours d'élaboration,
    42 // qu'il peut, ou non, utiliser pour le calcul ou la recherche de la valeur demandée
    43 //
    44 // Actuellement le pipeline n'est appelé que si la valeur demandée
    45 // n'est pas déjà présente dans la session globale SPIP de base...
    46 //
    47 function pipelined_session_get ($champ) {
    48         if (!isset ($GLOBALS['visiteur_session'])
    49                 or !isset($GLOBALS['visiteur_session']['id_auteur'])    // il semble que ces précisions soient nécessaires
    50                 or !$GLOBALS['visiteur_session']['id_auteur'] )
    51                 return '';
    52         elseif (isset ($GLOBALS['visiteur_session'][$champ]))
    53                 return $GLOBALS['visiteur_session'][$champ];
    54 
    55         $session =
    56                 array ( 'champ' => $champ,
    57                                 'visiteur_session' => $GLOBALS['visiteur_session']);
    58         $session = pipeline ('session_get', $session);
    59         if (isset ($session['visiteur_session'][$champ]))
    60                 return $session['visiteur_session'][$champ];
    61         else
    62                 return '';
    63 };
    64 
    65 if (!function_exists('existe_argument_balise')) {
    66         // prolégomène à interprete_argument_balise
    67         function existe_argument_balise ($n, $p) {
    68                 return (($p->param) && (!$p->param[0][0]) && (count($p->param[0])>$n));
    69         };
    70 }
    71 
    72 /*
    73  * Recevant un argument entre quotes (contenant par exemple un nom de filtre)
    74  * trim_quote enlève les espaces de début et fin *à l'intérieur* des quotes
    75  * ex : reçoit ' filtre ' (quotes comprises) et renvoie 'filtre'
    76 */
    77 function trim_quote($f) {
    78         $f = trim($f);  // c'est pas ça l'important
    79         $l = strlen($f);
    80         if ((strpos($f,"'")!== 0) or (strrpos($f,"'")!== $l-1))
    81                 return $f;
    82         $r = '\''.trim(substr($f, 1, $l-2)).'\'';
    83         return $r;
    84 }
    85 
    86 // une fonction pour le code de |? (la négation de choixsivide)
    87 function choix_selon ($test, $sioui, $sinon) {
    88         return $test ? $sioui : $sinon;
    89 }
    90 
    9125define ('V_OUVRE_PHP', "'<'.'" . '?php ');
    9226define ('V_FERME_PHP', ' ?' . "'.'>'");
    9327
    94 // Appelé uniquement au recalcul pour la compilation
    95 // le code renvoyé sera inséré à l'intérieur d'un '...'
    96 function compile_appel_macro_session ($p) {
    97         $champ = interprete_argument_balise(1, $p);
    98         // $champ est entre quotes ''
    99         if (!$champ)
    100                 $champ = "'id_auteur'";
    101 
    102         if (erreur_argument_macro ('#_SESSION', 'champ', $champ, $p))
    103                 return "''";
    104 
    105         $get_champ = "pipelined_session_get('.\"$champ\".')";
    106 
    107         // champ sans application de filtre
    108         if (!existe_argument_balise(2, $p))
    109                 return $get_champ;
    110 
    111         // Application d'un filtre, récupéré entre quotes ''
    112         $filtre = trim_quote(interprete_argument_balise (2, $p));
    113         if (erreur_argument_macro ('#_SESSION', 'filtre', $filtre, $p))
    114                 return "''";
    115 
    116         // le filtre est il en fait un opérateur unaire ?
    117         if (in_array ($filtre, array ("'!'", "'non'"))) {
    118                 $unaire = trim ($filtre, "'");
    119                 switch ($unaire) {
    120                 case '!':
    121                         nobreak;
    122                 case 'non' :
    123                         return "(!$get_champ)";
    124                         break;
    125                 }
    126         }
    127 
    128         if ($filtre=="'?'")
    129                 $filtre = "'choix_selon'";
    130                
    131         // le filtre peut être appelé avec 0, un ou 2 arguments
    132         $arg_un = $arg_deux = $virgule_arg_un = $virgule_arg_deux = '';
    133        
    134         if (existe_argument_balise(3, $p)) {
    135                 $arg_un = trim_quote(interprete_argument_balise(3, $p));
    136                 if ($arg_un and erreur_argument_macro ('#_SESSION', 'arg_un', $arg_un, $p))
    137                         return "''";
    138                 $virgule_arg_un = ".', '.\"$arg_un\"";
    139         };
    140 
    141         // le filtre est il en fait un opérateur de comparaison ?
    142         if (in_array ($filtre, array ("'=='", "'!='", "'<'", "'<='", "'>'", "'>='"))) {
    143                 $comparateur = trim ($filtre, "'");
    144 
    145                 return "($get_champ $comparateur '.\"$arg_un\".')";
    146                 // #_SESSION{nom,==,JLuc} donnera
    147                 // '<'.'?php  echo (pipelined_session_get('."'nom'".') == '."'JLuc'".');  ?'.'>'
    148         }
    149 
    150         if (existe_argument_balise(4, $p)) {
    151                 $arg_deux = trim_quote(interprete_argument_balise(4, $p));
    152                 if ($arg_deux and erreur_argument_macro ('#_SESSION', 'arg_deux', $arg_deux, $p))
    153                         return "''";
    154                 $virgule_arg_deux = ".', '.\"$arg_deux\"";
    155         };
    156 
    157 // produira par exemple ensuite :
    158 // '<'.'?php  echo appliquer_filtre(pipelined_session_get('."'nom'".'), '."'strlen'".');  ?'.'>'
    159 // ou '<'.'?php  echo appliquer_filtre( pipelined_session_get('."'nbreste'".'), '."'plus'" .', "'3'" .');  ?'.'>'
    160         $r = "appliquer_filtre($get_champ, '.\"$filtre\" $virgule_arg_un $virgule_arg_deux .')";
    161 
    162         return $r;
    163 }
    164 
    165 //
    166 // Définition des balises
    167 // Attention : on ne peut PAS appliquer de filtre sur ces balises ni les utiliser dans une construction conditionnelle [avant(...) après]
    168 // Pour appliquer un filtre, utiliser la syntaxe dédiée avec un argument d'appel de la balise
    169 //
    170 
    171 /*
    172  * #_SESSION rend l'id_auteur si l'internaute est connecté
    173  * #_SESSION(champ) rend la valeur du champ de session étendue de l'internaute connecté
    174  * #_SESSION(champ, filtre[, arg1[, arg2]]) applique le filtre au champ de session étendue, avec 0, 1 ou 2 arguments supplémentaires et rend la valeur résultat
    175  *
    176  */
    177 function balise__SESSION_dist($p) {
    178         $p->code = V_OUVRE_PHP . ' echo '. compile_appel_macro_session($p). '; ' . V_FERME_PHP;
    179         $p->interdire_scripts = false;
    180         // echo "On insèrera l'évaluation du code suivant : <pre>".$p->code."</pre>\n\n";
    181         return $p;
    182 }
    183 
    184 /*
    185  * #_SESSION_SI teste si l'internaute est authentifié
    186  * #_SESSION_SI(champ) teste si le champ de session est non vide
    187  * #_SESSION_SI(champ, val) teste si le champ de session est égal à val
    188  *              C'est un raccourci pour #_SESSION_SI{champ,==,val}
    189  * #_SESSION_SI(champ, operateur, val) teste si le champ de session se compare positivement à la valeur spécifiée
    190  *      selon l'opérateur spécifié, qui peut etre
    191  * - soit un comparateur : ==, <, >, >=, <=
    192  * - soit un opérateur unaire : ! ou non
    193  * - soit un filtre (nom de fonction) recevant 2 arguments : la valeur du champ et val.
    194  *              C'est alors le retour qui est testé.
    195  * Produit par exemple le code suivant :
    196  *      '<'.'?php  if (pipelined_session_get('."'nom'".')) {  ?'.'>'
    197 */
    198 function balise__SESSION_SI_dist($p) {
    199         // Appelé uniquement au recalcul
    200         $p->code = V_OUVRE_PHP . 'if ('.compile_appel_macro_session($p).') { ' . V_FERME_PHP;
    201         $p->interdire_scripts = false;
    202         return $p;
    203 }
    204 
    205 function balise__SESSION_SINON_dist($p) {
    206         $p->code = V_OUVRE_PHP.' } else { '.V_FERME_PHP;
    207         $p->interdire_scripts = false;
    208         return $p;
    209 }
    210 
    211 function balise__SESSION_FIN_dist($p) {
    212         $p->code = V_OUVRE_PHP.' } '.V_FERME_PHP;
    213         $p->interdire_scripts = false;
    214         return $p;
    215 }
    216 
    217 function macrosession_pipe($q="!!! non défini !!!") {
    218         if (isset($_GET['debug']))
    219                 echo "exec macrosession_pipe($q)<br>";
    220         return $q;
    221 }
    222 function macrosession_print($a) {
    223         if (isset($_GET['debug']))
    224                 echo '<pre>'.print_r($a, 1).'</pre>';
    225         return "''";
    226 }
    227 
    228 function compile_appel_macro_autoriser ($p) {
    229         if (!existe_argument_balise(1, $p)) {
    230                 erreur_squelette ("Il faut au moins un argument à la balise #_AUTORISER", $p);
    231                 return "''";
    232         };
    233         $autorisation = interprete_argument_balise(1, $p);
    234 
    235         if (erreur_argument_macro ('#_AUTORISER_SI', 'autorisation', $autorisation, $p))
    236                 return "''";
    237 
    238         // l'autorisation peut être appelé avec 0, un ou 2 arguments
    239         if (!existe_argument_balise(2, $p))
    240                 return "autoriser('.\"$autorisation\".')";
    241 
    242         $type = trim_quote(interprete_argument_balise (2, $p));
    243         if (erreur_argument_macro ("#_AUTORISER_SI{ $autorisation,...}", 'type', $type, $p))
    244                 return "''";
    245 
    246         if (!existe_argument_balise(3, $p))
    247                 return "autoriser('.\"$autorisation\".', '.\"$type\".')";
    248 
    249         $id = trim_quote(interprete_argument_balise (3, $p));
    250         //
    251         // 4 possibilités de passer des id calculées à #_AUTORISER_SI :
    252         // - Appels directs de #BALISE ou #GET{variable} (non recommandé)
    253         // - Passer 'env', 'boucle' et 'url' pour chercher l'id_ associé au type dans l'env reçu, dans la boucle immédiatement englobante ou dans l'url
    254         // Ex : #_AUTORISER{modifier,article,env} ou #_AUTORISER{modifier,article,boucle} ou #_AUTORISER{modifier,article,url}
    255         //
    256 
    257         // Hacks : décompiler pour reconnaître et gérer #BALISE et #GET{variable}
    258         //
    259         // 1) Balises genre #ID_ARTICLE
    260         // Comme leur source php est inséré dans une chaine il faut l'enchasser entre accolades, et enlever le @
    261         // TODO : assurer une évaluation hors chaine
    262         if ((substr ($id,0,11) == '@$Pile[0][\'')
    263                 and preg_match("/[a-z_]+'\]$/iu", substr ($id, 11))) { // c'était \$ ce qui semble une erreur
    264                 $id = 'macrosession_pipe({'.substr($id, 1).'})';
    265         }
    266         // 2) #GET{variable}
    267         // cad : table_valeur($Pile["vars"], (string)'variable', null)
    268         // Pour simplifier la réécriture, on ne passe pas par table_valeur
    269         elseif (preg_match("/^table_valeur\(\\\$Pile\[\"vars\"\], \(string\)'([a-z_]+)', null\)\s*\$/iu",$id,$matches)) {
    270                 $id = 'macrosession_pipe({$Pile["vars"]["'.$matches[1].'"]})';
    271         }
    272         elseif (erreur_argument_macro ("#_AUTORISER_SI{ $autorisation, $type, ...}", 'id', $id, $p, 'contexte_ok'))
    273                 return "''";
    274 
    275         if (!existe_argument_balise(4, $p)) {
    276                 $id_type = "'id_".substr($type,1);      //      TODO : utiliser API spip
    277                 switch($id) {   
    278                         // TODO : gérer ces cas dans la continuité des 1) et 2) plus haut, en affectant $id. Ainsi ce sera compatible avec arguments qui et opt
    279                         // 3)
    280                         case "'env'" :
    281                                 if (isset($_GET['debug']))
    282                                         echo "Avec 'env' : compile appel autoriser($autorisation, $type, \$Pile[0][$id_type])<br>";
    283                                 $ret = "autoriser('.\"$autorisation\".', '.\"$type\".', '.\"macrosession_pipe({\$Pile[0][$id_type]})\".')";
    284                                 return $ret;
    285 
    286                         case "'boucle'" :
    287                                 if (isset($_GET['debug']))
    288                                         echo "Avec 'boucle' : compile appel autoriser($autorisation, $type, \$Pile[\$SP][$id_type])<br>";
    289                                 $ret = "autoriser('.\"$autorisation\".', '.\"$type\".', '.\"macrosession_pipe({\$Pile[\$SP][$id_type]})\".')";
    290                                
    291                                 return $ret;
    292 
    293                         case "'debug'" :
    294                                 $ret = 'time()';
    295                                 if (isset($_GET['debug'])) {
    296                                         echo "Avec 'debug' : macrosession_print(get_defined_vars())<br>";
    297                                         $ret = "macrosession_print(get_defined_vars())";
    298                                 }
    299                                 return $ret;
    300 
    301                         // 4)
    302                         case "'url'" :
    303                                 if (isset($_GET['debug']))
    304                                         echo "Avec 'url' : compile appel autoriser($autorisation, $type, _request($id_type)<br>";
    305                                 $ret = "autoriser('.\"$autorisation\".', '.\"$type\".', '.\"macrosession_pipe(_request($id_type))\".')";
    306                                 return $ret;
    307 
    308                         default :
    309                                 return "autoriser('.\"$autorisation\".', '.\"$type\".', '.\"$id\".')";
    310                 };
    311         };
    312 
    313         // ATTENTION : Les appels à #_AUTORISER_SI avec arguments $qui et $opt n'ont pas été testés
    314         $qui = trim_quote(interprete_argument_balise (4, $p));
    315         if (erreur_argument_macro ("#_AUTORISER_SI{ $autorisation, $type, $id, ...}", 'qui', $qui, $p))
    316                 return "''";
    317         if (!existe_argument_balise(5, $p))
    318                 return "autoriser('.\"$autorisation\".', '.\"$type\".', '.\"$id\".')";
    319 
    320         $opt = trim_quote(interprete_argument_balise (5, $p));
    321         if (erreur_argument_macro ('#_AUTORISER_SI', 'opt', $opt, $p))
    322                 return "''";
    323         return "autoriser('.\"$autorisation\".', '.\"$type\".', '.\"$id\".', '.\"$opt\".')";
    324 }
    325 
    326 function balise__AUTORISER_SI_dist($p) {
    327         $p->interdire_scripts = false;
    328 
    329         // Appelé uniquement au recalcul
    330         $p->code = V_OUVRE_PHP . 'if ('.compile_appel_macro_autoriser ($p).') { ' . V_FERME_PHP;
    331         return $p;
    332 }
    333 
    334 function balise__AUTORISER_SINON_dist($p) {
    335         return balise__SESSION_SINON_dist($p);
    336 }
    337 
    338 function balise__AUTORISER_FIN_dist($p) {
    339         return balise__SESSION_FIN_dist($p);
    340 }
    341  
    342 
    343 function erreur_argument_macro ($macro, $argument, $val, $p, $contexte_ok='') {
    344         if (substr($val, 0, 1) != "'") {
    345                 if ($contexte_ok)
    346                         $contexte_ok = "Pour chercher dans les variables d'environnement ou d'url, vous pouvez utiliser 'env', 'boucle', 'url' et aussi '#BALISE' pour les balises reçues par le squelette, mais pas pour les champs de la boucle immédiatement englobante";
    347                 erreur_squelette ("L'argument '$argument' de la macro '$macro' ne doit pas être une valeur calculée (".$val."). $contexte_ok", $p);
    348                 return true;
    349         };
    350         return false;
    351 }
     28include_spip('inc/macrosession_utils');
     29include_spip('inc/_session');
     30include_spip('inc/_autoriser');
Note: See TracChangeset for help on using the changeset viewer.