cdf18e45692430e3bee7bd7d330a1f8514035225
[lhc/web/www.git] / www / plugins / formidable / inc / formidable_fichiers.php
1 <?php
2
3 // Sécurité
4 if (!defined('_ECRIRE_INC_VERSION')) {
5 return;
6 }
7 include_spip('inc/flock');
8 include_spip('inc/documents');
9 if (!defined('_FORMIDABLE_TAILLE_MAX_FICHIERS_EMAIL')) {// la taille maximum (en Mio) des fichiers qu'on autorise directement en PJ dans les emails.
10 define('_FORMIDABLE_TAILLE_MAX_FICHIERS_EMAIL', 10);
11 }
12
13 if (!defined('_FORMIDABLE_EXPIRATION_FICHIERS_EMAIL')) {
14 // Combien de temps un lien par email dans fichier est valable (en seconde)
15 define('_FORMIDABLE_EXPIRATION_FICHIERS_EMAIL', 24*3600);
16 }
17 if (!defined('_FORMIDABLE_EFFACEMENT_FICHIERS_EMAIL')) {
18 // Au bout de combien de temps efface-t-on les fichiers enregistrés lorsque le traitement est uniquement email?
19 define('_FORMIDABLE_EFFACEMENT_FICHIERS_EMAIL', _FORMIDABLE_EXPIRATION_FICHIERS_EMAIL);
20 }
21 if (!defined('_FORMIDABLE_LIENS_FICHIERS_ACCUSE_RECEPTION')) {
22 // mettre à false si on ne veut pas de lien vers les fichiers dans l'accusé de réception
23 define('_FORMIDABLE_LIENS_FICHIERS_ACCUSE_RECEPTION', true);
24 }
25 /**
26 * Créer, si le formulaire contient des saisies de type fichiers, un dossier pour stocker les fichiers.
27 * Vérifier que ce dossier soit accessible en écriture.
28 * Vérifier qu'on ne puisse pas y accéder de l'exterieur.
29 *
30 * @param int $id_formulaire
31 * @param bool $forcer, pour forcer la création du dossier même si pas de saisie fichiers
32 * @return $erreur
33 **/
34 function formidable_creer_dossier_formulaire($id_formulaire, $forcer = false) {
35 if (!$forcer) {
36 include_spip('formulaires/formidable');
37 // Récuperer la liste des saisies de type fichier
38 $saisies_fichiers = formulaires_formidable_fichiers($id_formulaire);
39
40 if (!is_array($saisies_fichiers) or $saisies_fichiers == array ()) {
41 //pas de saisie fichiers?
42 return '';
43 }
44 }
45 $nom_dossier = "formulaire_$id_formulaire";
46
47 // On crée le dossier
48 sous_repertoire(_DIR_FICHIERS, '', true, true);
49 sous_repertoire(_DIR_FICHIERS_FORMIDABLE, '', true, true);
50 $dossier = sous_repertoire(_DIR_FICHIERS_FORMIDABLE, $nom_dossier, false, true);
51 if (strpos($dossier, "$nom_dossier/") === false) {
52 spip_log("Impossible d'écrire $nom_dossier", 'formidable'._LOG_ERREUR);
53 return _T(
54 'formidable:creer_dossier_formulaire_erreur_impossible_creer',
55 array('dossier'=>_DIR_FICHIERS_FORMIDABLE . $nom_dossier)
56 );
57 }
58
59 // Créer un htaccess ici
60 include_spip('inc/acces');
61 verifier_htaccess($dossier);
62
63 // on crée un fichier de test, pour s'assurer
64 // 1. Qu'on puisse écrire dans le rep
65 // 2. Qu'on ne puisse pas accéder à ce fichier depuis l'exterieur.
66 $fichier = $dossier.'test.txt';
67 $ecriture_ok = ecrire_fichier(
68 $fichier,
69 "Ce fichier n'est normalement pas lisible de l'extérieur. Si tel est le cas, il y a un souci de confidentialité.",
70 false
71 );
72 if ($ecriture_ok == false) {
73 spip_log("Impossible d'écrire dans $nom_dossier", 'formidable'._LOG_ERREUR);
74 return _T(
75 'formidable:creer_dossier_formulaire_erreur_impossible_ecrire',
76 array('dossier'=>_DIR_FICHIERS_FORMIDABLE . $nom_dossier)
77 );
78 }
79
80 include_spip('inc/distant');
81 $url = url_absolue($fichier);
82 if ($data = recuperer_page($url) && $data != null) {
83 // si on peut récuperer la page avec un statut http 200,
84 // c'est qu'il y a un problème. recuperer_page() est obsolète en 3.1, mais recuperer_url() n'existe pas en 3.0
85 spip_log("$nom_dossier accessible en lecture depuis le web", 'formidable'._LOG_CRITIQUE);
86 return _T(
87 'formidable:creer_dossier_formulaire_erreur_possible_lire_exterieur',
88 array('dossier'=>_DIR_FICHIERS_FORMIDABLE . $nom_dossier)
89 );
90 }
91 // Et si tout va bien
92 spip_log("Création du dossier $nom_dossier", 'formidable');
93 return '';
94 }
95
96 /**
97 * Déplace un fichier uploadé de son adresse temporaire vers son adresse définitive.
98 * Crée si besoin les dossiers de stockage.
99 *
100 * @param string $fichier l'adresse temporaire du fichier
101 * @param string $nom le nom du fichier
102 * @param string $mime le mime du fichier
103 * @param string $extension l'extension du fichier
104 * @param string $champ le champ concerné
105 * @return string $nom_definitif
106 * le nom définitif du fichier tel que stocké dans son dossier,
107 * vide s'il y a eu un souci lors du déplacement (dans ce cas un courriel sera envoyé au webmestre)
108 *
109 **/
110 function formidable_deplacer_fichier_emplacement_definitif($fichier, $nom, $mime, $extension, $champ, $options) {
111 if (isset($options['id_formulaire'])) {
112 $id_formulaire = $options['id_formulaire'];
113 $dossier_formulaire = "formulaire_$id_formulaire";
114 } else {
115 // si c'est pas set, c'est qu'il y a une erreur
116 return '';
117 }
118
119 if (isset($options['id_formulaires_reponse'])) {
120 $dossier_reponse = 'reponse_'.$options['id_formulaires_reponse'];
121 } elseif (isset($options['timestamp'])) {
122 $dossier_reponse = 'reponse_'.$options['timestamp'];
123 } else { // si ni timestamp, ni id_formulaires_reponse => erreur
124 return '';
125 }
126 // déterminer le basename
127 $basename = pathinfo($nom, PATHINFO_BASENAME);
128
129 // Appliquer les alias de type_mime
130 include_spip('base/typedoc');
131 while (isset($GLOBALS['mime_alias'][$mime])) {
132 $mime = $GLOBALS['mime_alias'][$mime];
133 }
134
135 // sécurité : si la combinaison extension/mime_type est inconnu de SPIP (spip_documents_type), on zip.
136 // On n'utilise volontairement pas verifier/fichiers.php, dès fois que celui-ci évolue dans le future
137 $res = sql_select(
138 'mime_type',
139 'spip_types_documents',
140 'mime_type='.sql_quote($mime).' and extension='.sql_quote($extension)
141 );
142 if (sql_count($res) == 0) {
143 $zipper = true;
144 $nom_dans_zip = $nom;
145 // pas de fichier nom de zip commencant par point
146 while (strpos($basename, '.') === 0) {
147 $basename = substr($basename, 1);
148 }
149 $nom = "$basename.zip";
150 } else {
151 $zipper = false;
152 }
153 if (!isset($options['timestamp'])) { // si on enregistre la réponse en base
154
155 // d'abord, créer si besoin le dossier pour le formulaire, si on a une erreur, on ne déplace pas le fichier
156 if (formidable_creer_dossier_formulaire($id_formulaire, true) != '') {
157 return '';
158 }
159
160 // puis on créer le dossier pour la réponse
161 $dossier_reponse = sous_repertoire(
162 _DIR_FICHIERS_FORMIDABLE.$dossier_formulaire.'/',
163 $dossier_reponse,
164 false,
165 true
166 );
167
168 // puis le dossier pour le champ
169 $dossier_champ = sous_repertoire($dossier_reponse, $champ, false, true);
170 $appendice_nom = 0;
171 } else { // si on enregistre sous forme de timestamp
172 sous_repertoire(_DIR_FICHIERS, '', true, true);
173 sous_repertoire(_DIR_FICHIERS_FORMIDABLE, '', true, true);
174 $dossier = sous_repertoire(_DIR_FICHIERS_FORMIDABLE, 'timestamp', false, true);
175 $dossier = sous_repertoire($dossier, $options['timestamp'], false, true);
176 $dossier_champ = sous_repertoire($dossier, $champ, false, true);
177
178 // Générer un fichier htaccess ici
179 include_spip('inc/acces');
180 verifier_htaccess($dossier);
181
182 // on crée un fichier de test, pour s'assurer
183 // 1. Qu'on puisse écrire dans le rep
184 // 2. Qu'on ne puisse pas accéder à ce fichier depuis l'exterieur.
185 $fichier_test = $dossier.'test.txt';
186 $ecriture_ok = ecrire_fichier(
187 $fichier_test,
188 "Ce fichier n'est normalement pas lisible de l'extérieur. Si tel est le cas, il y a un souci de confidentialité.",
189 false
190 );
191 if ($ecriture_ok == false) {
192 spip_log("Impossible d'écrire dans $dossier", 'formidable'._LOG_ERREUR);
193 return '';
194 }
195 include_spip('inc/distant');
196 $url = url_absolue($fichier_test);
197 if ($data = recuperer_page($url) && $data != null) {
198 // si on peut récuperer la page avec un statut http 200,
199 // c'est qu'il y a un problème.
200 // recuperer_page() est obsolète en 3.1, mais recuperer_url() n'existe pas en 3.0
201 spip_log("$dossier accessible en lecture depuis le web", 'formidable'._LOG_CRITIQUE);
202 return '';
203 }
204 }
205 // S'assurer qu'il n'y a pas un fichier du même nom à destination
206 $chemin_final = $dossier_champ.$nom;
207 $n = 1;
208 //la constante PATHINFO_FILENAME n'est qu'à partir de PHP 5.2, or SPIP 3 peut fonctionne en PHP 5.1
209 $basename_sans_extension = substr_replace($basename, '', -strlen($extension)-1);
210 while (@file_exists($chemin_final)) {
211 $nom = $basename_sans_extension."_$n.".$extension;
212 $chemin_final = $dossier_champ.$nom;
213 $n++;
214 }
215 if (!$zipper) { // si on ne zippe pas, c'est simple
216 if ($fichier = deplacer_fichier_upload($fichier, $chemin_final, true)) {
217 spip_log("Enregistrement du fichier $chemin_final", 'formidable');
218 return $nom;
219 } else {
220 spip_log("Pb lors de l'enregistrement du fichier $chemin_final", 'formidable'._LOG_ERREUR);
221 return '';
222 }
223 } else { // si on doit zipper, c'est plus complexe
224 include_spip('inc/pclzip');
225 $zip = new PclZip($chemin_final);
226 // mettre à jour le fichier dans le dossier cvtupload
227 if (!$tmp_dir = tempnam($dossier_champ, 'tmp_upload')) {
228 return '';
229 }
230 spip_unlink($tmp_dir);
231 @mkdir($tmp_dir);
232 $old_fichier = $fichier;
233 if (!$fichier = deplacer_fichier_upload($fichier, $tmp_dir.'/'.$nom_dans_zip, false)) {
234 spip_log("Pb lors de l'enregistrement du fichier $tmp_dir/$nom_dans_zip", 'formidable'._LOG_ERREUR);
235 return '';
236 }
237 $zip_final = $zip -> create(
238 $fichier,
239 PCLZIP_OPT_REMOVE_PATH,
240 $tmp_dir,
241 PCLZIP_OPT_ADD_PATH,
242 ''
243 );
244 if (!$zip_final) {
245 spip_log("Pb lors de l'enregistrement du fichier $fichier", 'formidable'._LOG_ERREUR);
246 return '';
247 } else {
248 spip_unlink($old_fichier);
249 supprimer_repertoire($tmp_dir);
250 spip_log("Enregistrement du fichier $fichier, automatiquement zippé", 'formidable');
251 return $nom;
252 }
253 }
254
255 return $nom;
256 }
257
258 /**
259 * Fournit à l'utilisateur·trice un fichier qui se trouve normalement dans un endroit inaccessible,
260 * par exemple dans config.
261 * La fonction ne vérifie ni l'existence effective du fichier,
262 * ni le droit effectif de l'utilisateur.
263 * Ceci doit être fait dans l'action qui appelle cette fonction
264 * @param string $chemin le chemin du fichier
265 * @param string $f le nom du fichier qui sera envoyé à l'utilisateur·trice.
266 *
267 **/
268 function formidable_retourner_fichier($chemin, $f) {
269 header('Content-Type: '.mime_content_type($chemin));
270 header("Content-Disposition: attachment; filename=\"$f\";");
271 header('Content-Transfer-Encoding: binary');
272 // fix for IE catching or PHP bug issue (inspiré de plugins-dist/dump/action/telecharger_dump.php
273 header('Pragma: public');
274 header('Expires: 0'); // set expiration time
275 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
276 if ($cl = filesize($chemin)) {
277 header('Content-Length: '.$cl);
278 }
279 readfile($chemin);
280 exit;
281 }
282 /**
283 * Déplacer un fichier temporaire à son emplacement définif.
284 * Produire un tableau de description des fichiers déplacés.
285 * Le tout à partir de la description d'une saisies 'fichiers'
286 * @param array $saisie la description de la saisie fichiers
287 * @param array $options
288 * des options, dépendantes du type de traitement,
289 * qui permettent d'indiquer où l'on déplace le fichier
290 * @return array un tableau de "vue" de la saisie
291 **/
292 function formidable_deplacer_fichiers_produire_vue_saisie($saisie, $options) {
293 $nb_fichiers_max = $saisie['options']['nb_fichiers'];
294 // on va parcourir $_FILES en nous limitant aux nombres de fichiers définies par la saisie,
295 // pour éviter les éventuelles ajout supplémentaire de fichiers par modif du html
296 $champ = $saisie['options']['nom'];
297 if (!isset($_FILES[$champ])) {//précaution
298 return null;
299 }
300 $description_fichiers = array();
301 $mon_file = $_FILES[$champ];
302 $i = 0;
303 while ($i < $nb_fichiers_max) {
304 if ($mon_file['error'][$i] == 0) {
305 // la saisie fichiers est forcément structurée sous la forme d'un tableau,
306 // on peut donc vérifier qu'il n'y a pas d'erreur facilement
307 $description = array(); // tableau pour stocker la description de ce fichier
308
309 // les infos qu'on peut récuperer directement de $files
310 $description['taille'] = $mon_file['size'][$i];
311 $description['mime'] = $mon_file['type'][$i];
312
313 // l'adresse du nouveau fichier, sans le chemin
314 if ($nouveau_nom = formidable_deplacer_fichier_emplacement_definitif(
315 $mon_file['tmp_name'][$i],
316 $mon_file['name'][$i],
317 $mon_file['type'][$i],
318 pathinfo($mon_file['name'][$i], PATHINFO_EXTENSION),
319 $champ,
320 $options
321 )) {
322 $description['nom'] = $nouveau_nom;
323 $description['extension'] = pathinfo($nouveau_nom, PATHINFO_EXTENSION);
324 } else {
325 $description['erreur'] = _T(
326 'formidable:erreur_deplacement_fichier',
327 array('nom'=>$mon_file['name'][$i])
328 );
329 $description['nom'] = $mon_file['name'][$i];
330 $description['tmp_name'] = $mon_file['tmp_name'][$i];
331 }
332 //on ajoute la description au tableau global
333 $description_fichiers[] = $description;
334 }
335 $i++;
336 }
337 return $description_fichiers;
338 }
339 /**
340 * Efface les fichiers d'un formulaire
341 * @param $str $id_formulaire
342 * @return int 1 ou 0 selon que l'on a effacé ou non un répertoire
343 **/
344 function formidable_effacer_fichiers_formulaire($id_formulaire) {
345 $chemin = _DIR_FICHIERS_FORMIDABLE."formulaire_$id_formulaire";
346 if (file_exists($chemin)) {// par sécurité
347 if (supprimer_repertoire($chemin)) {
348 spip_log("Effacement du dossier $chemin", 'formidable');
349 return 1;
350 } else {
351 spip_log("Pb lors de l'effacement du dossier $chemin", 'formidable'._LOG_ERREUR);
352 return 0;
353 }
354 }
355 return 0;
356 }
357
358 /**
359 * efface les fichiers d'une réponse formidable
360 * @param $str $id_formulaire
361 * @param $str $id_formulaires_reponse
362 * @return int 1 ou 0 selon que l'on a effacé ou non un répertoire
363 **/
364 function formidable_effacer_fichiers_reponse($id_formulaire, $id_formulaires_reponse) {
365 $chemin = _DIR_FICHIERS_FORMIDABLE."formulaire_$id_formulaire/reponse_$id_formulaires_reponse";
366 if (file_exists($chemin)) {// par sécurité
367 if (supprimer_repertoire($chemin)) {
368 spip_log("Effacement du dossier $chemin", 'formidable');
369 return 1;
370 } else {
371 spip_log("Pb lors de l'effacement du dossier $chemin", 'formidable'._LOG_ERREUR);
372 return 0;
373 }
374 }
375 return 0;
376 }
377
378 /** Efface les fichiers d'un champ pour les réponses d'un formulaire
379 * @param str $id_formulaire
380 * @param array|str $reponses
381 * @param str $champ
382 **/
383 function formidable_effacer_fichiers_champ($id_formulaire, $reponses, $champ) {
384 if ($champ != '') { // on devrait pas arriver ici avec un $champ vide, mais prenons nos précaution
385
386 if (!is_array($reponses)) {
387 $reponses = array($reponses);
388 }
389
390 $rep_vide = array('.', '..', '.ok'); // si scandire retourne cela où inférieur, alors le dossier est vide
391 foreach ($reponses as $rep) {
392 $chemin_reponse = _DIR_FICHIERS_FORMIDABLE."formulaire_$id_formulaire/reponse_$rep";
393 $chemin_champ = $chemin_reponse.'/'.$champ;
394
395 if (file_exists($chemin_champ)) {
396 if (supprimer_repertoire($chemin_champ)) {
397 spip_log("Effacement du dossier $chemin_champ", 'formidable');
398 } else {
399 spip_log("Pb lors de l'effacement du dossier $chemin_champ", 'formidable'._LOG_ERREUR);
400 }
401 if (count(array_diff(scandir($chemin_reponse), $rep_vide)) == 0) {
402 // si jamais il ne reste plus aucun fichiers pour cette réponse,
403 // on peut effacer le repertoire de celle-ci
404 if (supprimer_repertoire($chemin_reponse)) {
405 spip_log("Effacement du dossier $chemin_reponse", 'formidable');
406 } else {
407 spip_log("Pb lors de l'effacement du dossier $chemin_reponse", 'formidable'._LOG_ERREUR);
408 }
409 }
410 }
411 }
412 }
413 }
414
415 /** Efface les fichiers des réponses par email
416 * lorsque la constante _FORMIDABLE_EFFACEMENT_FICHIERS_EMAIL est différent de 0 et que le temps est écoulé
417 * @return int nombre de dossiers effacés
418 **/
419 function formidable_effacer_fichiers_email() {
420 if (_FORMIDABLE_EFFACEMENT_FICHIERS_EMAIL == 0) {
421 return 0;
422 }
423 $dossiers_effaces = 0;
424 $chemin = _DIR_FICHIERS_FORMIDABLE.'timestamp';
425 $timestamp = time();
426 if (is_dir($chemin)) {
427 $dossiers = scandir($chemin);
428 if (is_array($dossiers)) {
429 foreach ($dossiers as $dossier) {
430 if (strval(intval($dossier)) != $dossier) { // on ne traite que les dossiers qui ont comme nom un entier
431 continue;
432 }
433 if ($timestamp - intval($dossier) >= _FORMIDABLE_EFFACEMENT_FICHIERS_EMAIL) {
434 $chemin_complet = "$chemin/$dossier";
435 if (supprimer_repertoire($chemin_complet)) {
436 spip_log("Effacement du dossier $chemin_complet", 'formidable');
437 $dossiers_effaces++;
438 } else {
439 spip_log("Pb lors de l'effacement du dossier $chemin_complet", 'formidable'._LOG_ERREUR);
440 }
441 }
442 }
443 }
444 }
445 return $dossiers_effaces;
446 }
447 /**
448 * Génerer un zip des réponses d'un formulaire
449 * @param int $id_formulaire (identifiant numérique)
450 * @param str $chemin_du_zip chemin complet du zip
451 * @param str $fichier_csv un fichier csv à ajouter, contenant les réponses
452 * @return str|int chemin complet du zip ou 0 si erreur lors de la création
453 **/
454 function formidable_zipper_reponses_formulaire($id_formulaire, $chemin_du_zip, $fichier_csv, $saisies_fichiers) {
455 include_spip('inc/pclzip');
456 $zip = new PclZip("$chemin_du_zip");
457 $chemin_fichiers = _DIR_FICHIERS_FORMIDABLE . 'formulaire_' . $id_formulaire;
458 if (!$zip->create($saisies_fichiers, PCLZIP_OPT_REMOVE_PATH, $chemin_fichiers)) {
459 spip_log(
460 "Impossible de créer le zip pour l'export des réponses du formulaire $id_formulaire",
461 'formidable'._LOG_ERREUR
462 );
463 return 0;
464 } else {
465 $zip->add($fichier_csv, PCLZIP_OPT_REMOVE_ALL_PATH);
466 return $chemin_du_zip;
467 }
468 }
469 /**
470 * Générer une url d'action pour la récupération d'un fichier lié à une réponse
471 * @param int|str $id_formulaire
472 * @param int|str $id_formulaires_reponse
473 * @param str $saisie
474 * @param str $fichier
475 **/
476 function formidable_generer_url_action_recuperer_fichier($id_formulaire, $id_formulaires_reponse, $saisie, $fichier) {
477 $param = array(
478 'formulaire' => $id_formulaire,
479 'reponse' => $id_formulaires_reponse,
480 'saisie' => $saisie,
481 'fichier' => $fichier
482 );
483
484 // Pour les utilisateurs non authentifiés, on se base sur le cookier
485 $nom_cookie = formidable_generer_nom_cookie($id_formulaire);
486 if (isset($_COOKIE[$nom_cookie])) {
487 include_spip('inc/securiser_action');
488 $param['cookie'] = sha1($_COOKIE[$nom_cookie].secret_du_site());
489 }
490
491 $param = serialize($param);
492 $securiser_action = charger_fonction('securiser_action', 'inc');
493 return $securiser_action('formidable_recuperer_fichier', $param, '', false);
494 }
495
496 /** Générer une url d'action pour récuperer un fichier à partir d'un lien email
497 * @param string $saisie
498 * @param string $fichier
499 * @param array $options décrivant si on récupère par id de réponse ou par timestamp
500 * @return string $url
501 *
502 **/
503 function formidable_generer_url_action_recuperer_fichier_email($saisie, $fichier, $options) {
504 if (isset($options['id_formulaires_reponse'])) {//si reponses enregistrées
505 $arg = serialize(array(
506 'formulaire' => strval($options['id_formulaire']),
507 'reponse' => strval($options['id_formulaires_reponse']),
508 'fichier' => $fichier,
509 'saisie' => $saisie
510 ));
511 } elseif (isset($options['timestamp'])) {//si par timestamp
512 $arg = serialize(array(
513 'timestamp' => strval($options['timestamp']),
514 'fichier' => $fichier,
515 'saisie' => $saisie
516 ));
517 }
518 $pass = secret_du_site();
519 $action = 'formidable_recuperer_fichier_par_email';
520 $hash = _action_auteur("$action-$arg", '', $pass, 'alea_ephemere');
521 $url = generer_url_action($action, "arg=$arg&hash=$hash", true, true);
522 return $url;
523 }
524
525 /** Générer le chemin d'un fichier d'après les paramètres passés en argument
526 * @param array $param, paramètres décrivant le fichiers: nom, timestamp de la réponse ou numéro d'enregistrement de la réponse, id du formulaire, champ formidable
527 * @return string $chemin;
528 **/
529 function formidable_generer_chemin_fichier($param){
530 $chemin_fichier = '';
531 if (isset($param['reponse'])) {
532 $chemin_fichier = _DIR_FICHIERS_FORMIDABLE
533 .'formulaire_'.$param['formulaire']
534 .'/reponse_'.$param['reponse']
535 .'/'.$param['saisie']
536 .'/'.$param['fichier'];
537 } elseif (isset($param['timestamp'])) {
538 $chemin_fichier = _DIR_FICHIERS_FORMIDABLE
539 . 'timestamp/'
540 . $param['timestamp'].'/'
541 . $param['saisie'].'/'
542 . $param['fichier'];
543 } else {
544 include_spip('inc/minipres');
545 echo minipres(_T('formidable:erreur_fichier_introuvable'));
546 }
547 return $chemin_fichier;
548 }
549