source: spip-zone/_plugins_/cvt-upload/trunk/inc/cvtupload.php @ 111887

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

trailing spaces

File size: 11.9 KB
Line 
1<?php
2
3// Sécurité
4if (!defined('_ECRIRE_INC_VERSION')) {
5        return;
6}
7
8
9/**
10 * Age maximum des fichiers dans le dossier temporaire
11 **/
12if (!defined('_CVTUPLOAD_AGE_MAX')) {
13        define('_CVTUPLOAD_AGE_MAX', 6*3600);
14}
15
16/**
17 * Nombre maximum de fichiers dans le dossier temporaire
18 **/
19if (!defined('_CVTUPLOAD_MAX_FILES')) {
20        define('_CVTUPLOAD_MAX_FILES', 200);
21}
22
23
24include_spip('base/abstract_sql');
25/**
26 * Chercher si des champs fichiers ont été déclarés dans le fichier formulaires/xxx.php
27 * Sert de condition preliminaire pour les pipelines formulaire_charger, formulaire_verifier et formulaire_fond du plugin
28 *
29 * @param string $form
30 *     le nom du formulaire
31 * @param array $args
32 *     - l'id de l'objet
33 *
34 * @return array
35 *     valeur(s) de l'attribut 'name' du ou des input de type file dans formulaires/xxx.html
36 */
37function cvtupload_chercher_fichiers($form, $args) {
38        $fichiers = array();
39
40        // S'il existe une fonction de fichiers dédiée à ce formulaire
41        if ($fonction_fichiers = charger_fonction('fichiers', 'formulaires/'.$form, true)) {
42                $fichiers = call_user_func_array($fonction_fichiers, $args);
43        }
44
45        // Dans tous les cas on applique le pipeline, si un plugin veut ajouter des choses
46        $fichiers = pipeline(
47                'formulaire_fichiers',
48                array('args'=>array('form'=>$form, 'args'=>$args), 'data'=>$fichiers)
49        );
50
51        return $fichiers;
52}
53
54/**
55 * Génére le HTML de chaque fichier déjà uploadé
56 *
57 * @param array $infos_fichiers
58 *              Tableau contenant les informations pour chaque champ de fichier
59 * @return array
60 *              Retourne un tableau avec pour chaque champ une clé contenant le HTML
61 **/
62function cvtupload_generer_html($infos_fichiers = null) {
63        static $html_fichiers = array();
64        // Si on a des infos de fichiers, on va re-générer du HTML
65        if ($infos_fichiers and is_array($infos_fichiers)) {
66                foreach ($infos_fichiers as $champ => $fichier) {
67                        // Si c'est un champ unique
68                        if (isset($fichier['name'])) {
69                                $html_fichiers[$champ] = recuperer_fond(
70                                        'formulaires/inc-cvtupload-fichier',
71                                        array_merge($fichier, array(
72                                                'crochets' => "[$champ]",
73                                                'champ'    => "$champ",
74                                        ))
75                                );
76                        } // Sinon c'est un champ multiple
77                        else {
78                                $html_fichiers[$champ] = array();
79                                foreach ($fichier as $cle => $infos) {
80                                        $html_fichiers[$champ][$cle] = recuperer_fond(
81                                                'formulaires/inc-cvtupload-fichier',
82                                                array_merge($infos, array(
83                                                        'crochets' => "[$champ][$cle]",
84                                                        'champ'    => $champ . "[$cle]",
85                                                ))
86                                        );
87                                }
88                        }
89                }
90        }
91
92        return $html_fichiers;
93}
94
95/**
96 * Déplace un fichier uploadé dans un endroit temporaire et retourne des informations dessus.
97 * @param array $fichier
98 *              Le morceau de $_FILES concernant le ou les fichiers
99 * @param string $repertoire
100 *              Chemin de destination des fichiers
101 * @param string $form
102 *              Formulaire d'où ça vient
103 * @param bool $deplacer
104 *              Mettre a False pour se contenter de copier
105 * @return array
106 *              Retourne un tableau d'informations sur le fichier ou un tableau de tableaux si plusieurs fichiers. Ce tableau est compatible avec l'action "ajouter_un_fichier" de SPIP.
107 **/
108function cvtupload_deplacer_fichier($fichier, $repertoire, $form, $deplacer = true) {
109        $vignette_par_defaut = charger_fonction('vignette', 'inc/');
110        $infos = array();
111        // On commence par nettoyer le dossier
112        cvtupload_nettoyer_repertoire($repertoire);
113
114        // Si on est sur un upload de type fichier unique, on reformate le tableau pour faire comme si on était en fichiers multiples
115        if (!is_array($fichier['name'])) {
116                $fichier_unique = true;
117                $fichier_nouveau = array();
118                foreach ($fichier as $champ => $valeur) {
119                        $fichier_nouveau[$champ] = array($valeur);
120                }
121                $fichier = $fichier_nouveau;
122        } else {
123                $fichier_unique = false;
124        }
125
126        foreach ($fichier['name'] as $cle => $nom) {
127                // On commence par transformer le nom du fichier pour éviter les conflits, on supprime notamment les accents
128                $nom = preg_replace(',\.\.+,', '.', $nom); // pas de .. dans le nom du doc
129                $nom = preg_replace("/[^.=\w-]+/", "_",
130                        translitteration(preg_replace("/<[^>]*>/", '', $nom)));
131                $nom = strtolower($nom);
132                if (// Si le fichier a bien un nom et qu'il n'y a pas d'erreur associé à ce fichier
133                        ($nom != null)
134                        and ($fichier['error'][$cle] == 0)
135                        // Et qu'on génère bien un nom de fichier aléatoire pour déplacer le fichier
136                        and $chemin_aleatoire = tempnam($repertoire, $form.'_')
137                ) {
138                        $extension = strtolower(pathinfo($fichier['name'][$cle], PATHINFO_EXTENSION));
139                        $chemin_aleatoire_brut = $chemin_aleatoire;
140                        if (in_array($extension, array('png','jpg','gif'))) {
141                                $chemin_aleatoire .= ".$extension";
142                        }
143                        // Déplacement du fichier vers le dossier de réception temporaire + récupération d'infos
144                        if (deplacer_fichier_upload($fichier['tmp_name'][$cle], $chemin_aleatoire_brut, $deplacer)) {
145                                $infos[$cle]['tmp_name'] = $chemin_aleatoire_brut;
146                                $infos[$cle]['name'] = $nom;
147                                $infos[$cle]['extension'] = $extension;
148                                // si image on fait une copie avec l'extension pour pouvoir avoir l'image réduite en vignette
149                                if (in_array($extension, array('png','jpg','gif'))) {
150                                        $infos[$cle]['vignette'] = $chemin_aleatoire;
151                                        link($chemin_aleatoire_brut,$chemin_aleatoire);
152                                } else {
153                                        $infos[$cle]['vignette'] = $vignette_par_defaut($infos[$cle]['extension'], false, true);
154                                }
155                                //On récupère le type MIME du fichier aussi
156                                $infos[$cle]['mime'] = cvt_upload_determiner_mime($fichier['type'][$cle], $infos[$cle]['extension']);
157                                $infos[$cle]['taille'] = $fichier['size'][$cle];
158                                // On stocke des infos sur le formulaire
159                                $infos[$cle]['form'] = $form;
160                                $infos[$cle]['infos_encodees'] = encoder_contexte_ajax($infos[$cle], $form);
161                        }
162                }
163        }
164
165        if ($fichier_unique == true) {
166                $infos = $infos[0];
167        }
168        return $infos;
169}
170
171/**
172 * Modifier $_FILES pour que le nom et le chemin du fichier temporaire
173 * correspondent à ceux qu'on a défini dans cvtupload_deplacer_fichier().
174 * Cela permet aux traitements ultérieurs
175 * de ne pas avoir à se préoccuper de l'emploi ou non de cvtupload.
176 *
177 * @param $infos_fichiers
178 *  Information sur les fichiers tels que déplacés par cvtupload_deplacer_fichier()
179 * @return void
180**/
181function cvtupload_modifier_files($infos_fichiers) {
182        foreach ($infos_fichiers as $champ => $description) {
183                if (isset($description['tmp_name'])) {//Upload unique
184                         $_FILES[$champ] = array();//On surcharge tout la description $_FILES pour ce champ.  Dans tous les cas les infos ont été stockées dans $description
185                         $_FILES[$champ]['name'] = $description['name'];
186                         $_FILES[$champ]['tmp_name'] = $description['tmp_name'];
187                         $_FILES[$champ]['type'] = $description['mime'];
188                         $_FILES[$champ]['error'] = 0; //on fait comme s'il n'y avait pas d'erreur, ce qui n'est pas forcément vrai…
189                         $_FILES[$champ]['size'] = $description['taille'];
190                } else {//Upload multiple
191                        //On surcharge tout la description $_FILES pour ce champ. Dans tous les cas les infos ont été stockées dans $description
192                        if (isset($_FILES[$champ])) {
193                                $old_FILES_champ = $_FILES[$champ];
194                        } else {
195                                $old_FILES_champ = array();
196                        }
197                        $_FILES[$champ]['name'] = array();
198                        $_FILES[$champ]['tmp_name'] = array();
199                        $_FILES[$champ]['type'] = array();
200                        $_FILES[$champ]['error'] = array();
201                        $_FILES[$champ]['size'] = array();
202                        // Et on re-rempli à partir de $description
203                        foreach ($description as $fichier_individuel => $description_fichier_individuel) {
204                                $_FILES[$champ]['name'][$fichier_individuel] = $description_fichier_individuel['name'];
205                                $_FILES[$champ]['tmp_name'][$fichier_individuel] = $description_fichier_individuel['tmp_name'];
206                                $_FILES[$champ]['type'][$fichier_individuel] = $description_fichier_individuel['mime'];
207                                $_FILES[$champ]['error'][$fichier_individuel] = 0; //on fait comme s'il n'y avait pas d'erreur, ce qui n'est pas forcément vrai…
208                                $_FILES[$champ]['size'][$fichier_individuel] = $description_fichier_individuel['taille'];
209                        }
210                        // Si on vient d'envoyer un ou plusieur $champ[] vide, on les rajoute dans notre nouveau $FILES
211                        if (isset($old_FILES_champ['error']) and is_array($old_FILES_champ['error'])) {
212                                foreach ($old_FILES_champ['error'] as $id_fichier_individuel => $error_fichier_individuel){
213                                        if ($error_fichier_individuel!=0 and !isset($infos_fichiers[$champ][$id_fichier_individuel])){//Uniquement les erreurs
214                                                $_FILES[$champ]['name'][$id_fichier_individuel] = $old_FILES_champ['name'][$id_fichier_individuel];
215                                                $_FILES[$champ]['tmp_name'][$id_fichier_individuel] = $old_FILES_champ['tmp_name'][$id_fichier_individuel];
216                                                $_FILES[$champ]['type'][$id_fichier_individuel] = $old_FILES_champ['type'][$id_fichier_individuel];
217                                                $_FILES[$champ]['error'][$id_fichier_individuel] = $old_FILES_champ['error'][$id_fichier_individuel];
218                                                $_FILES[$champ]['size'][$id_fichier_individuel] = $old_FILES_champ['size'][$id_fichier_individuel];
219                                        }
220                                }
221                        }
222                        // On remet de l'ordre dans champ dans chaque tableau correspondant à une propriété de $_FILES, histoire d'avoir 0,1,2,3 et pas 3,1,0,2
223                        foreach ($_FILES[$champ] as $propriete => $valeurs_propriete) {
224                                ksort($valeurs_propriete);
225                                $_FILES[$champ][$propriete] = $valeurs_propriete;
226                        }
227                }
228        }
229}
230
231/**
232 * Nettoyer $_FILES pour effacer les entrées dont on a vérifié qu'elle ne répondaient pas à certains critères
233 *
234 * @param string $champ
235 *      Le nom du champ concerné dans $_FILES
236 * @param string[]|string $erreurs
237 *      Si un upload multiple, un tableau des $erreurs avec comme clés les numéros des fichiers à supprimer dans $_FILES[$champ]
238 *      Si un upload unique, une chaîne, qui si non vide, indique qu'il faut effacer le $_FILE[$champ]
239 * @return void
240**/
241function cvtupload_nettoyer_files_selon_erreurs($champ, $erreurs) {
242        if (is_array($erreurs)) { // cas d'upload multiple
243                foreach ($erreurs as $cle => $erreur) {
244                        foreach ($_FILES[$champ] as $propriete => $valeur) {
245                                unset($_FILES[$champ][$propriete][$cle]);
246                        }
247                }
248        } elseif ($erreurs!='') { // cas d'upload unique avec erreur
249                unset($_FILES[$champ]);
250        }
251}
252
253/**
254 * Détermine un MIME lorsque les informations de PHP sont imprécises.
255 * Par exemple PHP considère qu'un fichier .tex est de MIME application/octet-stream
256 * Ce qui n'est absolument pas utilse
257 * @param string $mime_suppose
258 * @param string $extension
259 * @return string $mime_trouve
260**/
261function cvt_upload_determiner_mime($mime_suppose, $extension) {
262        if (!in_array($mime_suppose, array('text/plain', '', 'application/octet-stream'))) { // si on a un mime précis, on le renvoie, tout simplement
263                return $mime_suppose;
264        }
265        $mime_spip = sql_getfetsel('mime_type', 'spip_types_documents', 'extension='.sql_quote($extension));
266        if ($mime_spip) {
267                return $mime_spip;
268        } else {
269                return $mime_suppose;
270        }
271}
272
273/**
274 * Nettoyer un répertoire suivant l'age et le nombre de ses fichiers
275 *
276 * @param string $repertoire
277 *              Répertoire à nettoyer
278 * @param int $age_max
279 *              Age maxium des fichiers en seconde
280 * @param int $max_files
281 *              Nombre maximum de fichiers dans le dossier
282 * @return void
283 **/
284function cvtupload_nettoyer_repertoire($repertoire, $age_max = _CVTUPLOAD_AGE_MAX, $max_files = _CVTUPLOAD_MAX_FILES) {
285        include_spip('inc/flock');
286
287        // Si on entre bien dans le répertoire
288        if ($ressource_repertoire = opendir($repertoire)) {
289                $fichiers = array();
290
291                // On commence par supprimer les plus vieux
292                while ($fichier = readdir($ressource_repertoire)) {
293                        if (!in_array($fichier, array('.', '..', '.ok'))) {
294                                $chemin_fichier = $repertoire.$fichier;
295
296                                if (is_file($chemin_fichier) and !jeune_fichier($chemin_fichier, $age_max)) {
297                                        supprimer_fichier($chemin_fichier);
298                                } else {
299                                        $fichiers[@filemtime($chemin_fichier).'_'.rand()] = $chemin_fichier;
300                                }
301                        }
302                }
303
304                // On trie les fichiers par ordre de leur date
305                ksort($fichiers);
306
307                // Puis s'il reste trop de fichiers, on supprime le surplus
308                $nb_fichiers = count($fichiers);
309                if ($nb_fichiers > $max_files) {
310                        $nb_a_supprimer = $nb_fichiers - $max_files - 1;
311
312                        while ($nb_a_supprimer) {
313                                $fichier = array_shift($fichiers);
314                                supprimer_fichier($fichier);
315                                $nb_a_supprimer--;
316                        }
317                }
318        }
319}
Note: See TracBrowser for help on using the repository browser.