source: spip-zone/_plugins_/macrosession/trunk/macrosession_options.php @ 113627

Last change on this file since 113627 was 113627, checked in by root, 4 months ago

ce $ ressemble fort à une erreur

File size: 12.8 KB
Line 
1<?php
2
3/**
4 * Outils SPIP supplémentaires pour une gestion efficace pour l'hébergement
5 * des accés aux données de la _session courant
6 * et pour l'accès à des données de session étendue
7 *
8 * Balises #_SESSION, #_SESSION_SI, #_SESSION_SINON, #_SESSION_FIN
9 *
10 * @copyright   2016, 2017
11 * @author              JLuc
12 * @credit              Marcimat
13 * @licence             GPL
14 *
15 */
16
17include_spip('inc/session');
18include_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
21include_spip ('inc/autoriser'); 
22
23unset($_GET['debug']); // commenter pour permettre l'analyse et debug
24
25// on utilise nobreak quand il n'y a pas de break entre 2 cases d'un switch,
26// pour témoigner du fait que cette omission est intentionnelle
27if (!defined('nobreak'))
28        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//
47function 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
65if (!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*/
77function 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)
87function choix_selon ($test, $sioui, $sinon) {
88        return $test ? $sioui : $sinon;
89}
90
91define ('V_OUVRE_PHP', "'<'.'" . '?php ');
92define ('V_FERME_PHP', ' ?' . "'.'>'");
93
94// Appelé uniquement au recalcul pour la compilation
95// le code renvoyé sera inséré à l'intérieur d'un '...'
96function 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 */
177function 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*/
198function 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
205function 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
211function balise__SESSION_FIN_dist($p) {
212        $p->code = V_OUVRE_PHP.' } '.V_FERME_PHP;
213        $p->interdire_scripts = false;
214        return $p;
215}
216
217function macrosession_pipe($q="!!! non défini !!!") {
218        if (isset($_GET['debug']))
219                echo "exec macrosession_pipe($q)<br>";
220        return $q;
221}
222function macrosession_print($a) {
223        if (isset($_GET['debug']))
224                echo '<pre>'.print_r($a, 1).'</pre>';
225        return "''";
226}
227
228function 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
326function 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
334function balise__AUTORISER_SINON_dist($p) {
335        return balise__SESSION_SINON_dist($p);
336}
337
338function balise__AUTORISER_FIN_dist($p) {
339        return balise__SESSION_FIN_dist($p);
340}
341 
342
343function 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}
Note: See TracBrowser for help on using the repository browser.