Changeset 113654 in spip-zone


Ignore:
Timestamp:
Jan 28, 2019, 12:36:57 PM (3 weeks 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 )

Location:
_plugins_/macrosession/trunk
Files:
4 added
3 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');
  • _plugins_/macrosession/trunk/paquet.xml

    r113631 r113654  
    22        prefix="macrosession"
    33        categorie="outil"
    4         version="0.10.0"
     4        version="0.11.0"
    55        etat="test"
    66        compatibilite="[2.1.0;3.2.*]"
  • _plugins_/macrosession/trunk/plugin.xml

    r113631 r113654  
    55        <auteur>JLuc</auteur>
    66        <licence>GPL</licence>
    7         <version>0.10.0</version>
     7        <version>0.11.0</version>
    88        <etat>test</etat>
    99        <description>
    1010        Macros SPIP #_SESSION, #_SESSION_SI, #_AUTORISER_SI, etc
    11         pour accéder aux données de la session de la _session courant et les tester efficacement
     11        pour accéder aux données de la session de la _session courant
    1212        ou à des données de sessions d'autre origine que la session spip,
    13         et les tester et tester les autorisations
     13        et les tester efficacement ainsi que les autorisations
    1414        sans multiplier les caches sessionnés
    1515        </description>
Note: See TracChangeset for help on using the changeset viewer.