joindre_document.php 10 KB

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