source: spip-zone/_core_/plugins/medias/inc/joindre_document.php

Last change on this file was 113294, checked in by spip.franck@…, 2 months ago

Il parait que le futur c'est maintenant :-D

File size: 11.0 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  SPIP, Systeme de publication pour l'internet                           *
5 *                                                                         *
6 *  Copyright (c) 2001-2019                                                *
7 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
8 *                                                                         *
9 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
10 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
11\***************************************************************************/
12
13if (!defined('_ECRIRE_INC_VERSION')) {
14        return;
15}
16
17
18/**
19 * Recuperer le nom du fichier selon le mode d'upload choisi
20 * et mettre cela au format $_FILES
21 *
22 * Renvoie une liste de fichier ou un message en cas d'erreur
23 *
24 * @return string/array
25 */
26function joindre_trouver_fichier_envoye() {
27        static $files = array();
28        // on est appele deux fois dans un hit, resservir ce qu'on a trouve a la verif
29        // lorsqu'on est appelle au traitement
30
31        if (count($files)) {
32                return $files;
33        }
34
35        if (_request('joindre_upload')) {
36                $post = isset($_FILES) ? $_FILES : $GLOBALS['HTTP_POST_FILES'];
37                $files = array();
38                if (is_array($post)) {
39                        include_spip('action/ajouter_documents');
40                        foreach ($post as $file) {
41                                if (is_array($file['name'])) {
42                                        while (count($file['name'])) {
43                                                $test = array(
44                                                        'error' => array_shift($file['error']),
45                                                        'name' => array_shift($file['name']),
46                                                        'tmp_name' => array_shift($file['tmp_name']),
47                                                        'type' => array_shift($file['type']),
48                                                );
49                                                if (!($test['error'] == 4)) {
50                                                        if (is_string($err = joindre_upload_error($test['error']))) {
51                                                                return $err;
52                                                        } // un erreur upload
53                                                        if (!is_array(verifier_upload_autorise($test['name']))) {
54                                                                return _T('medias:erreur_upload_type_interdit', array('nom' => $test['name']));
55                                                        }
56                                                        $files[] = $test;
57                                                }
58                                        }
59                                } else {
60                                        //UPLOAD_ERR_NO_FILE
61                                        if (!($file['error'] == 4)) {
62                                                if (is_string($err = joindre_upload_error($file['error']))) {
63                                                        return $err;
64                                                } // un erreur upload
65                                                if (!is_array(verifier_upload_autorise($file['name']))) {
66                                                        return _T('medias:erreur_upload_type_interdit', array('nom' => $file['name']));
67                                                }
68                                                $files[] = $file;
69                                        }
70                                }
71                        }
72                        if (!count($files)) {
73                                return _T('medias:erreur_indiquez_un_fichier');
74                        }
75                }
76
77                return $files;
78        } elseif (_request('joindre_distant')) {
79                $path = _request('url');
80                if (!strlen($path) or $path == 'http://') {
81                        return _T('medias:erreur_indiquez_un_fichier');
82                }
83                include_spip('inc/distant');
84                if (!valider_url_distante($path)) {
85                        return _T('medias:erreur_upload_type_interdit', array('nom' => $path));
86                }
87                include_spip('action/ajouter_documents');
88                $infos = renseigner_source_distante($path);
89                if (!is_array($infos)) {
90                        return $infos;
91                } // message d'erreur
92                else {
93                        return array(
94                                array(
95                                        'name' => basename($path),
96                                        'tmp_name' => $path,
97                                        'distant' => true,
98                                )
99                        );
100                }
101        } elseif (_request('joindre_ftp')) {
102                $path = _request('cheminftp');
103                if (!$path || strstr($path, '..')) {
104                        return _T('medias:erreur_indiquez_un_fichier');
105                }
106
107                include_spip('inc/documents');
108                include_spip('inc/actions');
109                $upload = determine_upload();
110                if ($path != '/' and $path != './') {
111                        $upload .= $path;
112                }
113
114                if (!is_dir($upload)) {
115                        // seul un fichier est demande
116                        return array(
117                                array(
118                                        'name' => basename($upload),
119                                        'tmp_name' => $upload
120                                )
121                        );
122                } else {
123                        // on upload tout un repertoire
124                        $files = array();
125                        foreach (preg_files($upload) as $fichier) {
126                                $files[] = array(
127                                        'name' => basename($fichier),
128                                        'tmp_name' => $fichier
129                                );
130                        }
131
132                        return $files;
133                }
134        } elseif (_request('joindre_zip') and $token_zip = _request('chemin_zip')) {
135                $zip_to_clean = (isset($GLOBALS['visiteur_session']['zip_to_clean']) ?
136                        unserialize($GLOBALS['visiteur_session']['zip_to_clean']) : array());
137                if (!$zip_to_clean
138                        or !isset($zip_to_clean[$token_zip])
139                        or !$path = $zip_to_clean[$token_zip]) {
140                        return _T('avis_operation_impossible');
141                }
142
143                include_spip('inc/documents'); //pour creer_repertoire_documents
144                define('_TMP_ZIP', $path);
145                define('_TMP_DIR', creer_repertoire_documents(md5($path . $GLOBALS['visiteur_session']['id_auteur'])));
146                if (_TMP_DIR == _DIR_IMG) {
147                        return _T('avis_operation_impossible');
148                }
149
150                $files = array();
151                if (_request('options_upload_zip') == 'deballe') {
152                        $files = joindre_deballer_lister_zip($path, _TMP_DIR);
153                }
154
155                // si le zip doit aussi etre conserve, l'ajouter
156                if (_request('options_upload_zip') == 'upload' or _request('options_deballe_zip_conserver')) {
157                        $files[] = array(
158                                'name' => basename($path),
159                                'tmp_name' => $path,
160                        );
161                }
162                return $files;
163        }
164
165        return array();
166}
167
168
169// Erreurs d'upload
170// renvoie false si pas d'erreur
171// et true si erreur = pas de fichier
172// pour les autres erreurs renvoie le message d'erreur
173function joindre_upload_error($error) {
174
175        if (!$error) {
176                return false;
177        }
178        spip_log("Erreur upload $error -- cf. http://php.net/manual/fr/features.file-upload.errors.php");
179        switch ($error) {
180                case 4: /* UPLOAD_ERR_NO_FILE */
181                        return true;
182
183                # on peut affiner les differents messages d'erreur
184                case 1: /* UPLOAD_ERR_INI_SIZE */
185                        $msg = _T(
186                                'medias:upload_limit',
187                                array('max' => ini_get('upload_max_filesize'))
188                        );
189                        break;
190                case 2: /* UPLOAD_ERR_FORM_SIZE */
191                        $msg = _T(
192                                'medias:upload_limit',
193                                array('max' => ini_get('upload_max_filesize'))
194                        );
195                        break;
196                case 3: /* UPLOAD_ERR_PARTIAL  */
197                        $msg = _T(
198                                'medias:upload_limit',
199                                array('max' => ini_get('upload_max_filesize'))
200                        );
201                        break;
202                case 6: /* UPLOAD_ERR_NO_TMP_DIR  */
203                        $msg = _T('medias:erreur_dossier_tmp_manquant');
204                        break;
205                case 7: /* UPLOAD_ERR_CANT_WRITE */
206                        $msg = _T('medias:erreur_ecriture_fichier');
207                        break;
208                default: /* autre */
209                        if (!$msg) {
210                                $msg = _T('pass_erreur') . ' ' . $error
211                                        . '<br />' . propre('[->http://php.net/manual/fr/features.file-upload.errors.php]');
212                        }
213                        break;
214        }
215        spip_log("erreur upload $error");
216        return $msg;
217}
218
219/**
220 * Verifier si le fichier poste est un zip
221 * Si on sait le deballer, proposer les options necessaires
222 *
223 * @param array $files
224 * @return string
225 */
226function joindre_verifier_zip($files) {
227        if (function_exists('gzopen')
228                and (count($files) == 1)
229                and !isset($files[0]['distant'])
230                and
231                (preg_match('/\.zip$/i', $files[0]['name'])
232                        or (isset($files[0]['type']) and $files[0]['type'] == 'application/zip'))
233        ) {
234                // on pose le fichier dans le repertoire zip
235                // (nota : copier_document n'ecrase pas un fichier avec lui-meme
236                // ca autorise a boucler)
237                include_spip('inc/getdocument');
238                $desc = $files[0];
239                $zip = copier_document(
240                        'zip',
241                        $desc['name'],
242                        $desc['tmp_name']
243                );
244
245                // Est-ce qu'on sait le lire ?
246                include_spip('inc/pclzip');
247                if ($zip
248                        and $archive = new PclZip($zip)
249                        and $contenu = joindre_decrire_contenu_zip($archive)
250                        and $tmp = sous_repertoire(_DIR_TMP, 'zip')
251                        and rename($zip, $tmp = $tmp . basename($zip))
252                ) {
253                        $zip_to_clean = (isset($GLOBALS['visiteur_session']['zip_to_clean']) ?
254                                unserialize($GLOBALS['visiteur_session']['zip_to_clean']) : array());
255                        $zip_to_clean[md5($tmp)] = $tmp;
256                        session_set('zip_to_clean', serialize($zip_to_clean));
257                        $contenu[] = $tmp;
258
259                        return $contenu;
260                }
261        }
262
263        // ce n'est pas un zip sur lequel il faut demander plus de precisions
264        return false;
265}
266
267/**
268 * Verifier et decrire les fichiers de l'archive, en deux listes :
269 * - une liste des noms de fichiers ajoutables
270 * - une liste des erreurs (fichiers refuses)
271 *
272 * @param object $zip
273 * @return array
274 */
275function joindre_decrire_contenu_zip($zip) {
276        include_spip('action/ajouter_documents');
277        // si pas possible de decompacter: installer comme fichier zip joint
278        if (!$list = $zip->listContent()) {
279                return false;
280        }
281
282        // Verifier si le contenu peut etre uploade (verif extension)
283        $fichiers = array();
284        $erreurs = array();
285        foreach ($list as $file) {
286                if (accepte_fichier_upload($f = $file['stored_filename'])) {
287                        $fichiers[$f] = $file;
288                } else // pas de message pour les dossiers et fichiers caches
289                {
290                        if (substr($f, -1) !== '/' and substr(basename($f), 0, 1) !== '.') {
291                                $erreurs[] = _T('medias:erreur_upload_type_interdit', array('nom' => $f));
292                        }
293                }
294        }
295
296        // si aucun fichier uploadable : installer comme fichier zip joint
297        if (!count($fichiers)) {
298                return false;
299        }
300
301        ksort($fichiers);
302
303        return array($fichiers, $erreurs);
304}
305
306
307// https://code.spip.net/@joindre_deballes
308function joindre_deballer_lister_zip($path, $tmp_dir) {
309        include_spip('inc/pclzip');
310        $archive = new PclZip($path);
311        $archive->extract(
312                PCLZIP_OPT_PATH,
313                $tmp_dir,
314                PCLZIP_CB_PRE_EXTRACT,
315                'callback_deballe_fichier'
316        );
317        if ($contenu = joindre_decrire_contenu_zip($archive)) {
318                $files = array();
319                $fichiers = reset($contenu);
320                foreach ($fichiers as $fichier) {
321                        $f = basename($fichier['filename']);
322                        $files[] = array(
323                                'tmp_name' => $tmp_dir . $f,
324                                'name' => $f,
325                                'titrer' => _request('options_deballe_zip_titrer'),
326                                'mode' => _request('options_deballe_zip_mode_document') ? 'document' : null
327                        );
328                }
329
330                return $files;
331        }
332
333        return _T('avis_operation_impossible');
334}
335
336if (!function_exists('fixer_extension_document')) {
337        /**
338         * Cherche dans la base le type-mime du tableau representant le document
339         * et corrige le nom du fichier ; retourne array(extension, nom corrige)
340         * s'il ne trouve pas, retourne '' et le nom inchange
341         *
342         * @param unknown_type $doc
343         * @return unknown
344         */
345// https://code.spip.net/@fixer_extension_document
346        function fixer_extension_document($doc) {
347                $extension = '';
348                $name = $doc['name'];
349                if (preg_match(',\.([^.]+)$,', $name, $r)
350                        and $t = sql_fetsel(
351                                'extension',
352                                'spip_types_documents',
353                                'extension=' . sql_quote(corriger_extension($r[1]))
354                        )
355                ) {
356                        $extension = $t['extension'];
357                        $name = preg_replace(',\.[^.]*$,', '', $doc['name']) . '.' . $extension;
358                } else {
359                        if ($t = sql_fetsel('extension', 'spip_types_documents', 'mime_type=' . sql_quote($doc['type']))) {
360                                $extension = $t['extension'];
361                                $name = preg_replace(',\.[^.]*$,', '', $doc['name']) . '.' . $extension;
362                        }
363                }
364
365                return array($extension, $name);
366        }
367}
368
369//
370// Gestion des fichiers ZIP
371//
372// https://code.spip.net/@accepte_fichier_upload
373
374function accepte_fichier_upload($f) {
375        if (!preg_match(',.*__MACOSX/,', $f)
376                and !preg_match(',^\.,', basename($f))
377        ) {
378                include_spip('action/ajouter_documents');
379                $ext = corriger_extension((strtolower(substr(strrchr($f, '.'), 1))));
380
381                return sql_countsel(
382                        'spip_types_documents',
383                        'extension=' . sql_quote($ext) . " AND upload='oui'"
384                );
385        }
386}
387
388# callback pour le deballage d'un zip telecharge
389# http://www.phpconcept.net/pclzip/man/en/?options-pclzip_cb_pre_extractfunction
390// https://code.spip.net/@callback_deballe_fichier
391
392function callback_deballe_fichier($p_event, &$p_header) {
393        if (accepte_fichier_upload($p_header['filename'])) {
394                $p_header['filename'] = _TMP_DIR . basename($p_header['filename']);
395
396                return 1;
397        } else {
398                return 0;
399        }
400}
Note: See TracBrowser for help on using the repository browser.