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

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

l'espace privé affiche pour un formulaire donnée le formulaire, sans passer d'identifiant explicite de réponse précédente. Du coup l'option d'identification par id de réponse plantait (erreur sql). On corrige cela (Florence Henry, contrib)

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