[SPIP] ~v3.0.20-->v3.0.25
[lhc/web/clavette_www.git] / www / plugins-dist / medias / action / ajouter_documents.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2016 *
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
13 if (!defined("_ECRIRE_INC_VERSION")) return;
14
15 include_spip('inc/getdocument');
16 include_spip('inc/documents');
17 include_spip('inc/choisir_mode_document'); // compat core
18 include_spip('inc/renseigner_document');
19
20 /**
21 * Ajouter des documents
22 *
23 * @param int $id_document
24 * document a remplacer, ou pour une vignette, l'id_document de maman
25 * 0 ou 'new' pour une insertion
26 * @param $files
27 * tableau de taleau de propriete pour chaque document a inserer
28 * @param $objet
29 * objet auquel associer le document
30 * @param $id_objet
31 * id_objet
32 * @param $mode
33 * mode par defaut si pas precise pour le document
34 * @return array
35 * liste des id_documents inseres
36 */
37 function action_ajouter_documents_dist($id_document, $files, $objet, $id_objet, $mode){
38 $ajouter_un_document = charger_fonction('ajouter_un_document','action');
39 $ajoutes = array();
40
41 // on ne peut mettre qu'un seul document a la place d'un autre ou en vignette d'un autre
42 if (intval($id_document)){
43 $ajoutes[] = $ajouter_un_document($id_document, reset($files), $objet, $id_objet, $mode);
44 }
45 else
46 foreach($files as $file){
47 $ajoutes[] = $ajouter_un_document('new', $file, $objet, $id_objet, $mode);
48 }
49 return $ajoutes;
50 }
51
52 /**
53 * Ajouter un document (au format $_FILES)
54 *
55 * http://code.spip.net/@ajouter_un_document
56 *
57 * @param int $id_document
58 * document a remplacer, ou pour une vignette, l'id_document de maman
59 * 0 ou 'new' pour une insertion
60 * @param array $file
61 * proprietes au format $_FILE etendu :
62 * string tmp_name : source sur le serveur
63 * string name : nom du fichier envoye
64 * bool titrer : donner ou non un titre a partir du nom du fichier
65 * bool distant : pour utiliser une source distante sur internet
66 * string mode : vignette|image|documents|choix
67 * @param string $objet
68 * objet auquel associer le document
69 * @param int $id_objet
70 * id_objet
71 * @param string $mode
72 * mode par defaut si pas precise pour le document
73 * @return array|bool|int|mixed|string|unknown
74 * si int : l'id_document ajouté (opération réussie)
75 * si string : une erreur s'est produit, la chaine est le message d'erreur
76 *
77 */
78 function action_ajouter_un_document_dist($id_document, $file, $objet, $id_objet, $mode) {
79
80 $source = $file['tmp_name'];
81 $nom_envoye = $file['name'];
82
83 // passer en minuscules le nom du fichier, pour eviter les collisions
84 // si le file system fait la difference entre les deux il ne detectera
85 // pas que Toto.pdf et toto.pdf
86 // et on aura une collision en cas de changement de file system
87 $file['name'] = strtolower(translitteration($file['name']));
88
89 // Pouvoir definir dans mes_options.php que l'on veut titrer tous les documents par d?faut
90 if (!defined('_TITRER_DOCUMENTS')) { define('_TITRER_DOCUMENTS', false); }
91
92 $titrer = isset($file['titrer'])?$file['titrer']:_TITRER_DOCUMENTS;
93 $mode = ((isset($file['mode']) AND $file['mode'])?$file['mode']:$mode);
94
95 include_spip('inc/modifier');
96 if (isset($file['distant']) AND $file['distant'] AND !in_array($mode,array('choix','auto','image','document'))) {
97 spip_log("document distant $source accepte sans verification, mode=$mode","medias"._LOG_INFO_IMPORTANTE);
98 include_spip('inc/distant');
99 $file['tmp_name'] = _DIR_RACINE . copie_locale($source);
100 $source = $file['tmp_name'];
101 unset($file['distant']);
102 }
103
104 // Documents distants : pas trop de verifications bloquantes, mais un test
105 // via une requete HEAD pour savoir si la ressource existe (non 404), si le
106 // content-type est connu, et si possible recuperer la taille, voire plus.
107 if (isset($file['distant']) AND $file['distant']) {
108 if (!tester_url_absolue($source)){
109 return _T('medias:erreur_chemin_distant', array('nom' => $source));
110 }
111 include_spip('inc/distant');
112 if (is_array($a = renseigner_source_distante($source))) {
113
114 $champs = $a;
115 # NB: dans les bonnes conditions (fichier autorise et pas trop gros)
116 # $a['fichier'] est une copie locale du fichier
117
118 unset($champs['type_image']);
119 }
120 // on ne doit plus arriver ici, car l'url distante a ete verifiee a la saisie !
121 else {
122 spip_log("Echec du lien vers le document $source, abandon");
123 return $a; // message d'erreur
124 }
125 }
126 else { // pas distant
127
128 $champs = array(
129 'distant' => 'non'
130 );
131
132 $type_image = ''; // au pire
133 $champs['titre'] = '';
134 if ($titrer){
135 $titre = substr($nom_envoye,0, strrpos($nom_envoye, ".")); // Enlever l'extension du nom du fichier
136 $titre = preg_replace(',[[:punct:][:space:]]+,u', ' ', $titre);
137 $champs['titre'] = preg_replace(',\.([^.]+)$,', '', $titre);
138 }
139
140 if (!is_array($fichier = fixer_fichier_upload($file, $mode)))
141 return is_string($fichier)?$fichier:_T("medias:erreur_upload_type_interdit",array('nom'=>$file['name']));
142
143 $champs['inclus'] = $fichier['inclus'];
144 $champs['extension'] = $fichier['extension'];
145 $champs['fichier'] = $fichier['fichier'];
146
147 /**
148 * Récupère les informations du fichier
149 * -* largeur
150 * -* hauteur
151 * -* type_image
152 * -* taille
153 * -* ses metadonnées si une fonction de metadatas/ est présente
154 */
155 $infos = renseigner_taille_dimension_image($champs['fichier'],$champs['extension']);
156 if (is_string($infos))
157 return $infos; // c'est un message d'erreur !
158
159 $champs = array_merge($champs,$infos);
160
161 // Si mode == 'choix', fixer le mode image/document
162 if (in_array($mode,array('choix','auto'))) {
163 $choisir_mode_document = charger_fonction('choisir_mode_document','inc');
164 $mode = $choisir_mode_document($champs, $champs['inclus'] == 'image', $objet);
165 }
166 $champs['mode'] = $mode;
167
168 if (($test = verifier_taille_document_acceptable($champs))!==true){
169 spip_unlink($champs['fichier']);
170 return $test; // erreur sur les dimensions du fichier
171 }
172
173 unset($champs['type_image']);
174 unset($champs['inclus']);
175 $champs['fichier'] = set_spip_doc($champs['fichier']);
176 }
177
178 // si le media est pas renseigne, le faire, en fonction de l'extension
179 if (!isset($champs['media'])){
180 $champs['media'] = sql_getfetsel('media_defaut','spip_types_documents','extension='.sql_quote($champs['extension']));
181 }
182
183 // lier le parent si necessaire
184 if ($id_objet=intval($id_objet) AND $objet)
185 $champs['parents'][] = "$objet|$id_objet";
186
187 // "mettre a jour un document" si on lui
188 // passe un id_document
189 if ($id_document=intval($id_document)){
190 unset($champs['titre']); // garder le titre d'origine
191 unset($champs['date']); // garder la date d'origine
192 unset($champs['descriptif']); // garder la desc d'origine
193 // unset($a['distant']); # on peut remplacer un doc statique par un doc distant
194 // unset($a['mode']); # on peut remplacer une image par un document ?
195 }
196
197 include_spip('action/editer_document');
198 // Installer le document dans la base
199 if (!$id_document){
200 if ($id_document = document_inserer())
201 spip_log ("ajout du document ".$file['tmp_name']." ".$file['name']." (M '$mode' T '$objet' L '$id_objet' D '$id_document')",'medias');
202 else
203 spip_log ("Echec insert_document() du document ".$file['tmp_name']." ".$file['name']." (M '$mode' T '$objet' L '$id_objet' D '$id_document')",'medias'._LOG_ERREUR);
204 }
205 if (!$id_document)
206 return _T('medias:erreur_insertion_document_base',array('fichier'=>"<em>".$file['name']."</em>"));
207
208 document_modifier($id_document,$champs);
209
210 // permettre aux plugins de faire des modifs a l'ajout initial
211 // ex EXIF qui tourne les images si necessaire
212 // Ce plugin ferait quand même mieux de se placer dans metadata/jpg.php
213 pipeline('post_edition',
214 array(
215 'args' => array(
216 'table' => 'spip_documents', // compatibilite
217 'table_objet' => 'documents',
218 'spip_table_objet' => 'spip_documents',
219 'type' =>'document',
220 'id_objet' => $id_document,
221 'champs' => array_keys($champs),
222 'serveur' => '', // serveur par defaut, on ne sait pas faire mieux pour le moment
223 'action' => 'ajouter_document',
224 'operation' => 'ajouter_document', // compat <= v2.0
225 ),
226 'data' => $champs
227 )
228 );
229
230 return $id_document ;
231 }
232
233
234 /**
235 * Corrige l'extension du fichier dans quelques cas particuliers
236 * (a passer dans ecrire/base/typedoc)
237 * A noter : une extension 'pdf ' passe dans la requete de controle
238 * mysql> SELECT * FROM spip_types_documents WHERE extension="pdf ";
239 *
240 * @param string $ext
241 * @return string
242 */
243 function corriger_extension($ext) {
244 $ext = preg_replace(',[^a-z0-9],i', '', $ext);
245 switch ($ext) {
246 case 'htm':
247 $ext='html';
248 break;
249 case 'jpeg':
250 $ext='jpg';
251 break;
252 case 'tiff':
253 $ext='tif';
254 break;
255 case 'aif':
256 $ext='aiff';
257 break;
258 case 'mpeg':
259 $ext='mpg';
260 break;
261 }
262 return $ext;
263 }
264
265 /**
266 * Verifie la possibilite d'uploader une extension
267 * renvoie un tableau descriptif si l'extension est acceptee
268 * avec un index 'autozip' si il faut zipper
269 * false ou message d'erreur si l'extension est refusee
270 * Verifie aussi si l'extension est autorisee pour le mode demande
271 * si on connait le mode a ce moment la
272 *
273 */
274 function verifier_upload_autorise($source, $mode=''){
275 $infos = array('fichier'=>$source);
276 $res = false;
277 if (preg_match(",\.([a-z0-9]+)(\?.*)?$,i", $source, $match)
278 AND $ext = $match[1]){
279
280 $ext = corriger_extension(strtolower($ext));
281 if ($res = sql_fetsel("extension,inclus,media_defaut as media", "spip_types_documents", "extension=" . sql_quote($ext) . " AND upload='oui'"))
282 $infos = array_merge($infos,$res);
283 }
284 if (!$res){
285 if ($res = sql_fetsel("extension,inclus,media_defaut as media", "spip_types_documents", "extension='zip' AND upload='oui'")){
286 $infos = array_merge($infos,$res);
287 $res['autozip'] = true;
288 }
289 }
290 if ($mode AND $res){
291 // verifier en fonction du mode si une fonction est proposee
292 if ($verifier_document_mode = charger_fonction("verifier_document_mode_".$mode,"inc",true)){
293 $check = $verifier_document_mode($infos); // true ou message d'erreur sous forme de chaine
294 if ($check!==true)
295 $res = $check;
296 }
297 }
298
299 if (!$res OR is_string($res)) {
300 spip_log("Upload $source interdit ($res)",_LOG_INFO_IMPORTANTE);
301 }
302
303 return $res;
304 }
305
306
307 /**
308 * tester le type de document :
309 * - interdit a l'upload ?
310 * - quelle extension dans spip_types_documents ?
311 * - est-ce "inclus" comme une image ?
312 *
313 * le zipper si necessaire
314 *
315 * @param array $file //format $_FILES
316 * @return array
317 */
318 function fixer_fichier_upload($file, $mode=''){
319
320 if (is_array($row=verifier_upload_autorise($file['name'], $mode))) {
321 if (!isset($row['autozip'])){
322 $row['fichier'] = copier_document($row['extension'], $file['name'], $file['tmp_name']);
323
324 /**
325 * On vérifie que le fichier a une taille
326 * si non, on le supprime et on affiche une erreur
327 */
328 if($row['fichier'] && (!$taille = @intval(filesize(get_spip_doc($row['fichier']))))) {
329 spip_log ("Echec copie du fichier ".$file['tmp_name']." (taille de fichier indéfinie)");
330 spip_unlink(get_spip_doc($row['fichier']));
331 return _T('medias:erreur_copie_fichier',array('nom'=> $file['tmp_name']));
332 }else
333 return $row;
334 }
335 // creer un zip comme demande
336 // pour encapsuler un fichier dont l'extension n'est pas supportee
337 else{
338
339 unset($row['autozip']);
340
341 $ext = 'zip';
342 if (!$tmp_dir = tempnam(_DIR_TMP, 'tmp_upload'))
343 return false;
344
345 spip_unlink($tmp_dir);
346 @mkdir($tmp_dir);
347
348 include_spip('inc/charsets');
349 $tmp = $tmp_dir.'/'.translitteration($file['name']);
350
351 $file['name'] .= '.'.$ext; # conserver l'extension dans le nom de fichier, par exemple toto.js => toto.js.zip
352
353 // deplacer le fichier tmp_name dans le dossier tmp
354 deplacer_fichier_upload($file['tmp_name'], $tmp, true);
355
356 include_spip('inc/pclzip');
357 $source = _DIR_TMP . basename($tmp_dir) . '.'.$ext;
358 $archive = new PclZip($source);
359
360 $v_list = $archive->create($tmp,
361 PCLZIP_OPT_REMOVE_PATH, $tmp_dir,
362 PCLZIP_OPT_ADD_PATH, '');
363
364 effacer_repertoire_temporaire($tmp_dir);
365 if (!$v_list) {
366 spip_log("Echec creation du zip ");
367 return false;
368 }
369
370 $row['fichier'] = copier_document($row['extension'], $file['name'], $source);
371 spip_unlink($source);
372
373 /**
374 * On vérifie que le fichier zip créé a une taille
375 * si non, on le supprime et on affiche une erreur
376 */
377 if($row['fichier'] && (!$taille = @intval(filesize(get_spip_doc($row['fichier']))))) {
378 spip_log ("Echec copie du fichier ".$file['tmp_name']." (taille de fichier indéfinie)");
379 spip_unlink(get_spip_doc($row['fichier']));
380 return _T('medias:erreur_copie_fichier',array('nom'=> $file['tmp_name']));
381 }else
382 return $row;
383 }
384 }
385 else
386 return $row; // retourner le message d'erreur
387 }
388
389 /**
390 * Verifier si le fichier respecte les contraintes de tailles
391 *
392 * @param array $infos
393 * @return bool|mixed|string
394 */
395 function verifier_taille_document_acceptable($infos){
396
397 // si ce n'est pas une image
398 if (!$infos['type_image']) {
399 if (_DOC_MAX_SIZE > 0
400 AND $infos['taille'] > _DOC_MAX_SIZE*1024)
401 return _T('medias:info_doc_max_poids', array('maxi' => taille_en_octets(_DOC_MAX_SIZE*1024), 'actuel' => taille_en_octets($infos['taille'])));
402 }
403
404 // si c'est une image
405 else {
406
407 if (_IMG_MAX_SIZE > 0
408 AND $infos['taille'] > _IMG_MAX_SIZE*1024)
409 return _T('medias:info_image_max_poids', array('maxi' => taille_en_octets(_IMG_MAX_SIZE*1024), 'actuel' => taille_en_octets($infos['taille'])));
410
411 if (_IMG_MAX_WIDTH * _IMG_MAX_HEIGHT
412 AND ($infos['largeur'] > _IMG_MAX_WIDTH
413 OR $infos['hauteur'] > _IMG_MAX_HEIGHT))
414
415 return _T('medias:info_logo_max_taille',
416 array(
417 'maxi' =>
418 _T('info_largeur_vignette',
419 array('largeur_vignette' => _IMG_MAX_WIDTH,
420 'hauteur_vignette' => _IMG_MAX_HEIGHT)),
421 'actuel' =>
422 _T('info_largeur_vignette',
423 array('largeur_vignette' => $infos['largeur'],
424 'hauteur_vignette' => $infos['hauteur']))
425 ));
426 }
427
428 // verifier en fonction du mode si une fonction est proposee
429 if ($verifier_document_mode = charger_fonction("verifier_document_mode_".$infos['mode'],"inc",true))
430 return $verifier_document_mode($infos);
431
432 return true;
433 }
434
435
436 ?>