source: spip-zone/_plugins_/formidable/trunk/inc/formidable.php @ 118240

Last change on this file since 118240 was 118240, checked in by maieul@…, 6 months ago

ordre de configuration des traitements -> ordre d'execution (pipeline formidable_traitements)

File size: 18.8 KB
Line 
1<?php
2
3// Sécurité
4if (!defined('_ECRIRE_INC_VERSION')) {
5        return;
6}
7
8/*
9 * Liste tous les traitements configurables (ayant une description)
10 *
11 * @return array Un tableau listant des saisies et leurs options
12 */
13function traitements_lister_disponibles() {
14        static $traitements = null;
15
16        if (is_null($traitements)) {
17                $traitements = array();
18                $liste = find_all_in_path('traiter/', '.+[.]yaml$');
19                ksort($liste);
20
21                if (count($liste)) {
22                        foreach ($liste as $fichier => $chemin) {
23                                $type_traitement = preg_replace(',[.]yaml$,i', '', $fichier);
24                                // On ne garde que les traitements qui ont bien la fonction
25                                if (charger_fonction($type_traitement, 'traiter', true)
26                                        and (
27                                                is_array($traitement = traitements_charger_infos($type_traitement))
28                                        )
29                                ) {
30                                        $traitements[$type_traitement] = $traitement;
31                                }
32                        }
33                }
34        }
35
36        $traitements = pipeline(
37                'formidable_traitements',
38                array(
39                        'args' => array(
40                                'id_formulaire' => $id_formulaire,
41                                'identifiant' => $formulaire['identifiant']
42                        ),
43                        'data' => $traitements
44                )
45        );
46        return $traitements;
47}
48
49/**
50 * Charger les informations contenues dans le yaml d'un traitement
51 *
52 * @param string $type_saisie Le type de la saisie
53 * @return array Un tableau contenant le YAML décodé
54 */
55function traitements_charger_infos($type_traitement) {
56        include_spip('inc/yaml');
57        $fichier = find_in_path("traiter/$type_traitement.yaml");
58        $traitement = yaml_decode_file($fichier);
59
60        if (is_array($traitement)) {
61                $traitement += array('titre' => '', 'description' => '', 'icone' => '');
62                $traitement['titre'] = $traitement['titre'] ? _T_ou_typo($traitement['titre']) : $type_traitement;
63                $traitement['description'] = $traitement['description'] ? _T_ou_typo($traitement['description']) : '';
64                $traitement['icone'] = $traitement['icone'] ? find_in_path($traitement['icone']) : '';
65        }
66        return $traitement;
67}
68
69/*
70 * Liste tous les types d'échanges (export et import) existant pour les formulaires
71 *
72 * @return array Retourne un tableau listant les types d'échanges
73 */
74function echanges_formulaire_lister_disponibles() {
75        // On va chercher toutes les fonctions existantes
76        $liste = find_all_in_path('echanger/formulaire/', '.+[.]php$');
77        $types_echange = array('exporter' => array(), 'importer' => array());
78        if (count($liste)) {
79                foreach ($liste as $fichier => $chemin) {
80                        $type_echange = preg_replace(',[.]php$,i', '', $fichier);
81
82                        // On ne garde que les échanges qui ont bien la fonction
83                        if ($f = charger_fonction('exporter', "echanger/formulaire/$type_echange", true)) {
84                                $types_echange['exporter'][$type_echange] = $f;
85                        }
86                        if ($f = charger_fonction('importer', "echanger/formulaire/$type_echange", true)) {
87                                $types_echange['importer'][$type_echange] = $f;
88                        }
89                }
90        }
91        return $types_echange;
92}
93
94/*
95 * Génère le nom du cookie qui sera utilisé par le plugin lors d'une réponse
96 * par un visiteur non-identifié.
97 *
98 * @param int $id_formulaire L'identifiant du formulaire
99 * @return string Retourne le nom du cookie
100 */
101function formidable_generer_nom_cookie($id_formulaire) {
102        return $GLOBALS['cookie_prefix'].'cookie_formidable_'.$id_formulaire;
103}
104
105
106/*
107 * Trouver la réponse à éditer pour un formulaire donné,
108 * dans un contexte donné
109 * en fonction de la configuration du formulaire.
110 * @param int $id_formulaire L'identifiant du formulaire
111 * @param int $id_formulaires_reponse L'identifant de réponse passé au moment de l'appel du formulaire
112 * @param array $options Les options d'enregistrement du formulaire
113 * @param boolean $verifier_est_auteur si égal à true, on vérifie si $id_formulaires_reponse est passé que l'auteur connecté est bien l'auteur de la réponse passée en argument
114 * @return int $id_formulaires_reponse L'identifiant de la réponse à modifier effectivement.
115 *
116 */
117function formidable_trouver_reponse_a_editer($id_formulaire, $id_formulaires_reponse, $options, $verifier_est_auteur = false) {
118        // Si on passe un identifiant de reponse, on edite cette reponse si elle existe
119        if ($id_formulaires_reponse = intval($id_formulaires_reponse) and ($verifier_est_auteur == false or $options['identification'] == 'id_reponse')) {
120                return $id_formulaires_reponse;
121        } else {
122                // calcul des paramètres d'anonymisation
123
124                $reponses = formidable_verifier_reponse_formulaire(
125                        $id_formulaire,
126                        $options['identification'],
127                        isset($options['variable_php']) ? $options['variable_php'] : ''
128                );
129
130                //A-t-on demandé de vérifier que l'auteur soit bien celui de la réponse?
131                if ($id_formulaires_reponse = intval($id_formulaires_reponse)
132                        and $verifier_est_auteur == true) {
133                        if (!is_array($reponses) or in_array($id_formulaires_reponse, $reponses) == false) {
134                                $id_formulaires_reponse = false;
135                        }
136                        return $id_formulaires_reponse;
137                }
138
139                // Si multiple = non mais que c'est modifiable, alors on va chercher
140                // la dernière réponse si elle existe
141                if ($options
142                        and !$options['multiple']
143                        and $options['modifiable']
144                        and is_array($reponses)
145                        ) {
146                                $id_formulaires_reponse = array_pop($reponses);
147                }
148        }
149        return $id_formulaires_reponse;
150}
151
152/*
153 * Vérifie si le visiteur a déjà répondu à un formulaire
154 *
155 * @param int $id_formulaire L'identifiant du formulaire
156 * @param string $choix_identification Comment verifier une reponse. Priorite sur 'cookie' ou sur 'id_auteur'
157 * @param string $variable_php_identification : la variable php servant à identifier une réponse
158 * @return unknown_type Retourne un tableau contenant les id des réponses si elles existent, sinon false
159 */
160function formidable_verifier_reponse_formulaire($id_formulaire, $choix_identification = 'cookie', $variable_php_identification = '') {
161        global $auteur_session;
162        $id_auteur = $auteur_session ? intval($auteur_session['id_auteur']) : 0;
163        $nom_cookie = formidable_generer_nom_cookie($id_formulaire);
164        $cookie = isset($_COOKIE[$nom_cookie]) ? $_COOKIE[$nom_cookie] : false;
165        $variable_php_identification = formidable_variable_php_identification($variable_php_identification, $id_formulaire);
166
167        // ni cookie ni id, ni variable_php,  on ne peut rien faire
168        if (!$cookie and !$id_auteur and !$variable_php_identification) {
169                return false;
170        }
171
172
173        // Determiner les différentes clauses $WHERE possible en fonction de ce qu'on a
174        $where_id_auteur = '';
175        $where_cookie = '';
176        $where_variable_php = '';
177        if ($id_auteur) {
178                $where_id_auteur = 'id_auteur='.$id_auteur;
179        }
180        if ($cookie) {
181                $where_cookie = 'cookie='.sql_quote($cookie);
182        }
183        if ($variable_php_identification) {
184                $where_variable_php = 'variable_php='.$variable_php_identification;
185        }
186
187        // Comment identifie-t-on? Attention, le choix d'identification indique une PRIORITE, donc cela veut dire que les autres méthodes peuvent venir après, sauf dans le cas d'identification explicitement par id_reponse
188        if ($choix_identification == 'cookie' or !$choix_identification) {
189                if ($cookie) {
190                        $where = array($where_cookie);
191                } else {
192                        $where = array($where_id_auteur, $where_variable_php);
193                }
194        } elseif ($choix_identification == 'id_auteur') {
195                if ($id_auteur) {
196                        $where = array($where_id_auteur);
197                } else {
198                        $where = array($where_cookie, $where_variable_php);
199                }
200        } elseif ($choix_identification == 'variable_php') {
201                if ($variable_php_identification) {
202                        $where = array($where_variable_php);
203                } else {
204                        $where = array($where_cookie, $where_id_auteur);
205                }
206        } elseif ($choix_identification == 'id_reponse') {//Si le filtrage se fait par réponse, on prend tout (mais normalement on devrait pas aboutir ici si tel est le cas)
207                $where = array("1=1");
208        }
209        $where = array_filter($where);//Supprimer les wheres null
210        $where = implode($where, ' OR ');
211
212        $reponses = sql_allfetsel(
213                'id_formulaires_reponse',
214                'spip_formulaires_reponses',
215                array(
216                        array('=', 'id_formulaire', intval($id_formulaire)),
217                        array('=', 'statut', sql_quote('publie')),
218                        $where
219                ),
220                '',
221                'date'
222        );
223
224        if (is_array($reponses)) {
225                return array_map('reset', $reponses);
226        } else {
227                return false;
228        }
229}
230
231/*
232 * Génère la vue d'analyse de toutes les réponses à une saisie
233 *
234 * @param array $saisie Un tableau décrivant une saisie
235 * @param array $env L'environnement, contenant normalement la réponse à la saisie
236 * @return string Retour le HTML des vues
237 */
238function formidable_analyser_saisie($saisie, $valeurs = array(), $reponses_total = 0, $format_brut = false) {
239        // Si le paramètre n'est pas bon ou que c'est un conteneur, on génère du vide
240        if (!is_array($saisie) or (isset($saisie['saisies']) and $saisie['saisies'])) {
241                return '';
242        }
243
244        $contexte = array('reponses_total'=>$reponses_total);
245
246        // On sélectionne le type de saisie
247        $contexte['type_saisie'] = $saisie['saisie'];
248
249        // Peut-être des transformations à faire sur les options textuelles
250        $options = $saisie['options'];
251        foreach ($options as $option => $valeur) {
252                $options[$option] = _T_ou_typo($valeur, 'multi');
253        }
254
255        // On ajoute les options propres à la saisie
256        $contexte = array_merge($contexte, $options);
257
258        // On récupère toutes les valeurs du champ
259        if (isset($valeurs[$contexte['nom']])
260                and $valeurs[$contexte['nom']]
261                and is_array($valeurs[$contexte['nom']])) {
262                $contexte['valeurs'] = $valeurs[$contexte['nom']];
263        } else {
264                $contexte['valeurs'] = array();
265        }
266
267        // On génère la saisie
268        if ($format_brut) {
269                return analyser_saisie($contexte);
270        } else {
271                return recuperer_fond(
272                        'saisies-analyses/_base',
273                        $contexte
274                );
275        }
276}
277
278/*
279 * Renvoie une ligne de réponse sous la forme d'un tableau
280 *
281 * @param array $saisie Un tableau décrivant une saisie
282 * @return array Tableau contenant une ligne
283 */
284function analyser_saisie($saisie) {
285        if (!isset($saisie['type_saisie']) or $saisie['type_saisie'] == '') {
286                return '';
287        }
288
289        $ligne = array();
290
291        switch ($saisie['type_saisie']) {
292                case 'selecteur_rubrique':
293                case 'selecteur_rubrique_article':
294                case 'selecteur_article':
295                        $ligne['plein'] = count(array_filter($saisie['valeurs']));
296                        $ligne['vide'] = count(array_diff_key($saisie['valeurs'], array_filter($saisie['valeurs'])));
297                        break;
298                case 'radio':
299                case 'selection':
300                case 'selection_multiple':
301                case 'choix_couleur':
302                case 'checkbox':
303                        $stats = array();
304                        foreach ($saisie['valeurs'] as $valeur) {
305                                if (is_array($valeur)) {
306                                        foreach ($valeur as $choix) {
307                                                if (isset($stats["choix-$choix"])) {
308                                                        $stats["choix-$choix"]++;
309                                                } else {
310                                                        $stats["choix-$choix"] = 1;
311                                                }
312                                        }
313                                } else {
314                                        if (isset($stats["choix-$valeur"])) {
315                                                $stats["choix-$valeur"]++;
316                                        } else {
317                                                $stats["choix-$valeur"] = 1;
318                                        }
319                                }
320                        }
321                        $datas = is_string($saisie['datas'])
322                                ? saisies_chaine2tableau(saisies_aplatir_chaine($saisie['datas']))
323                                : $saisie['datas'];
324                        foreach ($datas as $key => $val) {
325                                $nb = (isset($stats["choix-$key"]))
326                                        ? $stats["choix-$key"]
327                                        : 0;
328                                $ligne[$val] = $nb;
329                        }
330                        break;
331                case 'destinataires':
332                        $stats = array();
333                        foreach ($saisie['valeurs'] as $valeur) {
334                                foreach ($valeur as $choix) {
335                                        if (isset($stats["choix-$choix"])) {
336                                                $stats["choix-$choix"]++;
337                                        } else {
338                                                $stats["choix-$choix"] = 1;
339                                        }
340                                }
341                        }
342                        foreach ($stats as $key => $val) {
343                                $key = str_replace('choix-', '', $key);
344                                if ($key == '') {
345                                        $key = '<valeur vide>';
346                                }
347                                $auteur = sql_getfetsel('nom', 'spip_auteurs', "id_auteur=$key");
348                                $ligne[$auteur] = $val;
349                        }
350                        break;
351        }
352
353        $vide = 0;
354        foreach ($saisie['valeurs'] as $valeur) {
355                if ($valeur == '') {
356                        $vide++;
357                }
358                switch ($saisie['type_saisie']) {
359                        case 'case':
360                        case 'oui_non':
361                                if (isset($ligne['oui']) == false) {
362                                        $ligne['oui'] = 0;
363                                }
364                                if (isset($ligne['non']) == false) {
365                                        $ligne['non'] = 0;
366                                }
367                                if ($valeur) {
368                                        $ligne['oui']++;
369                                } else {
370                                        $ligne['non']++;
371                                }
372                                break;
373                        case 'input':
374                        case 'hidden':
375                        case 'explication':
376                                break;
377                }
378        }
379        $ligne['sans_reponse'] = $vide;
380        $ligne['header'] = $saisie['label'] != ''
381                ? $saisie['label']
382                : $saisie['type_saisie'];
383
384        return $ligne;
385}
386
387
388/**
389 * Tente de déserialiser un texte
390 *
391 * Si le paramètre est un tableau, retourne le tableau,
392 * Si c'est une chaîne, tente de la désérialiser, sinon
393 * retourne la chaîne.
394 *
395 * @filtre
396 *
397 * @param string|array $texte
398 *       Le texte (possiblement sérializé) ou un tableau
399 * @return array|string
400 *       Tableau, texte désérializé ou texte
401**/
402function filtre_tenter_unserialize_dist($texte) {
403        if (is_array($texte)) {
404                return $texte;
405        }
406        if ($tmp = @unserialize($texte)) {
407                return $tmp;
408        }
409        return $texte;
410}
411
412
413/**
414 * Retourne un texte du nombre de réponses
415 *
416 * @param int $nb
417 *       Nombre de réponses
418 * @return string
419 *       Texte indiquant le nombre de réponses
420**/
421function titre_nb_reponses($nb) {
422        if (!$nb) {
423                return _T('formidable:reponse_aucune');
424        }
425        if ($nb == 1) {
426                return _T('formidable:reponse_une');
427        }
428        return _T('formidable:reponses_nb', array('nb' => $nb));
429}
430
431/**
432 * Transforme le hash MD5 en une valeur numérique unique
433 *
434 * trouvé ici : http://stackoverflow.com/questions/1422725/represent-md5-hash-as-an-integer
435 * @param string $hex_str La valeur alphanumérique à transformer
436 * @return string Valeur numérique
437*/
438function md5_hex_to_dec($hex_str) {
439        $arr = str_split($hex_str, 4);
440        $dec = array();
441        foreach ($arr as $grp) {
442                $dec[] = str_pad(hexdec($grp), 5, '0', STR_PAD_LEFT);
443        }
444
445        /* on s'assure que $result ne commence pas par un zero */
446        $result = implode('', $dec);
447        for ($cpt = 0; $cpt < strlen($result); $cpt++) {
448                if ($result[$cpt] != '0') {
449                        break;
450                }
451        }
452        $result = substr($result, $cpt);
453        return $result;
454}
455
456/**
457 * Transforme un login en une valeur numérique de 19 caractères
458 *
459 * NOTE: il devient impossible de retrouver la valeur d'origine car le HASH
460 * est coupé à 19cars et est donc incomplet. L'unicité n'est pas garantie mais
461 * les chances pour que deux logins tombent sur le même HASH sont de 1 sur
462 * 10 milliards de milliards
463 * A la fin, on recherche et supprime les éventuels zéros de début
464 * @param string $login Login à transformer
465 * @param string $id_form ID du formulaire concerné
466 * @return string Un nombre de 19 chiffres
467*/
468function formidable_scramble($login, $id_form) {
469        if (isset($GLOBALS['formulaires']['passwd']['interne']) == false) {
470                $passwd = $GLOBALS['formulaires']['passwd']['interne'];
471        } else {
472                $passwd = 'palabresecreta';
473        }
474        $login_md5 = md5("$login$passwd$id_form");
475        $login_num = md5_hex_to_dec($login_md5);
476        $login_num = substr($login_num, 0, 19);
477
478        return $login_num;
479}
480
481/**
482 * Dans une chaîne, remplace les @raccourci@
483 * par la valeur saisie.
484 * @param string $chaine la chaîne à transformer
485 * @param array $saisies la liste des saisies du formulaire
486 * @param bool|string $brut=false, pour indiquer si on veut utiliser les valeurs brutes;
487 * @param string|bool $sans_reponse chaine à afficher si pas de réponse. Si true, prend la chaîne par défaut
488 * @return string la chaîne transformée
489 */
490function formidable_raccourcis_arobases_2_valeurs_champs($chaine, $saisies, $brut=false, $sans_reponse = true) {
491        list($valeurs,$valeurs_libellees) = formidable_tableau_valeurs_saisies($saisies, $sans_reponse);
492        $a_remplacer = array();
493        if (preg_match_all('/@[\w]+@/', $chaine, $a_remplacer)) {
494                $a_remplacer = $a_remplacer[0];
495                foreach ($a_remplacer as $cle => $val) {
496                        $a_remplacer[$cle] = trim($val, '@');
497                }
498                $a_remplacer = array_flip($a_remplacer);
499                if ($brut) {
500                        $a_remplacer = array_intersect_key($valeurs, $a_remplacer);
501                }
502                else {
503                        $a_remplacer = array_intersect_key($valeurs_libellees, $a_remplacer);
504                }
505                $a_remplacer = array_merge($a_remplacer, array('nom_site_spip' => lire_config("nom_site")));
506        }
507        return trim(_L($chaine, $a_remplacer));
508}
509/**
510 * Récupère l'ensemble des valeurs postée dans un formulaires
511 * Les retourne sous deux formes : brutes et libellés (par ex. pour les @select@
512 * @param array $saisies les saisies du formulaires
513 * @param string|bool $sans_reponse chaine à afficher si pas de réponse. Si true, prend la chaîne par défaut
514 * @return array (brutes, libellées)
515 * On met les résultats en statiques pour gagner un peu de temps
516 */
517function formidable_tableau_valeurs_saisies($saisies, $sans_reponse = true) {
518        if (isset($valeurs)) {
519                return array($valeurs,$valeurs_libellees);
520        }
521        // On parcourt les champs pour générer le tableau des valeurs
522        static $valeurs = array();
523        static $valeurs_libellees = array();
524        if ($sans_reponse === true) {
525                $sans_reponse =  _T('saisies:sans_reponse');
526        }
527        include_spip('inc/saisies_afficher_si_php');
528        $saisies_apres_afficher_si = saisies_verifier_afficher_si($saisies);
529        $saisies_fichiers = saisies_lister_avec_type($saisies, 'fichiers');
530        $saisies_par_nom = saisies_lister_par_nom($saisies);
531        $saisies_par_nom_apres_afficher_si = saisies_lister_par_nom($saisies_apres_afficher_si);
532        $champs = saisies_lister_champs($saisies);
533
534
535        // On n'utilise pas formulaires_formidable_fichiers,
536        // car celui-ci retourne les saisies fichiers du formulaire dans la base… or, on sait-jamais,
537        // il peut y avoir eu une modification entre le moment où l'utilisateur a vu le formulaire et maintenant
538        foreach ($champs as $champ) {
539                if (array_key_exists($champ, $saisies_fichiers)) {// si on a affaire à une saisie de type fichiers, on considère qu'il n'y pas vraiment de valeur brute
540                } elseif ($saisies_par_nom[$champ]['saisie'] == 'explication') {
541                        $valeurs[$champ] = $saisies_par_nom_apres_afficher_si[$champ]['options']['texte'];
542                        $valeurs_libellees[$champ] =  $valeurs[$champ];
543                }       else {
544                        // On récupère la valeur postée
545                        $valeurs[$champ] = _request($champ);
546                        $valeurs_libellees[$champ] = formidable_nettoyer_saisie_vue(recuperer_fond(
547                                'saisies-vues/_base',
548                                array_merge(
549                                        array(
550                                                'type_saisie' => $saisies_par_nom[$champ]['saisie'],
551                                                'valeur' => $valeurs[$champ],
552                                                'valeur_uniquement' => 'oui',
553                                                'sans_reponse' => $sans_reponse
554                                        ),
555                                        $saisies_par_nom[$champ]['options']
556                                )
557                        ));
558                }
559        }
560        return array($valeurs, $valeurs_libellees);
561}
562
563/**
564 * Retourne la valeur "scrambelisée" de la variable PHP d'identification.
565 * pour les deux variables proposés par formidable, recherche directement dans $_SERVER
566 * sinon utilise un eval() si une autre variable a été défini en global.
567 * Mais peu probable que le cas se présente, car pas d'interface dans le .yaml pour proposer d'autres variables que celle définies par formidable
568 * @param string $nom_variable le nom de la variable
569 * @param string $id_formulaire le formulaire concerné
570 * @return string
571 */
572function formidable_variable_php_identification($nom_variable, $id_formulaire) {
573        //Pour compat ascendante
574        if (isset($GLOBALS['formulaires']['variables_anonymisation'])) {
575                $nom_variable = $GLOBALS['formulaires']['variables_anonymisation'][$nom_variable];
576                $valeur_variable = eval ("return $nom_variable;");
577        }
578
579        if (in_array($nom_variable, array("remote_user", "php_auth_user"))) {
580                $nom_variable = strtoupper($nom_variable);
581                $valeur_variable = isset($_SERVER[$nom_variable]) ? $_SERVER[$nom_variable] : 0;
582        }  else {
583                $valeur_variable = 0;
584        }
585
586        if ($valeur_variable) {
587                $valeur_variable = formidable_scramble($valeur_variable, $id_formulaire);
588        }
589        return $valeur_variable;
590}
Note: See TracBrowser for help on using the repository browser.