[PLUGINS] ~maj globale
[lhc/web/www.git] / www / plugins / formidable / inc / formidable.php
1 <?php
2
3 // Sécurité
4 if (!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 */
13 function 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 */
45 function 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 */
64 function 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 */
91 function formidable_generer_nom_cookie($id_formulaire) {
92 return $GLOBALS['cookie_prefix'].'cookie_formidable_'.$id_formulaire;
93 }
94
95 /*
96 * Vérifie si le visiteur a déjà répondu à un formulaire
97 *
98 * @param int $id_formulaire L'identifiant du formulaire
99 * @param string $choix_identification Comment verifier une reponse. Priorite sur 'cookie' ou sur 'id_auteur'
100 * @param string $anonymisation : vaut '' si le formulaire n'est pas anonymisé, sinon c'est la variable d'anonymisation
101 * @return unknown_type Retourne un tableau contenant les id des réponses si elles existent, sinon false
102 */
103 function formidable_verifier_reponse_formulaire($id_formulaire, $choix_identification = 'cookie', $anonymisation = '') {
104 global $auteur_session;
105 $id_auteur = $auteur_session ? intval($auteur_session['id_auteur']) : 0;
106 $nom_cookie = formidable_generer_nom_cookie($id_formulaire);
107 $cookie = isset($_COOKIE[$nom_cookie]) ? $_COOKIE[$nom_cookie] : false;
108
109 $anonymiser = ($anonymisation == '') ? false : true;
110 if ($anonymiser) {
111 $anonymiser_variable = $anonymisation;
112 }
113
114 // traitement de l'anonymisation
115 if ($anonymiser) {
116 // mod de l'id_auteur
117 $variables_anonymisation =
118 $GLOBALS['formulaires']['variables_anonymisation'][$anonymiser_variable];
119 $id = eval("return $variables_anonymisation;");
120 $id_auteur = formidable_scramble($id, $id_formulaire);
121 }
122 // ni cookie ni id, on ne peut rien faire
123 if (!$cookie and !$id_auteur) {
124 return false;
125 }
126
127 // priorite sur le cookie
128 if ($choix_identification == 'cookie' or !$choix_identification) {
129 if ($cookie) {
130 $where = '(cookie='.sql_quote($cookie).($id_auteur ? ' OR id_auteur='.$id_auteur.')' : ')');
131 } else {
132 $where = 'id_auteur='.$id_auteur;
133 }
134 } else {
135 // sinon sur l'id_auteur
136 if ($id_auteur) {
137 $where = 'id_auteur='.$id_auteur;
138 } else {
139 $where = '(cookie='.sql_quote($cookie).($id_auteur ? ' OR id_auteur='.$id_auteur.')' : ')');
140 }
141 }
142
143 $reponses = sql_allfetsel(
144 'id_formulaires_reponse',
145 'spip_formulaires_reponses',
146 array(
147 array('=', 'id_formulaire', intval($id_formulaire)),
148 array('=', 'statut', sql_quote('publie')),
149 $where
150 ),
151 '',
152 'date'
153 );
154
155 if (is_array($reponses)) {
156 return array_map('reset', $reponses);
157 } else {
158 return false;
159 }
160 }
161
162 /*
163 * Génère la vue d'analyse de toutes les réponses à une saisie
164 *
165 * @param array $saisie Un tableau décrivant une saisie
166 * @param array $env L'environnement, contenant normalement la réponse à la saisie
167 * @return string Retour le HTML des vues
168 */
169 function formidable_analyser_saisie($saisie, $valeurs = array(), $reponses_total = 0, $format_brut = false) {
170 // Si le paramètre n'est pas bon ou que c'est un conteneur, on génère du vide
171 if (!is_array($saisie) or (isset($saisie['saisies']) and $saisie['saisies'])) {
172 return '';
173 }
174
175 $contexte = array('reponses_total'=>$reponses_total);
176
177 // On sélectionne le type de saisie
178 $contexte['type_saisie'] = $saisie['saisie'];
179
180 // Peut-être des transformations à faire sur les options textuelles
181 $options = $saisie['options'];
182 foreach ($options as $option => $valeur) {
183 $options[$option] = _T_ou_typo($valeur, 'multi');
184 }
185
186 // On ajoute les options propres à la saisie
187 $contexte = array_merge($contexte, $options);
188
189 // On récupère toutes les valeurs du champ
190 if (isset($valeurs[$contexte['nom']])
191 and $valeurs[$contexte['nom']]
192 and is_array($valeurs[$contexte['nom']])) {
193 $contexte['valeurs'] = $valeurs[$contexte['nom']];
194 } else {
195 $contexte['valeurs'] = array();
196 }
197
198 // On génère la saisie
199 if ($format_brut) {
200 return analyser_saisie($contexte);
201 } else {
202 return recuperer_fond(
203 'saisies-analyses/_base',
204 $contexte
205 );
206 }
207 }
208
209 /*
210 * Renvoie une ligne de réponse sous la forme d'un tableau
211 *
212 * @param array $saisie Un tableau décrivant une saisie
213 * @return array Tableau contenant une ligne
214 */
215 function analyser_saisie($saisie) {
216 if (!isset($saisie['type_saisie']) or $saisie['type_saisie'] == '') {
217 return '';
218 }
219
220 $ligne = array();
221
222 switch ($saisie['type_saisie']) {
223 case 'selecteur_rubrique':
224 case 'selecteur_rubrique_article':
225 case 'selecteur_article':
226 $ligne['plein'] = count(array_filter($saisie['valeurs']));
227 $ligne['vide'] = count(array_diff_key($saisie['valeurs'], array_filter($saisie['valeurs'])));
228 break;
229 case 'radio':
230 case 'selection':
231 case 'selection_multiple':
232 case 'choix_couleur':
233 case 'checkbox':
234 $stats = array();
235 foreach ($saisie['valeurs'] as $valeur) {
236 if (is_array($valeur)) {
237 foreach ($valeur as $choix) {
238 if (isset($stats["choix-$choix"])) {
239 $stats["choix-$choix"]++;
240 } else {
241 $stats["choix-$choix"] = 1;
242 }
243 }
244 } else {
245 if (isset($stats["choix-$valeur"])) {
246 $stats["choix-$valeur"]++;
247 } else {
248 $stats["choix-$valeur"] = 1;
249 }
250 }
251 }
252 $datas = is_string($saisie['datas'])
253 ? saisies_chaine2tableau(saisies_aplatir_chaine($saisie['datas']))
254 : $saisie['datas'];
255 foreach ($datas as $key => $val) {
256 $nb = (isset($stats["choix-$key"]))
257 ? $stats["choix-$key"]
258 : 0;
259 $ligne[$val] = $nb;
260 }
261 break;
262 case 'destinataires':
263 $stats = array();
264 foreach ($saisie['valeurs'] as $valeur) {
265 foreach ($valeur as $choix) {
266 if (isset($stats["choix-$choix"])) {
267 $stats["choix-$choix"]++;
268 } else {
269 $stats["choix-$choix"] = 1;
270 }
271 }
272 }
273 foreach ($stats as $key => $val) {
274 $key = str_replace('choix-', '', $key);
275 if ($key == '') {
276 $key = '<valeur vide>';
277 }
278 $auteur = sql_getfetsel('nom', 'spip_auteurs', "id_auteur=$key");
279 $ligne[$auteur] = $val;
280 }
281 break;
282 }
283
284 $vide = 0;
285 foreach ($saisie['valeurs'] as $valeur) {
286 if ($valeur == '') {
287 $vide++;
288 }
289 switch ($saisie['type_saisie']) {
290 case 'case':
291 case 'oui_non':
292 if (isset($ligne['oui']) == false) {
293 $ligne['oui'] = 0;
294 }
295 if (isset($ligne['non']) == false) {
296 $ligne['non'] = 0;
297 }
298 if ($valeur) {
299 $ligne['oui']++;
300 } else {
301 $ligne['non']++;
302 }
303 break;
304 case 'input':
305 case 'hidden':
306 case 'explication':
307 break;
308 }
309 }
310 $ligne['sans_reponse'] = $vide;
311 $ligne['header'] = $saisie['label'] != ''
312 ? $saisie['label']
313 : $saisie['type_saisie'];
314
315 return $ligne;
316 }
317
318
319 /**
320 * Tente de déserialiser un texte
321 *
322 * Si le paramètre est un tableau, retourne le tableau,
323 * Si c'est une chaîne, tente de la désérialiser, sinon
324 * retourne la chaîne.
325 *
326 * @filtre
327 *
328 * @param string|array $texte
329 * Le texte (possiblement sérializé) ou un tableau
330 * @return array|string
331 * Tableau, texte désérializé ou texte
332 **/
333 function filtre_tenter_unserialize_dist($texte) {
334 if (is_array($texte)) {
335 return $texte;
336 }
337 if ($tmp = @unserialize($texte)) {
338 return $tmp;
339 }
340 return $texte;
341 }
342
343
344 /**
345 * Retourne un texte du nombre de réponses
346 *
347 * @param int $nb
348 * Nombre de réponses
349 * @return string
350 * Texte indiquant le nombre de réponses
351 **/
352 function titre_nb_reponses($nb) {
353 if (!$nb) {
354 return _T('formidable:reponse_aucune');
355 }
356 if ($nb == 1) {
357 return _T('formidable:reponse_une');
358 }
359 return _T('formidable:reponses_nb', array('nb' => $nb));
360 }
361
362 /**
363 * Transforme le hash MD5 en une valeur numérique unique
364 *
365 * trouvé ici : http://stackoverflow.com/questions/1422725/represent-md5-hash-as-an-integer
366 * @param string $hex_str La valeur alphanumérique à transformer
367 * @return string Valeur numérique
368 */
369 function md5_hex_to_dec($hex_str) {
370 $arr = str_split($hex_str, 4);
371 $dec = array();
372 foreach ($arr as $grp) {
373 $dec[] = str_pad(hexdec($grp), 5, '0', STR_PAD_LEFT);
374 }
375
376 /* on s'assure que $result ne commence pas par un zero */
377 $result = implode('', $dec);
378 for ($cpt = 0; $cpt < strlen($result); $cpt++) {
379 if ($result[$cpt] != '0') {
380 break;
381 }
382 }
383 $result = substr($result, $cpt);
384 return $result;
385 }
386
387 /**
388 * Transforme un login en une valeur numérique de 19 caractères
389 *
390 * NOTE: il devient impossible de retrouver la valeur d'origine car le HASH
391 * est coupé à 19cars et est donc incomplet. L'unicité n'est pas garantie mais
392 * les chances pour que deux logins tombent sur le même HASH sont de 1 sur
393 * 10 milliards de milliards
394 * A la fin, on recherche et supprime les éventuels zéros de début
395 * @param string $login Login à transformer
396 * @param string $id_form ID du formulaire concerné
397 * @param string $passwd Chaîne 'secrète' ajoutée au login et id_formulaire pour éviter
398 * les recoupements d'identité entre plusieurs formulaires
399 * @return string Un nombre de 19 chiffres
400 */
401 function formidable_scramble($login, $id_form, $passwd = '') {
402 if ($passwd == '') {
403 $passwd = $GLOBALS['formulaires']['passwd']['interne'];
404 }
405 $login_md5 = md5("$login$passwd$id_form");
406 $login_num = md5_hex_to_dec($login_md5);
407 $login_num = substr($login_num, 0, 19);
408
409 return $login_num;
410 }