source: spip-zone/_plugins_/_stable_/cfg/inc/cfg_formulaire.php @ 18706

Last change on this file since 18706 was 18706, checked in by marcimat@…, 12 years ago
  • nouvelle propriété <!-- head= ce que l'on veut --> qui permet d'envoyer du contenu dans le head de l'espace privé lorsque le fond qui le contient est selectionné. (attention à la présence de --> dans ce contenu qui pourrait gêner le compilateur de CFG)
File size: 14.2 KB
Line 
1<?php
2
3/*
4 * Plugin CFG pour SPIP
5 * (c) toggg 2007, distribue sous licence GNU/GPL
6 * Documentation et contact: http://www.spip-contrib.net/
7 *
8 */
9
10if (!defined("_ECRIRE_INC_VERSION")) return;
11
12
13// la classe cfg represente une page de configuration
14class cfg_formulaire
15{
16// le storage, par defaut metapack: spip_meta serialise
17        var $storage = 'metapack';
18// l'objet de classe cfg_<storage> qui assure lecture/ecriture des config
19        var $sto = null;
20// les options de creation de cet objet
21        var $optsto = array();
22// le "faire" de autoriser($faire), par defaut, autoriser_configurer_dist()
23        var $autoriser = 'configurer';
24// la config est-elle permise ?
25        var $_permise = false;
26// en cas de refus, un message informatif [(#REM) refus=...]
27        var $refus = '';
28// partie du fond cfg a inserer dans le head par le pipeline header_prive (todo insert_head?)
29        var $head = '';
30// le nom du meta (ou autre) ou va etre stocke la config concernee
31        var $nom = '';
32// le fond html utilise , en general pour config simple idem $nom
33        var $vue = '';
34// pour une config multiple , l'id courant
35        var $cfg_id = '';
36// sous tableau optionel du meta ou va etre stocke le fragment de config
37// vide = a la "racine" du meta nomme $nom
38        var $casier = '';
39// descriptif
40        var $descriptif = '';
41// cfg doit-il encadrer le formulaire tout seul ?
42        var $presentation = 'auto';
43// cfg doit-il afficher un lien vers le fond sous forme d'onglet
44// dans la page ?exec=cfg
45        var $onglet = 'oui'; 
46// compte-rendu des mises a jour, vide == pas d'erreur
47        var $message = '';
48// afficher ce compte rendu ?
49        var $afficher_messages = true;
50// liens optionnels sur des sous-config <!-- liens*=xxx -->
51        var $liens = array();
52// liens optionnels sur des sous-config pour des fonds utilisant un champ multiple  <!-- liens_multi*=xxx -->
53        var $liens_multi = array();
54// les champs trouve dans le fond
55        var $champs = array();
56// les champs index
57        var $champs_id = array();
58// leurs valeurs
59        var $val = array();
60// nom de la table sql pour storage extra ou table
61        var $table = '';
62// autoriser l'insertion de nouveau contenu dans une table sans donner d'identifiant ?
63        var $autoriser_absence_id = 'non';
64// pour tracer les valeurs modifiees
65        var $log_modif = '';
66// stockage du fond compile par recuperer_fond()
67        var $fond_compile = '';
68// configuration des types
69//TODO traductions
70        var $types = array(
71                  'id' => array('#^[a-z_]\w*$#i', 'lettre ou &#095; suivie de lettres, chiffres ou &#095;'),
72                  'idnum' => array('#^\d+$#', 'chiffres', 'intval'),
73                  'pwd' => array('#^.{5}#', 'minimum 5 caract&egrave;res;'));
74       
75        /*
76         * Constructeur de la classe
77         */
78        function cfg_formulaire($nom, $vue = '', $cfg_id = '', $opt = array())
79        {
80                $this->nom = $nom;
81                $this->base_url = generer_url_ecrire('');
82                foreach ($opt as $o=>$v) {
83                        $this->$o = $v;
84                }
85
86                // pre-analyser le formulaire
87                // c'est a dire recuperer les parametres CFG et les noms des champs du formulaire
88                if ($vue) {
89                        $erreur = $this->set_vue($vue);
90                        $this->message .= $erreur;
91                }
92
93                $this->_permise = $this->autoriser();
94               
95                /*
96                 * Cas des champs multi, si des champs (Y)
97                 * sont declares id par la classe cfg_id,
98                 * <input type='x' name='Yn' class='cfg_id'>
99                 * on les ajoute dans le chemin pour retrouver les donnees
100                 * #CONFIG{.../y1/y2/y3/...}
101                 *
102                 */
103                if (_request('_cfg_affiche')) {
104                        $this->cfg_id = $sep = '';
105                        foreach ($this->champs_id as $name) {
106                                $this->cfg_id .= $sep . _request($name);
107                                $sep = '/';
108                    }
109            } else {
110                        $this->cfg_id = $cfg_id;
111            }
112               
113                // creer le storage et lire les valeurs
114                $this->storage = strtolower(trim($this->storage));
115                $classto = 'cfg_' . $this->storage;
116                include_spip('inc/' . $classto);
117                $this->sto = new $classto($this, $this->optsto);
118                $this->val = $this->sto->lire();
119        }
120
121
122        /*
123         * Determine l'arborescence ou CFG doit chercher les valeurs deja enregistrees
124         * si nom=toto, casier=chose/truc, cfg_id=2,
125         * cfg cherchera dans #CONFIG{toto/chose/truc/2}
126         *
127         */
128        function nom_config()
129        {
130            return $this->nom . ($this->casier ? '/' . $this->casier : '') .
131                        ($this->cfg_id ? '/' . $this->cfg_id : '');
132        }
133
134        /*
135         * La vue est le nom du fond CFG a lire.
136         *
137         * On lit le fond et on recupere
138         * - les parametres CFG contenus dans les balises [(#REM) param=valeur]
139         * - ainsi que les nom des champs de formulaires
140         *
141         */
142        function set_vue($vue)
143        {
144                // lecture de la vue.
145                $this->vue = $vue;
146                $fichier = find_in_path($nom = 'fonds/cfg_' . $this->vue .'.html');
147                if (!lire_fichier($fichier, $this->controldata)) {
148                        return _T('cfg:erreur_lecture', array('nom' => $nom));
149                }
150               
151                // recherche et stockage des parametres de cfg
152                $this->recuperer_parametres();
153                // recherche et stockage des noms de champs de formulaire
154                return $this->recuperer_noms_champs();
155        }
156
157
158
159        /*
160         *
161         * Recherche et stockage
162         * des parametres passes a CFG
163         * par <!--
164         * ou par #REM (deprecie)
165         */
166        function recuperer_parametres(){
167                // cas de #REM (deprecie)
168                preg_replace_callback('/(\[\(#REM\) ([a-z0-9_]\w+)(\*)?=)(.*?)\]/sim',
169                                        array(&$this, 'post_params'), $this->controldata);
170                                       
171                // cas de <!--
172                // liste des post-proprietes de l'objet cfg, lues apres recuperer_fond()
173                // et stockees dans <!-- param=valeur -->
174                $this->recuperer_parametres_post_compile();
175
176        }
177       
178       
179        function recuperer_parametres_post_compile(){
180                $this->rempar = array(array());
181                if (preg_match_all('/<!-- [a-z0-9_]\w+\*?=/i', $this->controldata, $this->rempar)) {
182                        // il existe des champs <!-- param=valeur -->, on les stocke
183                        $this->recuperer_fond();
184                        $this->current_rempar = 0;
185                        $this->fond_compile = preg_replace_callback('/(<!-- ([a-z0-9_]\w+)(\*)?=)(.*?)-->/sim',
186                                                                array(&$this, 'post_params'), $this->fond_compile);
187                        // s'il en reste : il y a un probleme !
188                        if (preg_match('/<!-- [a-z0-9_]\w+\*?=/', $this->fond_compile)) {
189                                die('erreur manque parametre externe: '
190                                        . htmlentities(var_export($this->rempar, true)));
191                        }
192                }               
193        }
194       
195       
196        /*
197         *
198         * Recherche et stockage
199         * des noms des champs (y) du formulaire
200         * <input type="x" name="y"... />
201         *
202         */     
203        function recuperer_noms_champs(){       
204                // recherche d'au moins un champ de formulaire pour savoir si la vue est valide
205                $this->recuperer_fond();
206                if (!preg_match_all(
207                  '#<(?:(select|textarea)|input type="(text|password|checkbox|radio|hidden)") name="(\w+)(\[\])?"(?: class="[^"]*?(?:type_(\w+))?[^"]*?(?:cfg_(\w+))?[^"]*?")?( multiple=)?[^>]*?>#ims',
208                                                $this->fond_compile, $matches, PREG_SET_ORDER)) {
209                        return _T('cfg:pas_de_champs_dans', array('nom' => $this->vue));
210                }
211               
212                // stockage des champs trouves dans $this->champs
213                foreach ($matches as $regs) {
214                        if (substr($regs[3], 0, 5) == '_cfg_') {
215                                continue;
216                        }
217                    if (!empty($regs[1])) {
218                        $regs[2] = strtolower($regs[1]);
219                            if ($regs[2] == 'select' && !empty($regs[7])) {
220                                $regs[2] = 'selmul';
221                            }
222                    }
223                    $this->champs[$regs[3]] =
224                        array('inp' => $regs[2], 'typ' => '', 'array' => !empty($regs[4]));
225                    if (!empty($regs[5])) {
226                        $this->champs[$regs[3]]['typ'] = $regs[5];
227                    }
228                    if (!empty($regs[6])) {
229                        $this->champs[$regs[3]]['cfg'] = $regs[6];
230                        if ($regs[6] == 'id') {
231                                $this->champs[$regs[3]]['id'] = count($this->champs_id);
232                                $this->champs_id[] = $regs[3];
233                        }
234                    }
235            }
236            return '';
237        }       
238         
239       
240        /*
241         *
242         * Compiler le fond CFG si ce n'est pas fait
243         *
244         */
245        function recuperer_fond($contexte = array(), $forcer = false){
246                if (!$this->fond_compile OR $forcer){
247                        include_spip('inc/presentation'); // offrir les fonctions d'espace prive
248                        include_spip('public/assembler');
249                        $this->fond_compile = recuperer_fond(
250                                        'fonds/cfg_' . $this->vue,
251                                        $this->val 
252                                                ? array_merge($contexte, $this->val) 
253                                                : $contexte);
254                }
255        }
256       
257       
258        /*
259         * Verifie les autorisations
260         * d'affichage du formulaire
261         * (parametre autoriser=quoi)
262         */
263        function autoriser()
264        {
265                include_spip('inc/autoriser');
266                return autoriser($this->autoriser);
267        }
268
269        /*
270         * Log le message passe en parametre
271         * $this->log('message');
272         */
273        function log($message)
274        {
275                ($GLOBALS['auteur_session'] && ($qui = $GLOBALS['auteur_session']['login']))
276                || ($qui = $GLOBALS['ip']);
277                spip_log('cfg (' . $this->nom_config() . ') par ' . $qui . ': ' . $message);
278        }
279
280       
281        /*
282         * Modifie ou supprime les donnees postees par le formulaire
283         */
284        function modifier($supprimer = false)
285        {
286                // suppression ?
287                if ($supprimer) {
288                        $ok = $this->sto->modifier($supprimer);
289                        // dans le cas d'une suppression, il faut vider $this->val qui
290                        // contient encore les valeurs du formulaire, sinon elles sont
291                        // passees dans le fond et le formulaire garde les informations
292                        // d'avant la suppression
293                        if ($ok) {
294                                $this->val = array();
295                                $msg = _T('cfg:config_supprimee', array('nom' => $this->nom_config()));
296                        } else {
297                                $msg = _T('cfg:erreur_suppression', array('nom' => $this->nom_config()));
298                        }
299                        $this->message .= $msg;
300                        $this->log($msg);
301                }
302                // sinon verification du type des valeurs postees
303                else if (($this->message = $this->controle())) {
304                }
305                // si valeurs valides, ont elles changees ?
306                else if (!$this->log_modif) {
307                        $this->message .= _T('cfg:pas_de_changement', array('nom' => $this->nom_config()));
308                }
309                // si elles ont changees, on modifie !
310                else {
311                        $ok = $this->sto->modifier();
312                        $this->message .= ($msg = $ok 
313                                                ? _T('cfg:config_enregistree', array('nom' => $this->nom_config())) 
314                                                : _T('cfg:erreur_enregistrement', array('nom' => $this->nom_config())));
315                        $this->log($msg . ' ' . $this->log_modif);
316                }
317                // pipeline 'cfg_post_edition'
318                $this->message = pipeline('cfg_post_edition',array('args'=>array('nom_config'=>$this->nom_config()),'data'=>$this->message));
319        }
320
321
322        /*
323         * Gere le traitement du formulaire qui a ete valide.
324         *
325         */
326        function traiter()
327        {
328                // est on autorise ?
329                if (!$this->_permise) {
330                        return;
331                }
332       
333                // enregistrement ou suppression ?
334                $enregistrer = $supprimer = false;
335                if ($this->message ||
336                        ! (($enregistrer = _request('_cfg_ok')) ||
337                                                        ($supprimer = _request('_cfg_delete')))) {
338                        return;
339                }
340       
341                $securiser_action = charger_fonction('securiser_action', 'inc');
342                $securiser_action();
343                // suppression
344                if ($supprimer) {
345                        $this->modifier('supprimer');
346                // sinon modification
347                // seulement si les types de valeurs attendus sont corrects
348                } elseif (!($this->message = $this->controle())) {
349
350                        if ($this->new_id != $this->cfg_id && !_request('_cfg_copier')) {
351                                $this->modifier('supprimer');
352                        }
353                        $this->cfg_id = $this->new_id;
354                        $this->modifier();
355                }
356
357                // Si le fond du formulaire demande expressement une redirection
358                // par <!-- rediriger=1 -->, on stocke le message dans une meta
359                // et on redirige le client, de maniere a charger la page
360                // avec la nouvelle config (ce qui permet par exemple a Autorite
361                // de controler d'eventuels conflits generes par les nouvelles autorisations)
362                if ($this->rediriger && $this->message) {
363                        include_spip('inc/meta');
364                        ecrire_meta('cfg_message_'.$GLOBALS['auteur_session']['id_auteur'], $this->message, 'non');
365                        if (defined('_COMPAT_CFG_192')) ecrire_metas();
366                        include_spip('inc/headers');
367                        redirige_par_entete(parametre_url(self(),null,null,'&'));
368                }
369        }
370
371        /*
372         * Verifie les valeurs postees.
373         * - stocke les valeurs qui ont changees dans $this->val[$nom_champ] = 'nouvelle_valeur'
374         * - verifie que les types de valeurs attendus sont corrects ($this->types)
375         */
376        function controle()
377        {
378            $return = '';
379
380                foreach ($this->champs as $name => $def) {
381                        // enregistrement des valeurs postees
382                        $oldval = $this->val[$name];
383                    $this->val[$name] = _request($name);
384                    if ($oldval != $this->val[$name]) {
385                        $this->log_modif .= $name . ':' .
386                                var_export($oldval, true) . '/' . var_export($this->val[$name], true) .', ';
387                    }
388                    // verification du type de valeur attendue
389                    // cela est defini par un nom de class css (class="type_idnum")
390                    // 'idnum' etant defini dans $this->types['idnum']...
391                    // si le nom du champ possede une traduction, il sera traduit.
392                    if (!empty($def['typ']) && isset($this->types[$def['typ']])) {
393                        if (!preg_match($this->types[$def['typ']][0], $this->val[$name])) {
394                                $return .= _T($name) . '&nbsp;:<br />' .
395                                  $this->types[$def['typ']][1] . '<br />';
396                        }
397                    }
398            }
399            // donner un identifiant au formulaire ?
400                $this->new_id = '';
401                $sep = '';
402                foreach ($this->champs_id as $name) {
403                        $this->new_id .= $sep . $this->val[$name];
404                        $sep = '/';
405            }
406            return $return;
407        }
408
409        /*
410         * Fabriquer les balises des champs d'apres un modele fonds/cfg_<driver>.html
411         * $contexte est un tableau (nom=>valeur)
412         * qui sera enrichi puis passe a recuperer_fond
413         */
414        function formulaire($contexte = array())
415        {
416                if (!find_in_path('fonds/cfg_' . $this->vue . '.html'))
417                        return '';
418
419                include_spip('inc/securiser_action');
420            $arg = 'cfg0.0.0-' . $this->nom . '-' . $this->vue;
421                $contexte['_cfg_'] =
422                        '?exec=cfg&cfg=' . $this->nom .
423                        '&cfg_vue=' . $this->vue .
424                        '&cfg_id=' . $this->cfg_id .
425                        '&base_url=' . $this->base_url .
426                    '&lang=' . $GLOBALS['spip_lang'] .
427                    '&arg=' . $arg .
428                    '&hash=' .  calculer_action_auteur('-' . $arg);
429
430                // recuperer le fond avec le contexte
431                // forcer le calcul.
432                $this->recuperer_fond($contexte, true);
433                $this->recuperer_parametres_post_compile(); // pour enlever les <!-- param=valeur --> ...
434                return $this->fond_compile;
435        }
436       
437       
438        /*
439         * callback pour interpreter les parametres objets du formulaire
440         * commun avec celui de set_vue()
441         *
442         * Parametres :
443         * - $regs[2] = 'param'
444         * - $regs[3] = '*' ou ''
445         * - $regs[4] = 'valeur'
446         *
447         * Lorsque des parametres sont passes dans le formulaire
448         * [(#REM) param=valeur] ou <!-- param=valeur -->
449         * stocker $this->param=valeur
450         *
451         * Si <!-- param*=valeur -->
452         * Stocker $this->param[]=valeur
453         *
454         */
455        function post_params($regs) {
456                // a priori, eviter l'injection du motif
457                if (isset($this->rempar)) {
458                        if (!isset($this->rempar[0][$this->current_rempar])
459                                || $regs[1] != $this->rempar[0][$this->current_rempar++]) {
460                                die("erreur parametre interne: " . htmlentities(var_export($regs[1], true)));
461                        }
462                }
463                // $regs[3] peut valoir '*' pour signaler un tableau
464                $regs[4] = trim($regs[4]);
465               
466                if (empty($regs[3])) {
467                    $this->{$regs[2]} = $regs[4];
468                } elseif (is_array($this->{$regs[2]})) {
469                    $this->{$regs[2]}[] = $regs[4];
470                }
471                // plus besoin de garder ca
472                return '';
473        }
474}
475?>
Note: See TracBrowser for help on using the repository browser.