[SPIP] ~2.1.12 -->2.1.25
[velocampus/web/www.git] / www / ecrire / inc / ajouter_documents.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2014 *
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
18 // Joindre un document ou un Zip a deballer (fonction pour action/joindre)
19 // Distinguer les deux cas pour commencer
20
21 // http://doc.spip.org/@inc_ajouter_documents_dist
22 function inc_ajouter_documents_dist ($sources, $file, $type, $id, $mode, $id_document, &$actifs, $hout='', $redirect='', $iframe_redirect='')
23 {
24 if (is_array($sources))
25 return liste_archive_jointe($sources, $file, $type, $id, $mode, $id_document, $hout, $redirect, $iframe_redirect);
26 else
27 return ajouter_un_document($sources, $file, $type, $id, $mode, $id_document, $actifs, $hout);
28 }
29
30
31 /**
32 * Choisir le mode du document : image/document
33 * fonction surchargeable
34 *
35 * @param unknown_type $fichier
36 * @param unknown_type $type_image
37 * @param unknown_type $largeur
38 * @param unknown_type $hauteur
39 */
40 function inc_choisir_mode_document_dist($fichier, $type_lien, $type_image, $largeur, $hauteur){
41
42 // si ce n'est pas une image, c'est forcement un document
43 if (!in_array($type_image, array('gif', 'png', 'jpg')))
44 return 'document';
45
46 // si on a pas le droit d'ajouter de document a l'objet, c'est donc un mode image
47 if ($type_lien AND isset($GLOBALS['meta']["documents_$type_lien"]) AND ($GLOBALS['meta']["documents_$type_lien"]=='non'))
48 return 'image';
49
50
51 // _INTERFACE_DOCUMENTS
52 // en fonction de la taille de l'image
53 // par defaut l'affectation en fonction de la largeur de l'image
54 // est desactivee car pas comprehensible par le novice
55 // il suffit de faire dans mes_options
56 // define('_LARGEUR_MODE_IMAGE', 450);
57 // pour beneficier de cette detection auto
58 if (!defined('_LARGEUR_MODE_IMAGE')) define('_LARGEUR_MODE_IMAGE', 0);
59
60 if (!_LARGEUR_MODE_IMAGE)
61 return 'image';
62
63 if ($largeur > 0
64 AND $largeur < _LARGEUR_MODE_IMAGE)
65 return 'image';
66 else
67 return 'document';
68 }
69
70 //
71 // Ajouter un document (au format $_FILES)
72 //
73 # $source, # le fichier sur le serveur (/var/tmp/xyz34)
74 # $nom_envoye, # son nom chez le client (portequoi.pdf)
75 # $type_lien, # lie a un article, une breve ou une rubrique ?
76 # $id_lien, # identifiant de l'article (ou rubrique) lie
77 # $mode, # 'image' => image en mode image
78 # # 'vignette' => personnalisee liee a un document
79 # 'document' => doc ou image en mode document
80 # 'distant' => lien internet
81 # $id_document, # pour une vignette, l'id_document de maman
82 # $actifs # les documents dont il faudra ouvrir la boite de dialogue
83
84 // http://doc.spip.org/@ajouter_un_document
85 function ajouter_un_document($source, $nom_envoye, $type_lien, $id_lien, $mode, $id_document, &$documents_actifs, $titrer=false) {
86
87 include_spip('inc/modifier');
88
89 // Documents distants : pas trop de verifications bloquantes, mais un test
90 // via une requete HEAD pour savoir si la ressource existe (non 404), si le
91 // content-type est connu, et si possible recuperer la taille, voire plus.
92
93 if ($mode == 'distant') {
94 include_spip('inc/distant');
95 if ($a = recuperer_infos_distantes($source)) {
96
97 # NB: dans les bonnes conditions (fichier autorise et pas trop gros)
98 # $a['fichier'] est une copie locale du fichier
99
100 $type_image = $a['type_image'];
101
102 unset($a['type_image']);
103 unset($a['body']);
104
105 $a['date'] = date('Y-m-d H:i:s');
106 $a['distant'] = 'oui';
107 $a['mode'] = 'document';
108 $a['fichier'] = set_spip_doc($source);
109 }
110 else {
111 spip_log("Echec du lien vers le document $source, abandon");
112 return;
113 }
114 } else { // pas distant
115
116 $type_image = ''; // au pire
117 // tester le type de document :
118 // - interdit a l'upload ?
119 // - quelle extension dans spip_types_documents ?
120 // - est-ce "inclus" comme une image ?
121 list($nom_envoye, $ext, $titre, $inclus) = corriger_extension_et_nom($nom_envoye, $titrer);
122
123 if ($inclus !== false) {
124 $type_inclus_image = ($inclus == 'image');
125 $fichier = copier_document($ext, $nom_envoye, $source);
126 } else {
127
128 /* STOCKER LES DOCUMENTS INCONNUS AU FORMAT .ZIP */
129 $type_inclus_image = false;
130
131 if (!sql_countsel("spip_types_documents", "extension='zip' AND upload='oui'")) {
132 spip_log("Extension $ext interdite a l'upload");
133 return;
134 }
135
136 $ext = 'zip';
137 if (!$tmp_dir = tempnam(_DIR_TMP, 'tmp_upload')) return;
138 spip_unlink($tmp_dir); @mkdir($tmp_dir);
139 $tmp = $tmp_dir.'/'.translitteration($nom_envoye);
140 $nom_envoye .= '.zip'; # conserver l'extension dans le nom de fichier, par exemple toto.js => toto.js.zip
141 deplacer_fichier_upload($source, $tmp);
142 include_spip('inc/pclzip');
143 $source = _DIR_TMP . 'archive.zip';
144 $archive = new PclZip($source);
145 $v_list = $archive->create($tmp,
146 PCLZIP_OPT_REMOVE_PATH, $tmp_dir,
147 PCLZIP_OPT_ADD_PATH, '');
148 effacer_repertoire_temporaire($tmp_dir);
149 if (!$v_list) {
150 spip_log("Echec creation du zip ");
151 return;
152 }
153 $fichier = copier_document($ext, $nom_envoye, $source);
154 spip_unlink($source);
155 }
156
157 // Prevoir traitement specifique pour videos
158 // (http://www.getid3.org/ peut-etre
159 if ($ext == "mov") {
160 $largeur = 0;
161 $hauteur = 0;
162 } else if ($ext == "svg") {
163 // recuperer les dimensions et supprimer les scripts
164 list($largeur,$hauteur)= traite_svg($fichier);
165 } else { // image ?
166 // Si c'est une image, recuperer sa taille et son type (detecte aussi swf)
167 $size_image = @getimagesize($fichier);
168 $largeur = intval($size_image[0]);
169 $hauteur = intval($size_image[1]);
170 $type_image = decoder_type_image($size_image[2]);
171 }
172
173 // Quelques infos sur le fichier
174 if (!$fichier OR !@file_exists($fichier)
175 OR !$taille = @intval(filesize($fichier))) {
176 spip_log ("Echec copie du fichier $fichier");
177 return;
178 }
179
180 // _INTERFACE_DOCUMENTS
181 // Si mode == 'choix', fixer le mode image/document
182 if ($mode == 'choix') {
183 $choisir_mode_document = charger_fonction('choisir_mode_document','inc');
184 $mode = $choisir_mode_document($fichier, $type_lien, $type_image, $largeur, $hauteur);
185 }
186
187
188 if (!$type_image) {
189 if (_DOC_MAX_SIZE > 0
190 AND $taille > _DOC_MAX_SIZE*1024) {
191 spip_unlink ($fichier);
192 check_upload_error(6,
193 _T('info_logo_max_poids',
194 array('maxi' => taille_en_octets(_DOC_MAX_SIZE*1024),
195 'actuel' => taille_en_octets($taille))));
196 }
197 if ($mode == 'image') {
198 spip_log ("le format de $fichier ne convient pas pour une image");
199 spip_unlink($fichier);
200 return;
201 }
202 }
203 else { // image
204 if (_IMG_MAX_SIZE > 0
205 AND $taille > _IMG_MAX_SIZE*1024) {
206 spip_unlink ($fichier);
207 check_upload_error(6,
208 _T('info_logo_max_poids',
209 array('maxi' => taille_en_octets(_IMG_MAX_SIZE*1024),
210 'actuel' => taille_en_octets($taille))));
211 }
212
213 if (_IMG_MAX_WIDTH * _IMG_MAX_HEIGHT
214 AND ($size_image[0] > _IMG_MAX_WIDTH
215 OR $size_image[1] > _IMG_MAX_HEIGHT)) {
216 spip_unlink ($fichier);
217 check_upload_error(6,
218 _T('info_logo_max_taille',
219 array(
220 'maxi' =>
221 _T('info_largeur_vignette',
222 array('largeur_vignette' => _IMG_MAX_WIDTH,
223 'hauteur_vignette' => _IMG_MAX_HEIGHT)),
224 'actuel' =>
225 _T('info_largeur_vignette',
226 array('largeur_vignette' => $size_image[0],
227 'hauteur_vignette' => $size_image[1]))
228 )));
229 }
230 }
231
232 // Si on veut uploader une vignette, il faut qu'elle ait ete bien lue
233 if ($mode == 'vignette') {
234 if (!$type_inclus_image) {
235 spip_log ("le format de $fichier ne convient pas pour une image"); # SVG
236 spip_unlink($fichier);
237 return;
238 }
239
240 if (!($largeur OR $hauteur)) {
241 spip_log('erreur upload vignette '.$fichier);
242 spip_unlink($fichier);
243 return;
244 }
245 } elseif (!in_array($mode, array('distant', 'image', 'document'))) {
246 if ($type_image AND $type_inclus_image)
247 $mode = 'image';
248 else
249 $mode = 'document';
250 }
251 $a = array(
252 'date' => date('Y-m-d H:i:s'),
253 'distant' => 'non',
254 'mode' => $mode,
255 'titre'=> $titre,
256 'largeur' => $largeur,
257 'hauteur' => $hauteur,
258 'taille' => $taille,
259 'extension'=> $ext,
260 'fichier' => set_spip_doc($fichier));
261 }
262
263 if (($id_document=intval($id_document)) AND $mode!='vignette') {
264
265 // Mise a jour des descripteurs d'un vieux doc
266 unset($a['titre']);
267 unset($a['date']);
268 unset($a['distant']);
269 unset($a['mode']);
270
271 sql_updateq('spip_documents', $a, "id_document=$id_document");
272 $id = $id_document;
273
274 } else {
275 // Installer le document dans la base
276 // attention piege semantique : les images s'installent en mode 'vignette'
277 // note : la fonction peut "mettre a jour un document" si on lui
278 // passe "mode=document" et "id_document=.." (pas utilise)
279
280 // Envoyer aux plugins
281 $a = pipeline('pre_insertion',
282 array(
283 'args' => array(
284 'table' => 'spip_documents',
285 ),
286 'data' => $a
287 )
288 );
289
290 if (strlen($a['fichier']) > 255) {
291 spip_log("Upload avec nom > 255 : " . $a['fichier']);
292 return;
293 }
294 $id = sql_insertq("spip_documents", $a);
295
296 pipeline('post_insertion',
297 array(
298 'args' => array(
299 'table' => 'spip_documents',
300 'id_objet' => $id_document
301 ),
302 'data' => $a
303 )
304 );
305
306 spip_log ("ajout du document $source $nom_envoye (M '$mode' T '$type_lien' L '$id_lien' D '$id')");
307
308 if ($id_lien AND $id
309 AND preg_match('/^[a-z0-9_]+$/i', $type_lien) # securite
310 ) {
311 sql_insertq('spip_documents_liens',
312 array('id_document' => $id,
313 'id_objet' => $id_lien,
314 'objet' => $type_lien));
315 } else spip_log("Pb d'insertion $id_lien $type_lien");
316
317 if ($id_document) {
318 sql_updateq("spip_documents", array("id_vignette" => $id, "mode" => 'document'), "id_document=$id_document");
319
320 } else $id_document = $id;
321
322
323 // Appliquer l'exif orientation
324 // http://trac.rezo.net/trac/spip/ticket/1494
325 define('_TOURNER_SELON_EXIF', false); # par defaut non, risque memoire
326 if (defined('_TOURNER_SELON_EXIF')
327 AND _TOURNER_SELON_EXIF
328 AND $mode == 'document'
329 AND $a['distant'] == 'non'
330 AND $a['extension'] == 'jpg') {
331 include_spip('action/tourner');
332 tourner_selon_exif_orientation($id_document, $fichier);
333 }
334
335 }
336 // pour que le retour vers ecrire/ active le bon doc.
337 $documents_actifs[$fichier] = $id_document;
338 // Notifications, gestion des revisions, reindexation...
339 pipeline('post_edition',
340 array(
341 'args' => array(
342 'operation' => 'ajouter_document',
343 'table' => 'spip_documents',
344 'id_objet' => $id,
345 'type_image' => $type_image
346 ),
347 'data' => null
348 )
349 );
350
351 return $id ;
352 }
353
354 // http://doc.spip.org/@verifier_compactes
355 function verifier_compactes($zip) {
356 if (!$list = $zip->listContent()) return array();
357 // si pas possible de decompacter: installer comme fichier zip joint
358 // Verifier si le contenu peut etre uploade (verif extension)
359 $aff_fichiers = array();
360 foreach ($list as $file) {
361 if (accepte_fichier_upload($f = $file['stored_filename']))
362 $aff_fichiers[$f] = $file;
363 else spip_log("chargement de $f interdit");
364 }
365 ksort($aff_fichiers);
366 return $aff_fichiers;
367 }
368
369 //
370 // Convertit le type numerique retourne par getimagesize() en extension fichier
371 //
372
373 // http://doc.spip.org/@decoder_type_image
374 function decoder_type_image($type, $strict = false) {
375 switch ($type) {
376 case 1:
377 return "gif";
378 case 2:
379 return "jpg";
380 case 3:
381 return "png";
382 case 4:
383 return $strict ? "" : "swf";
384 case 5:
385 return "psd";
386 case 6:
387 return "bmp";
388 case 7:
389 case 8:
390 return "tif";
391 default:
392 return "";
393 }
394 }
395
396
397 // http://doc.spip.org/@traite_svg
398 function traite_svg($file)
399 {
400 $texte = spip_file_get_contents($file);
401
402 // Securite si pas admin : virer les scripts et les references externes
403 // sauf si on est en mode javascript 'ok' (1), cf. inc_version
404 if ($GLOBALS['filtrer_javascript'] < 1
405 AND !autoriser('televerser','script')) {
406 include_spip('inc/texte');
407 $new = trim(safehtml($texte));
408 // petit bug safehtml
409 if (substr($new,0,2) == ']>') $new = ltrim(substr($new,2));
410 if ($new != $texte) ecrire_fichier($file, $texte = $new);
411 }
412
413 $width = $height = 150;
414 if (preg_match(',<svg[^>]+>,', $texte, $s)) {
415 $s = $s[0];
416 if (preg_match(',\WviewBox\s*=\s*.\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+),i', $s, $r)){
417 $width = $r[3];
418 $height = $r[4];
419 } else {
420 // si la taille est en centimetre, estimer le pixel a 1/64 de cm
421 if (preg_match(',\Wwidth\s*=\s*.(\d+)([^"\']*),i', $s, $r)){
422 if ($r[2] != '%') {
423 $width = $r[1];
424 if ($r[2] == 'cm') $width <<=6;
425 }
426 }
427 if (preg_match(',\Wheight\s*=\s*.(\d+)([^"\']*),i', $s, $r)){
428 if ($r[2] != '%') {
429 $height = $r[1];
430 if ($r[2] == 'cm') $height <<=6;
431 }
432 }
433 }
434 }
435 return array($width, $height);
436 }
437
438 // Regexp synthetisant un titre a partir d'un nom de fichier.
439 // Exemple: squelette-de-Mozart-vers-5-ans.jpg => squelette de Mozart vers 5 ans
440 define('_REGEXP_TITRER_DOCUMENT', ',[[:punct:][:space:]]+,u');
441
442 function corriger_extension_et_nom($nom, $titrer=false)
443 {
444 preg_match(",^(.*)\.([^.]+)$,", $nom, $match);
445 @list(,$titre,$ext) = $match;
446 // les navigateur devraient savoir que ceci est mime-type text
447 if (!$ext AND (strtolower($nom) === 'makefile'))
448 $ext = 'txt';
449 // securite : pas de . en dehors de celui separant l'extension
450 // sinon il est possible d'injecter du php dans un toto.php.txt
451 else $nom = str_replace('.','-',$titre).'.'.$ext;
452
453 if ($titrer) {
454 $titre = is_string($titre) ? $titre : preg_replace("%".$titre."%", ' ', $titre ? $titre : $nom);
455 } else $titre = '';
456 $ext = corriger_extension(strtolower($ext));
457 $row = sql_fetsel("inclus", "spip_types_documents", "extension=" . sql_quote($ext) . " AND upload='oui'");
458 return array($nom, $ext, $titre, $row ? $row['inclus'] : false);
459 }
460
461 //
462 // Corrige l'extension du fichier dans quelques cas particuliers
463 // (a passer dans ecrire/base/typedoc)
464 // A noter : une extension 'pdf ' passe dans la requete de controle
465 // mysql> SELECT * FROM spip_types_documents WHERE extension="pdf ";
466 // http://doc.spip.org/@corriger_extension
467 function corriger_extension($ext) {
468 $ext = preg_replace(',[^a-z0-9],i', '', $ext);
469 switch ($ext) {
470 case 'htm':
471 return 'html';
472 case 'jpeg':
473 return 'jpg';
474 case 'tiff':
475 return 'tif';
476 case 'aif':
477 return 'aiff';
478 case 'mpeg':
479 return 'mpg';
480 default:
481 return $ext;
482 }
483 }
484
485 // Cherche dans la base le type-mime du tableau representant le document
486 // et corrige le nom du fichier ; retourne array(extension, nom corrige)
487 // s'il ne trouve pas, retourne '' et le nom inchange
488 // http://doc.spip.org/@fixer_extension_document
489 function fixer_extension_document($doc) {
490 $extension = '';
491 $name = $doc['name'];
492 if (preg_match(',\.([^.]+)$,', $name, $r)
493 AND $t = sql_fetsel("extension", "spip_types_documents",
494 "extension=" . sql_quote(corriger_extension($r[1])))) {
495 $extension = $t['extension'];
496 $name = preg_replace(',\.[^.]*$,', '', $doc['name']).'.'.$extension;
497 } else {
498 // les navigateur devraient savoir que ceci est mime-type text
499 if (strtolower($name) === 'makefile') $doc['type'] = 'txt';
500 if ($t = sql_getfetsel("extension", "spip_types_documents",
501 "mime_type=" . sql_quote($doc['type']))) {
502 $name = preg_replace(',\.[^.]*$,', '', $doc['name']).'.'.$t;
503 }
504 }
505 return array($extension,$name);
506 }
507
508 // Afficher un formulaire de choix: decompacter et/ou garder tel quel
509 // et reconstruire un generer_action_auteur.
510 // Passer ca en squelette un de ces jours.
511
512 // http://doc.spip.org/@liste_archive_jointe
513 function liste_archive_jointe($valables, $zip, $type, $id, $mode, $id_document, $hash, $redirect, $iframe_redirect)
514 {
515 include_spip('inc/layer');
516
517 $arg = (intval($id) .'/' .intval($id_document) . "/$mode/$type");
518
519 $texte = "<div style='text-align: left'>
520 <input type='hidden' name='redirect' value='$redirect' />
521 <input type='hidden' name='iframe_redirect' value='$iframe_redirect' />
522 <input type='hidden' name='hash' value='$hash' />
523 <input type='hidden' name='chemin' value='$zip' />
524 <input type='hidden' name='arg' value='$arg' />
525 <input type='radio' checked='checked' name='sousaction5' id='sousaction5_5' value='5' onchange='jQuery(\"#options_deballe_zip\").slideUp();' />" .
526 "<label for='sousaction5_5'>" . _T('upload_zip_telquel'). "</label>" .
527 "<br />".
528 "<input type='radio' name='sousaction5' id='sousaction5_6' value='6' onchange='jQuery(\"#options_deballe_zip\").slideDown();' />".
529 "<label for='sousaction5_6'>" . _T('upload_zip_decompacter') . "</label>" .
530 "<ol>" .
531 liste_archive_taille($valables) .
532 "</ol>"
533
534 . debut_block_depliable(false,'options_deballe_zip')
535 . "<input type='checkbox' name='sousaction4' id='sousaction4_4' value='4' />".
536 "<label for='sousaction4_4'>" . _T('upload_zip_conserver') . "</label>" .
537 "<br /><input type='checkbox' name='titrer' id='titrer' />"
538 . "<label for='titrer'>" . _T('upload_zip_titrer') .
539 "</label>".
540 "</div></div>"
541 . fin_block()
542
543
544 . "<div style='text-align: right;'><input type='submit' value='".
545 _T('bouton_valider').
546 "' />";
547
548 $texte = "<p>" .
549 _T('upload_fichier_zip_texte') .
550 "</p><p>" .
551 _T('upload_fichier_zip_texte2') .
552 "</p>" .
553 generer_form_action('joindre', $texte,' method="post"');
554
555 if(_request("iframe")=="iframe") {
556 return "<p>build form $iframe_redirect</p>" .
557 "<div class='upload_answer upload_zip_list'>" .
558 $texte .
559 "</div>";
560 } else { return minipres(_T('upload_fichier_zip'), $texte); }
561 }
562
563 // http://doc.spip.org/@liste_archive_taille
564 function liste_archive_taille($files) {
565 $res = '';
566 foreach ($files as $nom => $file) {
567 $date = date_interface(date("Y-m-d H:i:s", $file['mtime']));
568
569 $taille = taille_en_octets($file['size']);
570 $res .= "<li title=\"".texte_backend($title)."\"><b>$nom</b> &ndash; $taille<br />&nbsp; $date</li>\n";
571 }
572 return $res;
573 }
574 ?>