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

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