source: spip-zone/_plugins_/crayons/trunk/action/crayons_store.php @ 110279

Last change on this file since 110279 was 110279, checked in by pierre.laszczak@…, 2 years ago

Sur une bdd externe on utilisera sql_updateq qui sait gérer les prefixes de table (!= spip_).
On garde un semblant de compatibilité.
-> update de z

File size: 18.3 KB
Line 
1<?php
2/**
3 * Crayons
4 * plugin for spip
5 * (c) Fil, toggg 2006-2013
6 * licence GPL
7 */
8
9if (!defined('_ECRIRE_INC_VERSION')) {
10        return;
11}
12
13function verif_secu($w, $secu) {
14        return (
15                $secu == md5($GLOBALS['meta']['alea_ephemere'].'='.$w)
16        or
17                $secu == md5($GLOBALS['meta']['alea_ephemere_ancien'].'='.$w)
18        );
19}
20
21function post_crayons() {
22        $results = array();
23
24        if (isset($_POST['crayons']) and is_array($_POST['crayons'])) {
25                foreach ($_POST['crayons'] as $crayon) {
26                        $name = $_POST['name_'.$crayon];
27                        $content = array();
28                        if ($_POST['fields_'.$crayon]) {
29                                foreach (explode(',', $_POST['fields_'.$crayon]) as $field) {
30                                        // cas particulier d'un envoi de fichier
31                                        if (isset($_FILES['content_'.$crayon.'_'.$field])) {
32                                                if ($_FILES['content_'.$crayon.'_'.$field]['size'] > 0) {
33                                                        $content[$field] = $_FILES['content_'.$crayon.'_'.$field];
34                                                } else {
35                                                        $content[$field] = false;
36                                                }
37                                                // cf. valeur passee dans crayon->md5() : false ou filemtime() du logo
38                                        } else {
39                                                /**
40                                                 * le changement de charset n'est plus necessaire
41                                                 * depuis jquery 1.5 (feature non documentee de jquery!)
42                                                 */
43                                                if (isset($_POST['content_'.$crayon.'_'.$field])) {
44                                                        $content[$field] = is_array($_POST['content_'.$crayon.'_'.$field])
45                                                                ?implode(',', $_POST['content_'.$crayon.'_'.$field])
46                                                                :$_POST['content_'.$crayon.'_'.$field];
47                                                } else {
48                                                        $content[$field] = null;
49                                                }
50                                        }
51                                }
52                        }
53
54                        // Si les donnees POSTees ne correspondent pas a leur md5,
55                        // il faut les traiter
56                        if (isset($name)
57                                and md5(serialize($content)) != $_POST['md5_'.$crayon]) {
58                                if (!isset($_POST['secu_'.$crayon])
59                                        or verif_secu($name, $_POST['secu_' . $crayon])) {
60                                        $results[] = array($name, $content, $_POST['md5_'.$crayon], $crayon);
61                                } else {
62                                        return false; // erreur secu
63                                }
64                        } else {
65                                // cas inchange
66                                $results[] = array($name, $content, false, $crayon);
67                        }
68                }
69        }
70        return $results;
71}
72
73
74function crayons_store($options = array()) {
75        // permettre de surcharger les fonctions de recuperation des valeurs
76        // et de sauvegardes de celles-ci
77        $options = array_merge(array(
78                        'f_get_valeur' => 'crayons_store_get_valeur',
79                        'f_set_modifs' => 'crayons_store_set_modifs',
80                ), $options);
81
82        include_spip('inc/crayons');
83        $wdgcfg = wdgcfg();
84
85        $return = array('$erreur'=>'');
86
87        $postees = post_crayons();
88
89        $invalides = $modifs = $updates = array();
90
91        if (!is_array($postees)) {
92                $return['$erreur'] = _U('crayons:donnees_mal_formatees');
93        } else {
94                foreach ($postees as $postee) {
95                        if ($postee[2] !== false) {
96                                $name = $postee[0];
97                                $content = $postee[1];
98
99                                if ($content && preg_match(_PREG_CRAYON, 'crayon '.$name, $regs)) {
100                                        list(,$crayon,$type,$modele,$id) = $regs;
101                                        $wid = $postee[3];
102
103                                        spip_log("autoriser('crayonner', $type, $id, null, array('modele' => $modele)", 'crayons_distant');
104                                        if (!autoriser('crayonner', $type, $id, null, array('modele' => $modele))) {
105                                                $return['$erreur'] =
106                                                        "$type $id: " . _U('crayons:non_autorise');
107                                        } else {
108                                                // recuperer l'existant pour calculer son md5 et verifier
109                                                // qu'il n'a pas ete modifie entre-temps
110                                                $get_valeur = $options['f_get_valeur'];
111                                                $data = $get_valeur($content, $regs);
112
113                                                $md5 = md5(serialize($data));
114
115                                                // est-ce que le champ a ete modifie dans la base entre-temps ?
116                                                if ($md5 != $postee[2]) {
117                                                        // si oui, la modif demandee correspond peut-etre
118                                                        // a la nouvelle valeur ? dans ce cas on procede
119                                                        // comme si "pas de modification", sinon erreur
120                                                        if ($md5 != md5(serialize($content))) {
121                                                                $return['$erreur'] = "$type $id $modele: " .
122                                                                        _U('crayons:modifie_par_ailleurs');
123                                                        }
124                                                }
125
126                                                // Vérifications, en retournant presque comme le pipeline formulaire_verifier
127                                                // On permet aussi de modifier la valeur soumise, si une valeur est retournée dans normaliser.
128                                                $data = pipeline(
129                                                        'crayons_verifier',
130                                                        array(
131                                                                'args' => array(
132                                                                        'type' => $type,
133                                                                        'modele' => $modele,
134                                                                        'id' => $id,
135                                                                        'content' => $content,
136                                                                        'wid' => $wid,
137                                                                ),
138                                                                'data' => array(
139                                                                        'erreurs' => array(), // couples : champ => texte d'erreur
140                                                                        'normaliser' => array(), // couples : champ => valeur à utiliser
141                                                                ),
142                                                        )
143                                                );
144
145                                                if (count($data['normaliser'])) {
146                                                        $content = $data['normaliser'] + $content;
147                                                }
148
149                                                if ($data['erreurs']) {
150                                                        foreach ($data['erreurs'] as $c => $e) {
151                                                                $invalides[$wid . '_' . $c]['msg'] = $e;
152                                                        }
153                                                }
154
155                                                $modifs[] = array($type, $modele, $id, $content, $wid);
156
157                                                // Anciennes méthodes de vérifications.
158                                                // Aiguillage pour verification de la saisie
159                                                // Pour traitement ulterieur les fonctions de verifications doivent renvoyer $invalides :
160                                                // $invalides[wid_champ]['msg'] -> message de saisie invalide
161                                                // $invalides[wid_champ]['retour'] -> caracteres invalides
162                                                $f = 'verifier_'.$type.'_'.$modele;
163                                                if (function_exists($f)) {
164                                                        $_invalides = $f($modifs);
165                                                        if ($_invalides and is_array($invalides)) {
166                                                                $invalides = array_merge($invalides, $_invalides);
167                                                        }
168                                                }
169
170                                        }
171                                }
172                        }
173                }
174        }
175
176        if (!$modifs and !$return['$erreur']) {
177                $return['$erreur'] = $wdgcfg['msgNoChange'] ? _U('crayons:pas_de_modification') : ' ';
178                $return['$annuler'] = true;
179        }
180
181        // un champ invalide ... ou rien ==> on ne fait rien !
182        if (count($invalides)) {
183                $return['$invalides'] = $invalides;
184                return $return;
185        }
186
187        // une quelconque erreur ... ou rien ==> on ne fait rien !
188        if (isset($return['$erreur']) and $return['$erreur']) {
189                return $return;
190        }
191
192        // on traite toutes les modifications
193        // en appelant la fonction adequate de traitement
194        $set_modifs = $options['f_set_modifs'];
195        $return = $set_modifs($modifs, $return);
196
197        // une quelconque erreur ... ou rien ==> on ne fait rien !
198        if ($return['$erreur']) {
199                return $return;
200        }
201
202        // et maintenant refaire l'affichage des crayons modifies
203        include_spip('inc/texte');
204        foreach ($modifs as $m) {
205                list($type, $modele, $id, $content, $wid) = $m;
206                        $f = charger_fonction($type.'_'.$modele, 'vues', true)
207                                or $f = charger_fonction($modele, 'vues', true)
208                                or $f = charger_fonction($type, 'vues', true)
209                                or $f = 'vues_dist';
210                        $return[$wid] = $f($type, $modele, $id, $content, $wid);
211        }
212        return $return;
213}
214
215// recuperer une valeur en fonction des parametres recuperes
216// cette fonction cherche une valeur d'une colonne d'une table SQL
217function crayons_store_get_valeur($content, $regs) {
218        list(,$crayon,$type,$modele,$id) = $regs;
219        return valeur_colonne_table($type, array_keys($content), $id);
220}
221
222// stocke les valeurs envoyees dans des colonnes de table SQL
223function crayons_store_set_modifs($modifs, $return) {
224        // sinon on bosse : toutes les modifs ont ete acceptees
225        // verifier qu'on a tout ce qu'il faut pour mettre a jour la base
226        // et regrouper les mises a jour par type/id
227        foreach ($modifs as $modif) {
228                list($type, $modele, $id, $content, $wid) = $modif;
229
230                $fun = '';
231                // si le crayon est un MODELE avec une fonction xxx_revision associee
232                // cas ou une fonction xxx_revision existe
233                if (function_exists($f = $type.'_'. $modele . '_revision')
234                        or function_exists($f = $modele . '_revision')
235                        or function_exists($f = $type . '_revision')) {
236                        $fun = $f;
237                } elseif (function_exists('lister_tables_objets_sql')
238                        and $tables_objet = lister_tables_objets_sql()
239                        and isset($tables_objet[table_objet_sql($type)])) {
240                        // si on est en SPIP 3+ et qu'on edite un objet editorial bien declare
241                        // passer par l'API objet_modifier
242                        $fun = 'crayons_objet_modifier';
243                } else {
244                        // sinon spip < 3 (ou pas un objet edito)
245                        // on teste les objets connus et on route sur les fonctions correspondantes
246                        switch ($type) {
247                                case 'article':
248                                        $fun = 'crayons_update_article';
249                                        break;
250                                case 'breve':
251                                        include_spip('action/editer_breve');
252                                        $fun = 'revisions_breves';
253                                        break;
254                                case 'forum':
255                                        include_spip('inc/forum');
256                                        $fun = 'enregistre_et_modifie_forum';
257                                        break;
258                                case 'rubrique':
259                                        include_spip('action/editer_rubrique');
260                                        $fun = 'revisions_rubriques';
261                                        break;
262                                case 'syndic':
263                                case 'site':
264                                        include_spip('action/editer_site');
265                                        $fun = 'revisions_sites';
266                                        break;
267                                case 'document':
268                                        include_spip('plugins/installer');
269                                        include_spip('inc/plugin');
270                                        if (spip_version_compare($GLOBALS['spip_version_branche'], '3.0.0alpha', '>=')) {
271                                                include_spip('action/editer_document');
272                                                $fun = 'document_modifier';
273                                        } else {
274                                                include_spip('inc/modifier');
275                                                $fun = 'revision_document';
276                                        }
277                                        break;
278                                // cas geres de la maniere la plus standard
279                                case 'auteur':
280                                case 'mot':
281                                case 'signature':
282                                case 'petition':
283                                default:
284                                        include_spip('inc/modifier');
285                                        $fun = 'revision_'.$type;
286                                        break;
287                        }
288                }
289                // si on a pas reussi on passe par crayons_update() qui fera un update sql brutal
290                if (!$fun or !function_exists($fun)) {
291                        $fun = 'crayons_update';
292                        // $return['$erreur'] = "$type: " . _U('crayons:non_implemente');
293                        // break;
294                }
295
296                if (!isset($updates[$type][$fun])) {
297                        $updates[$type][$fun] = array();
298                }
299                if (!isset($updates[$type][$fun][$id])) {
300                        $updates[$type][$fun][$id] = array('wdg'=>array(), 'chval'=>array());
301                }
302                // pour reaffecter le retour d'erreur sql au cas ou
303                $updates[$type][$fun][$id]['wdg'][] = $wid;
304                foreach ($content as $champtable => $val) {
305                        $updates[$type][$fun][$id]['chval'][$champtable] = $val;
306                }
307        }
308
309        // il manque une fonction de mise a jour ==> on ne fait rien !
310        if ($return['$erreur']) {
311                return $return;
312        }
313
314        // hop ! mises a jour table par table et id par id
315        foreach ($updates as $type => $idschamps) {
316                foreach ($idschamps as $fun => $ids) {
317                        foreach ($ids as $id => $champsvaleurs) {
318                                /* cas particulier du logo dans un crayon complexe :
319                                   ce n'est pas un champ de la table */
320                                if (isset($champsvaleurs['chval']['logo'])) {
321                                        spip_log('revision logo', 'crayons');
322                                        logo_revision($id, $champsvaleurs['chval'], $type, $champsvaleurs['wdg']);
323                                        unset($champsvaleurs['chval']['logo']);
324                                }
325                                if (count($champsvaleurs['chval'])) {
326                                        // -- revisions_articles($id_article, $c) --
327                                        spip_log("$fun($id ...)", 'crayons');
328                                        $updok = $fun($id, $champsvaleurs['chval'], $type, $champsvaleurs['wdg']);
329                                        // Renvoyer erreur si update base distante echoue,
330                                        // on ne regarde pas les updates base local car ils ne renvoient rien
331                                        list($distant,$table) = distant_table($type);
332                                        if ($distant and !$updok) {
333                                                $return['$erreur'] = "$type: " . _U('crayons:update_impossible');
334                                        }
335                                }
336                        }
337                }
338        }
339        return $return;
340}
341
342//
343// VUE
344//
345function vues_dist($type, $modele, $id, $content, $wid) {
346        // pour ce qui a une {lang_select} par defaut dans la boucle,
347        // la regler histoire d'avoir la bonne typo dans le propre()
348        // NB: ceci n'a d'impact que sur le "par defaut" en bas
349        list($distant,$table) = distant_table($type);
350        if (colonne_table($type, 'lang')) {
351                $b = valeur_colonne_table($type, 'lang', $id);
352                lang_select($a = array_pop($b));
353        } else {
354                lang_select($a = $GLOBALS['meta']['langue_site']);
355        }
356
357        // chercher vues/article_toto.html
358        // sinon vues/toto.html
359        if (find_in_path(($fond = 'vues/' . $type . '_' . $modele) . '.html')
360                or find_in_path(($fond = 'vues/' . $modele) .'.html')
361                or find_in_path(($fond = 'vues/' . $type) .'.html')) {
362                $primary = (function_exists('id_table_objet')?id_table_objet($table):'id_' . $table);
363                $contexte = array(
364                        $primary => $id,
365                        'crayon_type' => $type,
366                        'crayon_modele' => $modele,
367                        'champ' => $modele,
368                        'class' => _request('class_'.$wid),
369                        'self' => _request('self'),
370                        'lang' => $GLOBALS['spip_lang']
371                );
372                $contexte = array_merge($contexte, $content);
373                include_spip('public/assembler');
374                return recuperer_fond($fond, $contexte);
375        } else {
376                // vue par defaut
377                // Par precaution on va rechercher la valeur
378                // dans la base de donnees (meme si a priori la valeur est
379                // ce qu'on vient d'envoyer, il y a nettoyage des caracteres et
380                // eventuellement d'autres filtres de saisie...)
381                $bdd = valeur_colonne_table($type, $modele, $id);
382                if (count($bdd)) {
383                        $valeur = array_pop($bdd);
384                } else {
385                        // les champs n'ont pas ete retrouves dans la base
386                        // ce qui signifie a priori que nous sommes en face d'une cle primaire compose
387                        // et qu'un crayon a modifie un element de cette cle (c'est pas malin !)
388                        // dans ce cas, on reaffiche a minima ce qu'on vient de publier
389                        // mais il sera impossible de le reediter dans la foulee avec le meme crayon
390                        // (car l'identifiant du crayon se base sur l'id).
391                        // Il faudra donc recharger la page pour pouvoir reediter.
392                        if (is_scalar($id)) {
393                                $valeur = $content[$modele];
394                        }
395                }
396
397                if ($valeur) {
398                        // seul spip core sait rendre les donnees
399                        if (function_exists('appliquer_traitement_champ')) {
400                                $valeur = appliquer_traitement_champ($valeur, $modele, table_objet($table));
401                        } else {
402                                if (in_array($modele, array('chapo', 'texte', 'descriptif', 'ps', 'bio'))) {
403                                        $valeur = propre($valeur);
404                                } else {
405                                        $valeur = typo($valeur);
406                                }
407                        }
408                }
409                return $valeur;
410        }
411}
412
413
414/**
415 * Fonction de mise a jour par API editer_objet
416 * @param $id
417 * @param $data
418 * @param $type
419 * @param $ref
420 * @return bool|mixed|string
421 */
422function crayons_objet_modifier($id, $data, $type, $ref) {
423        if (include_spip('action/editer_objet')
424                and function_exists('objet_modifier')) {
425                $type = objet_type($type);
426                // objet_modifier attend id_parent pour le parent et pas id_rubrique
427                if (isset($data['id_rubrique']) and !isset($data['id_parent']) and $type!=='rubrique') {
428                        $data['id_parent'] = $data['id_rubrique'];
429                }
430                return objet_modifier($type, $id, $data);
431        }
432        // fallback
433        return crayons_update($id, $data, $type);
434}
435
436//
437// Fonctions de mise a jour generique
438//
439function crayons_update($id, $colval = array(), $type = '') {
440        if (!$colval or !count($colval)) {
441                return false;
442        }
443        list($distant,$table) = distant_table($type);
444
445        if ($distant) {
446                list($nom_table, $where) = table_where($type, $id);
447                if (!$nom_table) {
448                        return false;
449                }
450
451                $update = $sep = '';
452                foreach ($colval as $col => $val) {
453                        $update .= $sep . '`' . $col . '`=' . _q($val);
454                        $sep = ', ';
455                }
456
457                // Sur une bdd externe on utilise sql_updateq de preference ;
458        // l'api sql sait gerer les prefixes contrairement a spip_query.
459        // On garde un semblant de compatibilité
460        if ( isset($GLOBALS['spip_version_code']) && $GLOBALS['spip_version_code'] >= '1.93' ) {
461            $a = sql_updateq($nom_table , array($col => $val), $where,'',$distant);
462        }
463        else {
464            $a = spip_query($q = 'UPDATE `' . $nom_table . '` SET ' . $update . ' WHERE ' . $where, $distant);
465            #spip_log($q);
466        }
467
468                include_spip('inc/invalideur');
469
470                // Pour une base externe doit on prefixer le type avec le nom du connecteur?
471        // ex: nomconnect_objet
472                suivre_invalideur($type, $modif = true);
473
474        } else {
475                // cle primaire composee : 3-4-rubrique
476                // calculer un where approprie
477                // et modifier sans passer par la fonction destinee aux tables principales
478                // on limite a SPIP 2 mini car sql_updateq n'est pas mappe dans les crayons_compat
479                if (is_scalar($id) and ($GLOBALS['spip_version_code'] >= '1.93')) {
480                        list($nom_table, $where) = table_where($type, $id, true); // where sous forme de tableau
481                        $a = sql_updateq($nom_table, $colval, $where);
482                } else {
483                        // modification d'une table principale
484                        include_spip('inc/modifier');
485                        $a = modifier_contenu($type, $id, array(), $colval);
486                }
487        }
488        return $a;
489}
490
491//
492// Fonctions de mise a jour
493//
494function crayons_update_article($id_article, $c = false) {
495        include_spip('action/editer_article');
496
497        // Enregistrer les nouveaux contenus
498        revisions_articles($id_article, $c);
499
500        // En cas de statut ou de id_rubrique
501        // NB: instituer_article veut id_parent, et pas id_rubrique !
502        if (isset($c['id_rubrique'])) {
503                $c['id_parent'] = $c['id_rubrique'];
504                unset($c['id_rubrique']);
505        }
506        instituer_article($id_article, $c);
507}
508
509/**
510 * Enregistre les modifications sur une configuration
511 * suite à un crayon sur une meta
512 *
513 * La colonne est toujours 'valeur' pour ces données.
514 * La donnée à enregistrer peut-être une sous partie de configuration.
515 * Si c'est le cas, on gère l'enregistrement via ecrire_config.
516 *
517 * @param string $a
518 *   Nom ou clé de la meta (descriptif_site ou demo__truc pour demo/truc)
519 * @param bool|array $c
520 *   Liste des champs modifiés
521 *   Ici, 'valeur' normalement.
522 * @return void
523**/
524function revision_meta($a, $c = false) {
525        if (isset($c['valeur'])) {
526                // Certaines cles de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})
527                $a = str_replace('__', '/', $a);
528                spip_log("meta '$a' = '$c[valeur]'", 'crayons');
529                // eviter de planter les vieux SPIP
530                if (false === strpos($a, '/')) {
531                        ecrire_meta($a, $c['valeur']);
532                // SPIP 3 ou Bonux 2 ou CFG
533                } else {
534                        include_spip('inc/config');
535                        ecrire_config($a, $c['valeur']);
536                }
537                include_spip('inc/invalideur');
538                suivre_invalideur('meta');
539        }
540}
541
542
543// TODO:
544// Ce modele est cense enregistrer les tags sous forme de ??
545// une ligne dans un champ spip_articles.tags, et/ou des mots-cles...
546function modeles_tags($id, $c) {
547        var_dump($id); #id_article
548        var_dump($c); # perturbant : ici on a array('id_article'=>'valeur envoyee')
549}
550
551function action_crayons_store_dist() {
552        return action_crayons_store_args();
553}
554
555// permettre de passer une autre fonction de stockage des informations
556function action_crayons_store_args($store = 'crayons_store') {
557        header('Content-Type: text/plain; charset='.$GLOBALS['meta']['charset']);
558        lang_select($GLOBALS['auteur_session']['lang']);
559
560        $r = $store();
561
562        // Si on a ete appeles par jQuery, on renvoie tout, c'est le client
563        // crayons.js qui va traiter l'affichage du resultat et status
564        # Attention le test $_SERVER["HTTP_X_REQUESTED_WITH"] === "XMLHttpRequest"
565        # n'est pas bon car le cas d'un fichier uploade via iframe n'est pas detecte
566
567        // S'il y a une adresse de redirection, on renvoie vers elle
568        // En cas d'erreur il faudrait ajouter &err=... dans l'url ?
569        if (_request('redirect')) {
570                if (!$r['$erreur']
571                        or $r['$annuler']) {
572                        include_spip('inc/headers');
573                        redirige_par_entete(_request('redirect'));
574                } else {
575                        echo "<h4 class='status'>".$r['$erreur']."</h4>\n";
576
577                        foreach ($r as $wid => $v) {
578                                if ($wid !== '$erreur') {
579                                        echo "<div id='$wid'>$v</div><hr />\n";
580                                }
581                        }
582                        echo "<a href='".quote_amp(_request('redirect'))."'>"
583                                .quote_amp(_request('redirect'))
584                                ."</a>\n";
585                }
586        } else {
587                // Cas normal : JSON
588                echo crayons_json_export($r);
589        }
590
591        exit;
592}
Note: See TracBrowser for help on using the repository browser.