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