/htdocs/core/lib/files.lib.php

https://github.com/asterix14/dolibarr · PHP · 1040 lines · 677 code · 105 blank · 258 comment · 227 complexity · 20379755f6c4f3c26949425df5c13ae6 MD5 · raw file

  1. <?php
  2. /* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. * or see http://www.gnu.org/
  17. */
  18. /**
  19. * \file htdocs/core/lib/files.lib.php
  20. * \brief Library for file managing functions
  21. */
  22. /**
  23. * Return user/group account of web server
  24. *
  25. * @param string $mode 'user' or 'group'
  26. * @return string Return user or group of web server
  27. */
  28. function dol_getwebuser($mode)
  29. {
  30. $t='?';
  31. if ($mode=='user') $t=getenv('APACHE_RUN_USER'); // $_ENV['APACHE_RUN_USER'] is empty
  32. if ($mode=='group') $t=getenv('APACHE_RUN_GROUP');
  33. return $t;
  34. }
  35. /**
  36. * Scan a directory and return a list of files/directories.
  37. * Content for string is UTF8 and dir separator is "/".
  38. *
  39. * @param string $path Starting path from which to search
  40. * @param string $types Can be "directories", "files", or "all"
  41. * @param int $recursive Determines whether subdirectories are searched
  42. * @param string $filter Regex for include filter
  43. * @param string $excludefilter Array of Regex for exclude filter (example: array('\.meta$','^\.')
  44. * @param string $sortcriteria Sort criteria ("","name","date","size")
  45. * @param string $sortorder Sort order (SORT_ASC, SORT_DESC)
  46. * @param int $mode 0=Return array minimum keys loaded (faster), 1=Force all keys like date and size to be loaded (slower), 2=Force load of date only, 3=Force load of size only
  47. * @return array Array of array('name'=>'xxx','fullname'=>'/abc/xxx','date'=>'yyy','size'=>99,'type'=>'dir|file')
  48. */
  49. function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter="", $sortcriteria="name", $sortorder=SORT_ASC, $mode=0)
  50. {
  51. dol_syslog("files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".$excludefilter);
  52. $loaddate=($mode==1||$mode==2)?true:false;
  53. $loadsize=($mode==1||$mode==3)?true:false;
  54. // Clean parameters
  55. $path=preg_replace('/([\\/]+)$/i','',$path);
  56. $newpath=dol_osencode($path);
  57. if (! is_dir($newpath)) return array();
  58. if ($dir = opendir($newpath))
  59. {
  60. $file_list = array();
  61. while (false !== ($file = readdir($dir)))
  62. {
  63. if (! utf8_check($file)) $file=utf8_encode($file); // To be sure data is stored in utf8 in memory
  64. $qualified=1;
  65. // Define excludefilterarray
  66. $excludefilterarray=array('^\.');
  67. if (is_array($excludefilter))
  68. {
  69. $excludefilterarray=array_merge($excludefilterarray,$excludefilter);
  70. }
  71. else if ($excludefilter) $excludefilterarray[]=$excludefilter;
  72. // Check if file is qualified
  73. foreach($excludefilterarray as $filt)
  74. {
  75. if (preg_match('/'.$filt.'/i',$file)) { $qualified=0; break; }
  76. }
  77. if ($qualified)
  78. {
  79. $isdir=is_dir(dol_osencode($path."/".$file));
  80. // Check whether this is a file or directory and whether we're interested in that type
  81. if ($isdir && (($types=="directories") || ($types=="all") || $recursive))
  82. {
  83. // Add entry into file_list array
  84. if (($types=="directories") || ($types=="all"))
  85. {
  86. if ($loaddate || $sortcriteria == 'date') $filedate=dol_filemtime($path."/".$file);
  87. if ($loadsize || $sortcriteria == 'size') $filesize=dol_filesize($path."/".$file);
  88. if (! $filter || preg_match('/'.$filter.'/i',$path.'/'.$file))
  89. {
  90. $file_list[] = array(
  91. "name" => $file,
  92. "fullname" => $path.'/'.$file,
  93. "date" => $filedate,
  94. "size" => $filesize,
  95. "type" => 'dir'
  96. );
  97. }
  98. }
  99. // if we're in a directory and we want recursive behavior, call this function again
  100. if ($recursive)
  101. {
  102. $file_list = array_merge($file_list,dol_dir_list($path."/".$file, $types, $recursive, $filter, $excludefilter, $sortcriteria, $sortorder, $mode));
  103. }
  104. }
  105. else if (! $isdir && (($types == "files") || ($types == "all")))
  106. {
  107. // Add file into file_list array
  108. if ($loaddate || $sortcriteria == 'date') $filedate=dol_filemtime($path."/".$file);
  109. if ($loadsize || $sortcriteria == 'size') $filesize=dol_filesize($path."/".$file);
  110. if (! $filter || preg_match('/'.$filter.'/i',$path.'/'.$file))
  111. {
  112. $file_list[] = array(
  113. "name" => $file,
  114. "fullname" => $path.'/'.$file,
  115. "date" => $filedate,
  116. "size" => $filesize,
  117. "type" => 'file'
  118. );
  119. }
  120. }
  121. }
  122. }
  123. closedir($dir);
  124. // Obtain a list of columns
  125. $myarray=array();
  126. foreach ($file_list as $key => $row)
  127. {
  128. $myarray[$key] = $row[$sortcriteria];
  129. }
  130. // Sort the data
  131. if ($sortorder) array_multisort($myarray, $sortorder, $file_list);
  132. return $file_list;
  133. }
  134. else
  135. {
  136. return array();
  137. }
  138. }
  139. /**
  140. * Fast compare of 2 files identified by their properties ->name, ->date and ->size
  141. *
  142. * @param string $a File 1
  143. * @param string $b File 2
  144. * @return int 1, 0, 1
  145. */
  146. function dol_compare_file($a, $b)
  147. {
  148. global $sortorder;
  149. global $sortfield;
  150. $sortorder=strtoupper($sortorder);
  151. if ($sortorder == 'ASC') { $retup=-1; $retdown=1; }
  152. else { $retup=1; $retdown=-1; }
  153. if ($sortfield == 'name')
  154. {
  155. if ($a->name == $b->name) return 0;
  156. return ($a->name < $b->name) ? $retup : $retdown;
  157. }
  158. if ($sortfield == 'date')
  159. {
  160. if ($a->date == $b->date) return 0;
  161. return ($a->date < $b->date) ? $retup : $retdown;
  162. }
  163. if ($sortfield == 'size')
  164. {
  165. if ($a->size == $b->size) return 0;
  166. return ($a->size < $b->size) ? $retup : $retdown;
  167. }
  168. }
  169. /**
  170. * Return mime type of a file
  171. *
  172. * @param string $file Filename we looking for MIME type
  173. * @param string $default Default mime type if extension not found in known list
  174. * @param int $mode 0=Return full mime, 1=otherwise short mime string, 2=image for mime type, 3=source language
  175. * @return string Return a mime type family (text/xxx, application/xxx, image/xxx, audio, video, archive)
  176. * @see image_format_supported (images.lib.php)
  177. */
  178. function dol_mimetype($file,$default='application/octet-stream',$mode=0)
  179. {
  180. $mime=$default;
  181. $imgmime='other.png';
  182. $srclang='';
  183. $tmpfile=preg_replace('/\.noexe$/','',$file);
  184. // Text files
  185. if (preg_match('/\.txt$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; }
  186. if (preg_match('/\.rtx$/i',$tmpfile)) { $mime='text/richtext'; $imgmime='text.png'; }
  187. if (preg_match('/\.csv$/i',$tmpfile)) { $mime='text/csv'; $imgmime='text.png'; }
  188. if (preg_match('/\.tsv$/i',$tmpfile)) { $mime='text/tab-separated-values'; $imgmime='text.png'; }
  189. if (preg_match('/\.(cf|conf|log)$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; }
  190. if (preg_match('/\.ini$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; $srclang='ini'; }
  191. if (preg_match('/\.css$/i',$tmpfile)) { $mime='text/css'; $imgmime='css.png'; $srclang='css'; }
  192. // Certificate files
  193. if (preg_match('/\.(crt|cer|key|pub)$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; }
  194. // HTML/XML
  195. if (preg_match('/\.(html|htm|shtml)$/i',$tmpfile)) { $mime='text/html'; $imgmime='html.png'; $srclang='html'; }
  196. if (preg_match('/\.(xml|xhtml)$/i',$tmpfile)) { $mime='text/xml'; $imgmime='other.png'; $srclang='xml'; }
  197. // Languages
  198. if (preg_match('/\.bas$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; $srclang='bas'; }
  199. if (preg_match('/\.(c)$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; $srclang='c'; }
  200. if (preg_match('/\.(cpp)$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; $srclang='cpp'; }
  201. if (preg_match('/\.(h)$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; $srclang='h'; }
  202. if (preg_match('/\.(java|jsp)$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; $srclang='java'; }
  203. if (preg_match('/\.php([0-9]{1})?$/i',$tmpfile)) { $mime='text/plain'; $imgmime='php.png'; $srclang='php'; }
  204. if (preg_match('/\.(pl|pm)$/i',$tmpfile)) { $mime='text/plain'; $imgmime='pl.png'; $srclang='perl'; }
  205. if (preg_match('/\.sql$/i',$tmpfile)) { $mime='text/plain'; $imgmime='text.png'; $srclang='sql'; }
  206. if (preg_match('/\.js$/i',$tmpfile)) { $mime='text/x-javascript'; $imgmime='jscript.png'; $srclang='js'; }
  207. // Open office
  208. if (preg_match('/\.odp$/i',$tmpfile)) { $mime='application/vnd.oasis.opendocument.presentation'; $imgmime='ooffice.png'; }
  209. if (preg_match('/\.ods$/i',$tmpfile)) { $mime='application/vnd.oasis.opendocument.spreadsheet'; $imgmime='ooffice.png'; }
  210. if (preg_match('/\.odt$/i',$tmpfile)) { $mime='application/vnd.oasis.opendocument.text'; $imgmime='ooffice.png'; }
  211. // MS Office
  212. if (preg_match('/\.mdb$/i',$tmpfile)) { $mime='application/msaccess'; $imgmime='mdb.png'; }
  213. if (preg_match('/\.doc(x|m)?$/i',$tmpfile)) { $mime='application/msword'; $imgmime='doc.png'; }
  214. if (preg_match('/\.dot(x|m)?$/i',$tmpfile)) { $mime='application/msword'; $imgmime='doc.png'; }
  215. if (preg_match('/\.xls(b|m|x)?$/i',$tmpfile)) { $mime='application/vnd.ms-excel'; $imgmime='xls.png'; }
  216. if (preg_match('/\.xlt(x)?$/i',$tmpfile)) { $mime='application/vnd.ms-excel'; $imgmime='xls.png'; }
  217. if (preg_match('/\.xla(m)?$/i',$tmpfile)) { $mime='application/vnd.ms-excel'; $imgmime='xls.png'; }
  218. if (preg_match('/\.xsl(b|m|x)?$/i',$tmpfile)) { $mime='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; $imgmime='xls.png'; }
  219. if (preg_match('/\.pps(m|x)?$/i',$tmpfile)) { $mime='application/vnd.ms-powerpoint'; $imgmime='ppt.png'; }
  220. if (preg_match('/\.ppt(m|x)?$/i',$tmpfile)) { $mime='application/x-mspowerpoint'; $imgmime='ppt.png'; }
  221. // Other
  222. if (preg_match('/\.pdf$/i',$tmpfile)) { $mime='application/pdf'; $imgmime='pdf.png'; }
  223. // Scripts
  224. if (preg_match('/\.bat$/i',$tmpfile)) { $mime='text/x-bat'; $imgmime='script.png'; $srclang='dos'; }
  225. if (preg_match('/\.sh$/i',$tmpfile)) { $mime='text/x-sh'; $imgmime='script.png'; $srclang='bash'; }
  226. if (preg_match('/\.ksh$/i',$tmpfile)) { $mime='text/x-ksh'; $imgmime='script.png'; $srclang='bash'; }
  227. if (preg_match('/\.bash$/i',$tmpfile)) { $mime='text/x-bash'; $imgmime='script.png'; $srclang='bash'; }
  228. // Images
  229. if (preg_match('/\.ico$/i',$tmpfile)) { $mime='image/x-icon'; $imgmime='image.png'; }
  230. if (preg_match('/\.(jpg|jpeg)$/i',$tmpfile)) { $mime='image/jpeg'; $imgmime='image.png'; }
  231. if (preg_match('/\.png$/i',$tmpfile)) { $mime='image/png'; $imgmime='image.png'; }
  232. if (preg_match('/\.gif$/i',$tmpfile)) { $mime='image/gif'; $imgmime='image.png'; }
  233. if (preg_match('/\.bmp$/i',$tmpfile)) { $mime='image/bmp'; $imgmime='image.png'; }
  234. if (preg_match('/\.(tif|tiff)$/i',$tmpfile)) { $mime='image/tiff'; $imgmime='image.png'; }
  235. // Calendar
  236. if (preg_match('/\.vcs$/i',$tmpfile)) { $mime='text/calendar'; $imgmime='other.png'; }
  237. if (preg_match('/\.ics$/i',$tmpfile)) { $mime='text/calendar'; $imgmime='other.png'; }
  238. // Other
  239. if (preg_match('/\.torrent$/i',$tmpfile)) { $mime='application/x-bittorrent'; $imgmime='other.png'; }
  240. // Audio
  241. if (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i',$tmpfile)) { $mime='audio'; $imgmime='audio.png'; }
  242. // Video
  243. if (preg_match('/\.ogv$/i',$tmpfile)) { $mime='video/ogg'; $imgmime='video.png'; }
  244. if (preg_match('/\.webm$/i',$tmpfile)) { $mime='video/webm'; $imgmime='video.png'; }
  245. if (preg_match('/\.avi$/i',$tmpfile)) { $mime='video/x-msvideo'; $imgmime='video.png'; }
  246. if (preg_match('/\.divx$/i',$tmpfile)) { $mime='video/divx'; $imgmime='video.png'; }
  247. if (preg_match('/\.xvid$/i',$tmpfile)) { $mime='video/xvid'; $imgmime='video.png'; }
  248. if (preg_match('/\.(wmv|mpg|mpeg)$/i',$tmpfile)) { $mime='video'; $imgmime='video.png'; }
  249. // Archive
  250. if (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh)$/i',$tmpfile)) { $mime='archive'; $imgmime='archive.png'; } // application/xxx where zzz is zip, ...
  251. // Exe
  252. if (preg_match('/\.(exe|com)$/i',$tmpfile)) { $mime='application/octet-stream'; $imgmime='other.png'; }
  253. // Lib
  254. if (preg_match('/\.(dll|lib|o|so|a)$/i',$tmpfile)) { $mime='library'; $imgmime='library.png'; }
  255. // Err
  256. if (preg_match('/\.err$/i',$tmpfile)) { $mime='error'; $imgmime='error.png'; }
  257. // Return string
  258. if ($mode == 1)
  259. {
  260. $tmp=explode('/',$mime);
  261. return $tmp[1];
  262. }
  263. if ($mode == 2)
  264. {
  265. return $imgmime;
  266. }
  267. if ($mode == 3)
  268. {
  269. return $srclang;
  270. }
  271. return $mime;
  272. }
  273. /**
  274. * Test if filename is a directory
  275. *
  276. * @param string $folder Name of folder
  277. * @return boolean True if it's a directory, False if not found
  278. */
  279. function dol_is_dir($folder)
  280. {
  281. $newfolder=dol_osencode($folder);
  282. if (is_dir($newfolder)) return true;
  283. else return false;
  284. }
  285. /**
  286. * Return if path is a file
  287. *
  288. * @param string $pathoffile Path of file
  289. * @return boolean True or false
  290. */
  291. function dol_is_file($pathoffile)
  292. {
  293. $newpathoffile=dol_osencode($pathoffile);
  294. return is_file($newpathoffile);
  295. }
  296. /**
  297. * Return if path is an URL
  298. *
  299. * @param string $url Url
  300. * @return boolean True or false
  301. */
  302. function dol_is_url($url)
  303. {
  304. $tmpprot=array('file','http','ftp','zlib','data','ssh2','ogg','expect');
  305. foreach($tmpprot as $prot)
  306. {
  307. if (preg_match('/^'.$prot.':/i',$url)) return true;
  308. }
  309. return false;
  310. }
  311. /**
  312. * Test if a folder is empty
  313. *
  314. * @param string $folder Name of folder
  315. * @return boolean True if dir is empty or non-existing, False if it contains files
  316. */
  317. function dol_dir_is_emtpy($folder)
  318. {
  319. $newfolder=dol_osencode($folder);
  320. if (is_dir($newfolder))
  321. {
  322. $handle = opendir($newfolder);
  323. while ((gettype( $name = readdir($handle)) != "boolean"))
  324. {
  325. $name_array[] = $name;
  326. }
  327. foreach($name_array as $temp) $folder_content .= $temp;
  328. if ($folder_content == "...") return true;
  329. else return false;
  330. closedir($handle);
  331. }
  332. else
  333. return true; // Dir does not exists
  334. }
  335. /**
  336. * Count number of lines in a file
  337. *
  338. * @param string $file Filename
  339. * @return int <0 if KO, Number of lines in files if OK
  340. */
  341. function dol_count_nb_of_line($file)
  342. {
  343. $nb=0;
  344. $newfile=dol_osencode($file);
  345. //print 'x'.$file;
  346. $fp=fopen($newfile,'r');
  347. if ($fp)
  348. {
  349. while (!feof($fp))
  350. {
  351. $line=fgets($fp);
  352. $nb++;
  353. }
  354. fclose($fp);
  355. }
  356. else
  357. {
  358. $nb=-1;
  359. }
  360. return $nb;
  361. }
  362. /**
  363. * Return size of a file
  364. *
  365. * @param tring $pathoffile Path of file
  366. * @return string File size
  367. */
  368. function dol_filesize($pathoffile)
  369. {
  370. $newpathoffile=dol_osencode($pathoffile);
  371. return filesize($newpathoffile);
  372. }
  373. /**
  374. * Return time of a file
  375. *
  376. * @param string $pathoffile Path of file
  377. * @return timestamp Time of file
  378. */
  379. function dol_filemtime($pathoffile)
  380. {
  381. $newpathoffile=dol_osencode($pathoffile);
  382. return @filemtime($newpathoffile); // @Is to avoid errors if files does not exists
  383. }
  384. /**
  385. * Copy a file to another file
  386. * @param $srcfile Source file (can't be a directory)
  387. * @param $destfile Destination file (can't be a directory)
  388. * @param $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK)
  389. * @param $overwriteifexists Overwrite file if exists (1 by default)
  390. * @return boolean True if OK, false if KO
  391. */
  392. function dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1)
  393. {
  394. global $conf;
  395. $result=false;
  396. dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
  397. if ($overwriteifexists || ! dol_is_file($destfile))
  398. {
  399. $newpathofsrcfile=dol_osencode($srcfile);
  400. $newpathofdestfile=dol_osencode($destfile);
  401. $result=@copy($newpathofsrcfile, $newpathofdestfile);
  402. //$result=copy($srcfile, $destfile); // To see errors, remove @
  403. if (! $result) dol_syslog("files.lib.php::dol_copy failed", LOG_WARNING);
  404. if (empty($newmask) && ! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK;
  405. @chmod($newpathofdestfile, octdec($newmask));
  406. }
  407. return $result;
  408. }
  409. /**
  410. * Move a file into another name
  411. *
  412. * @param string $srcfile Source file (can't be a directory)
  413. * @param string $destfile Destination file (can't be a directory)
  414. * @param string $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK)
  415. * @param int $overwriteifexists Overwrite file if exists (1 by default)
  416. * @return boolean True if OK, false if KO
  417. */
  418. function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1)
  419. {
  420. global $conf;
  421. $result=false;
  422. dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
  423. if ($overwriteifexists || ! dol_is_file($destfile))
  424. {
  425. $newpathofsrcfile=dol_osencode($srcfile);
  426. $newpathofdestfile=dol_osencode($destfile);
  427. $result=@rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
  428. if (! $result) dol_syslog("files.lib.php::dol_move failed", LOG_WARNING);
  429. if (empty($newmask) && ! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK;
  430. @chmod($newpathofsrcfile, octdec($newmask));
  431. }
  432. return $result;
  433. }
  434. /**
  435. * Move an uploaded file after some controls.
  436. * If there is errors (virus found, antivir in error, bad filename), file is not moved.
  437. *
  438. * @param string $src_file Source full path filename ($_FILES['field']['tmp_name'])
  439. * @param string $dest_file Target full path filename
  440. * @param int $allowoverwrite 1=Overwrite target file if it already exists
  441. * @param int $disablevirusscan 1=Disable virus scan
  442. * @param string $uploaderrorcode Value of upload error code ($_FILES['field']['error'])
  443. * @param int $notrigger Disable all triggers
  444. * @return int >0 if OK, <0 or string if KO
  445. */
  446. function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $notrigger=0)
  447. {
  448. global $conf, $user, $langs, $db;
  449. global $object;
  450. $file_name = $dest_file;
  451. // If an upload error has been reported
  452. if ($uploaderrorcode)
  453. {
  454. switch($uploaderrorcode)
  455. {
  456. case UPLOAD_ERR_INI_SIZE: // 1
  457. return 'ErrorFileSizeTooLarge';
  458. break;
  459. case UPLOAD_ERR_FORM_SIZE: // 2
  460. return 'ErrorFileSizeTooLarge';
  461. break;
  462. case UPLOAD_ERR_PARTIAL: // 3
  463. return 'ErrorPartialFile';
  464. break;
  465. case UPLOAD_ERR_NO_TMP_DIR: //
  466. return 'ErrorNoTmpDir';
  467. break;
  468. case UPLOAD_ERR_CANT_WRITE:
  469. return 'ErrorFailedToWriteInDir';
  470. break;
  471. case UPLOAD_ERR_EXTENSION:
  472. return 'ErrorUploadBlockedByAddon';
  473. break;
  474. default:
  475. break;
  476. }
  477. }
  478. // If we need to make a virus scan
  479. if (empty($disablevirusscan) && file_exists($src_file) && ! empty($conf->global->MAIN_ANTIVIRUS_COMMAND))
  480. {
  481. require_once(DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php');
  482. $antivir=new AntiVir($db);
  483. $result = $antivir->dol_avscan_file($src_file);
  484. if ($result < 0) // If virus or error, we stop here
  485. {
  486. $reterrors=$antivir->errors;
  487. dol_syslog('Functions.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$file_name.'") KO with antivirus: result='.$result.' errors='.join(',',$antivir->errors), LOG_WARNING);
  488. return 'ErrorFileIsInfectedWithAVirus: '.join(',',$reterrors);
  489. }
  490. }
  491. // Security:
  492. // Disallow file with some extensions. We renamed them.
  493. // Car si on a mis le rep documents dans un rep de la racine web (pas bien), cela permet d'executer du code a la demande.
  494. if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$file_name))
  495. {
  496. $file_name.= '.noexe';
  497. }
  498. // Security:
  499. // On interdit fichiers caches, remontees de repertoire ainsi que les pipes dans les noms de fichiers.
  500. if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file))
  501. {
  502. dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
  503. return -1;
  504. }
  505. // Security:
  506. // On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans
  507. // les noms de fichiers.
  508. if (preg_match('/^\./',$dest_file) || preg_match('/\.\./',$dest_file) || preg_match('/[<>|]/',$dest_file))
  509. {
  510. dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
  511. return -2;
  512. }
  513. // The file functions must be in OS filesystem encoding.
  514. $src_file_osencoded=dol_osencode($src_file);
  515. $file_name_osencoded=dol_osencode($file_name);
  516. // Check if destination dir is writable
  517. // TODO
  518. // Check if destination file already exists
  519. if (! $allowoverwrite)
  520. {
  521. if (file_exists($file_name_osencoded))
  522. {
  523. dol_syslog("Functions.lib::dol_move_uploaded_file File ".$file_name." already exists", LOG_WARNING);
  524. return 'ErrorFileAlreadyExists';
  525. }
  526. }
  527. // Move file
  528. $return=move_uploaded_file($src_file_osencoded, $file_name_osencoded);
  529. if ($return)
  530. {
  531. if (! empty($conf->global->MAIN_UMASK)) @chmod($file_name_osencoded, octdec($conf->global->MAIN_UMASK));
  532. dol_syslog("Functions.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG);
  533. if (! $notrigger && is_object($object))
  534. {
  535. $object->src_file=$dest_file;
  536. // Appel des triggers
  537. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  538. $interface=new Interfaces($db);
  539. $result=$interface->run_triggers('FILE_UPLOAD',$object,$user,$langs,$conf);
  540. if ($result < 0) { $error++; $errors=$interface->errors; }
  541. // Fin appel triggers
  542. }
  543. return 1; // Success
  544. }
  545. else
  546. {
  547. dol_syslog("Functions.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
  548. return -3; // Unknown error
  549. }
  550. return 1;
  551. }
  552. /**
  553. * Remove a file or several files with a mask
  554. *
  555. * @param string $file File to delete or mask of file to delete
  556. * @param int $disableglob Disable usage of glob like *
  557. * @param int $nophperrors Disable all PHP output errors
  558. * @param int $notrigger Disable all triggers
  559. * @param Object $object Object
  560. * @return boolean True if file is deleted, False if error
  561. */
  562. function dol_delete_file($file,$disableglob=0,$nophperrors=0,$notrigger=0,$object=null)
  563. {
  564. global $db, $conf, $user, $langs;
  565. //print "x".$file." ".$disableglob;
  566. $ok=true;
  567. $file_osencoded=dol_osencode($file); // New filename encoded in OS filesystem encoding charset
  568. if (empty($disableglob))
  569. {
  570. foreach (glob($file_osencoded) as $filename)
  571. {
  572. if ($nophperrors) $ok=@unlink($filename); // The unlink encapsulated by dolibarr
  573. else $ok=unlink($filename); // The unlink encapsulated by dolibarr
  574. if ($ok)
  575. {
  576. dol_syslog("Removed file ".$filename,LOG_DEBUG);
  577. if (! $notrigger)
  578. {
  579. if (! is_object($object)) $object=(object) 'dummy';
  580. $object->src_file=$file;
  581. // TODO Replace trigger by a hook. Triggers must be used for business events only.
  582. // Appel des triggers
  583. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  584. $interface=new Interfaces($db);
  585. $result=$interface->run_triggers('FILE_DELETE',$object,$user,$langs,$conf);
  586. if ($result < 0) { $error++; $errors=$interface->errors; }
  587. // Fin appel triggers
  588. }
  589. }
  590. else dol_syslog("Failed to remove file ".$filename,LOG_WARNING);
  591. }
  592. }
  593. else
  594. {
  595. if ($nophperrors) $ok=@unlink($file_osencoded); // The unlink encapsulated by dolibarr
  596. else $ok=unlink($file_osencoded); // The unlink encapsulated by dolibarr
  597. if ($ok) dol_syslog("Removed file ".$file_osencoded,LOG_DEBUG);
  598. else dol_syslog("Failed to remove file ".$file_osencoded,LOG_WARNING);
  599. }
  600. return $ok;
  601. }
  602. /**
  603. * Remove a directory (not recursive, so content must be empty).
  604. * If directory is not empty, return false
  605. *
  606. * @param string $dir Directory to delete
  607. * @param int $nophperrors Disable all PHP output errors
  608. * @return boolean True if success, false if error
  609. */
  610. function dol_delete_dir($dir,$nophperrors=0)
  611. {
  612. $dir_osencoded=dol_osencode($dir);
  613. return ($nophperrors?@rmdir($dir_osencoded):rmdir($dir_osencoded));
  614. }
  615. /**
  616. * Remove a directory $dir and its subdirectories
  617. * @param dir Dir to delete
  618. * @param count Counter to count nb of deleted elements
  619. * @param nophperrors Disable all PHP output errors
  620. * @return int Number of files and directory removed
  621. */
  622. function dol_delete_dir_recursive($dir,$count=0,$nophperrors=0)
  623. {
  624. dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir,LOG_DEBUG);
  625. if (dol_is_dir($dir))
  626. {
  627. $dir_osencoded=dol_osencode($dir);
  628. if ($handle = opendir("$dir_osencoded"))
  629. {
  630. while (false !== ($item = readdir($handle)))
  631. {
  632. if (! utf8_check($item)) $item=utf8_encode($item); // should be useless
  633. if ($item != "." && $item != "..")
  634. {
  635. if (is_dir(dol_osencode("$dir/$item")))
  636. {
  637. $count=dol_delete_dir_recursive("$dir/$item",$count,$nophperrors);
  638. }
  639. else
  640. {
  641. dol_delete_file("$dir/$item",1,$nophperrors);
  642. $count++;
  643. //echo " removing $dir/$item<br>\n";
  644. }
  645. }
  646. }
  647. closedir($handle);
  648. dol_delete_dir($dir,$nophperrors);
  649. $count++;
  650. //echo "removing $dir<br>\n";
  651. }
  652. }
  653. //echo "return=".$count;
  654. return $count;
  655. }
  656. /**
  657. * Delete all preview files linked to object instance
  658. *
  659. * @param Object $object Object to clean
  660. * @return int 0 if error, 1 if OK
  661. */
  662. function dol_delete_preview($object)
  663. {
  664. global $langs,$conf;
  665. require_once(DOL_DOCUMENT_ROOT."/core/lib/files.lib.php");
  666. if ($object->element == 'commande') $dir = $conf->commande->dir_output;
  667. elseif ($object->element == 'propal') $dir = $conf->propale->dir_output;
  668. elseif ($object->element == 'ficheinter') $dir = $conf->ficheinter->dir_output;
  669. elseif ($object->element == 'order_supplier') $dir = $conf->fournisseur->dir_output.'/commande';
  670. elseif ($object->element == 'invoice_supplier') $dir = $conf->fournisseur->dir_output.'/facture';
  671. elseif ($object->element == 'project') $dir = $conf->projet->dir_output;
  672. elseif ($object->element == 'delivery') $dir = $conf->livraison->dir_output;
  673. elseif ($object->element == 'facture') $dir = $conf->facture->dir_output;
  674. elseif ($object->element == 'don') $dir = $conf->don->dir_output;
  675. if (empty($dir)) return 'ErrorObjectNoSupportedByFunction';
  676. $refsan = dol_sanitizeFileName($object->ref);
  677. $dir = $dir . "/" . $refsan ;
  678. $file = $dir . "/" . $refsan . ".pdf.png";
  679. $multiple = $file . ".";
  680. if (file_exists($file) && is_writable($file))
  681. {
  682. if ( ! dol_delete_file($file,1) )
  683. {
  684. $this->error=$langs->trans("ErrorFailedToOpenFile",$file);
  685. return 0;
  686. }
  687. }
  688. else
  689. {
  690. for ($i = 0; $i < 20; $i++)
  691. {
  692. $preview = $multiple.$i;
  693. if (file_exists($preview) && is_writable($preview))
  694. {
  695. if ( ! dol_delete_file($preview,1) )
  696. {
  697. $this->error=$langs->trans("ErrorFailedToOpenFile",$preview);
  698. return 0;
  699. }
  700. }
  701. }
  702. }
  703. return 1;
  704. }
  705. /**
  706. * Create a meta file with document file into same directory.
  707. * This should allow rgrep search
  708. *
  709. * @param Object $object Object
  710. * @return void
  711. */
  712. function dol_meta_create($object)
  713. {
  714. global $langs,$conf;
  715. $object->fetch_thirdparty();
  716. if ($conf->facture->dir_output)
  717. {
  718. $facref = dol_sanitizeFileName($object->ref);
  719. $dir = $conf->facture->dir_output . "/" . $facref;
  720. $file = $dir . "/" . $facref . ".meta";
  721. if (! is_dir($dir))
  722. {
  723. create_exdir($dir);
  724. }
  725. if (is_dir($dir))
  726. {
  727. $nblignes = count($object->lines);
  728. $client = $object->client->nom . " " . $object->client->address . " " . $object->client->cp . " " . $object->client->ville;
  729. $meta = "REFERENCE=\"" . $object->ref . "\"
  730. DATE=\"" . dol_print_date($object->date,'') . "\"
  731. NB_ITEMS=\"" . $nblignes . "\"
  732. CLIENT=\"" . $client . "\"
  733. TOTAL_HT=\"" . $object->total_ht . "\"
  734. TOTAL_TTC=\"" . $object->total_ttc . "\"\n";
  735. for ($i = 0 ; $i < $nblignes ; $i++)
  736. {
  737. //Pour les articles
  738. $meta .= "ITEM_" . $i . "_QUANTITY=\"" . $object->lines[$i]->qty . "\"
  739. ITEM_" . $i . "_UNIT_PRICE=\"" . $object->lines[$i]->price . "\"
  740. ITEM_" . $i . "_TVA=\"" .$object->lines[$i]->tva_tx . "\"
  741. ITEM_" . $i . "_DESCRIPTION=\"" . str_replace("\r\n","",nl2br($object->lines[$i]->desc)) . "\"
  742. ";
  743. }
  744. }
  745. $fp = fopen($file,"w");
  746. fputs($fp,$meta);
  747. fclose($fp);
  748. if (! empty($conf->global->MAIN_UMASK))
  749. @chmod($file, octdec($conf->global->MAIN_UMASK));
  750. }
  751. }
  752. /**
  753. * Init $_SESSION with uploaded files
  754. *
  755. * @param string $pathtoscan Path to scan
  756. * @return void
  757. */
  758. function dol_init_file_process($pathtoscan='')
  759. {
  760. $listofpaths=array();
  761. $listofnames=array();
  762. $listofmimes=array();
  763. if ($pathtoscan)
  764. {
  765. $listoffiles=dol_dir_list($pathtoscan,'files');
  766. foreach($listoffiles as $key => $val)
  767. {
  768. $listofpaths[]=$val['fullname'];
  769. $listofnames[]=$val['name'];
  770. $listofmimes[]=dol_mimetype($val['name']);
  771. }
  772. }
  773. $_SESSION["listofpaths"]=join(';',$listofpaths);
  774. $_SESSION["listofnames"]=join(';',$listofnames);
  775. $_SESSION["listofmimes"]=join(';',$listofmimes);
  776. }
  777. /**
  778. * Get and save an upload file (for example after submitting a new file a mail form).
  779. * All information used are in db, conf, langs, user and _FILES.
  780. *
  781. * @param string $upload_dir Directory to store upload files
  782. * @param int $allowoverwrite 1=Allow overwrite existing file
  783. * @param int $donotupdatesession 1=Do no edit _SESSION variable
  784. * @return string Message with result of upload and store.
  785. */
  786. function dol_add_file_process($upload_dir,$allowoverwrite=0,$donotupdatesession=0)
  787. {
  788. global $db,$user,$conf,$langs,$_FILES;
  789. $mesg='';
  790. if (! empty($_FILES['addedfile']['tmp_name']))
  791. {
  792. if (dol_mkdir($upload_dir) >= 0)
  793. {
  794. $resupload = dol_move_uploaded_file($_FILES['addedfile']['tmp_name'], $upload_dir . "/" . $_FILES['addedfile']['name'],$allowoverwrite,0, $_FILES['addedfile']['error']);
  795. if (is_numeric($resupload) && $resupload > 0)
  796. {
  797. $mesg = '<div class="ok">'.$langs->trans("FileTransferComplete").'</div>';
  798. if (empty($donotupdatesession))
  799. {
  800. include_once(DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php');
  801. $formmail = new FormMail($db);
  802. $formmail->add_attached_files($upload_dir . "/" . $_FILES['addedfile']['name'],$_FILES['addedfile']['name'],$_FILES['addedfile']['type']);
  803. }
  804. }
  805. else
  806. {
  807. $langs->load("errors");
  808. if ($resupload < 0) // Unknown error
  809. {
  810. $mesg = '<div class="error">'.$langs->trans("ErrorFileNotUploaded").'</div>';
  811. }
  812. else if (preg_match('/ErrorFileIsInfectedWithAVirus/',$resupload)) // Files infected by a virus
  813. {
  814. $mesg = '<div class="error">'.$langs->trans("ErrorFileIsInfectedWithAVirus").'</div>';
  815. }
  816. else // Known error
  817. {
  818. $mesg = '<div class="error">'.$langs->trans($resupload).'</div>';
  819. }
  820. }
  821. }
  822. }
  823. else
  824. {
  825. $langs->load("errors");
  826. $mesg = '<div class="warning">'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("File")).'</div>';
  827. }
  828. return $mesg;
  829. }
  830. /**
  831. * Remove an uploaded file (for example after submitting a new file a mail form).
  832. * All information used are in db, conf, langs, user and _FILES.
  833. *
  834. * @param int $filenb File nb to delete
  835. * @param int $donotupdatesession 1=Do not edit _SESSION variable
  836. * @param int $donotdeletefile 1=Do not delete physically file
  837. * @return string Message with result of upload and store.
  838. */
  839. function dol_remove_file_process($filenb,$donotupdatesession=0,$donotdeletefile=0)
  840. {
  841. global $db,$user,$conf,$langs,$_FILES;
  842. $mesg='';
  843. $keytodelete=$filenb;
  844. $keytodelete--;
  845. $listofpaths=array();
  846. $listofnames=array();
  847. $listofmimes=array();
  848. if (! empty($_SESSION["listofpaths"])) $listofpaths=explode(';',$_SESSION["listofpaths"]);
  849. if (! empty($_SESSION["listofnames"])) $listofnames=explode(';',$_SESSION["listofnames"]);
  850. if (! empty($_SESSION["listofmimes"])) $listofmimes=explode(';',$_SESSION["listofmimes"]);
  851. if ($keytodelete >= 0)
  852. {
  853. $pathtodelete=$listofpaths[$keytodelete];
  854. $filetodelete=$listofnames[$keytodelete];
  855. if (empty($donotdeletefile)) $result = dol_delete_file($pathtodelete,1);
  856. else $result=0;
  857. if ($result >= 0)
  858. {
  859. if (empty($donotdeletefile))
  860. {
  861. $langs->load("other");
  862. $mesg = '<div class="ok">'.$langs->trans("FileWasRemoved",$filetodelete).'</div>';
  863. //print_r($_FILES);
  864. }
  865. if (empty($donotupdatesession))
  866. {
  867. include_once(DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php');
  868. $formmail = new FormMail($db);
  869. $formmail->remove_attached_files($keytodelete);
  870. }
  871. }
  872. }
  873. return $mesg;
  874. }
  875. /**
  876. * Convert an image file into antoher format.
  877. * This need Imagick php extension.
  878. *
  879. * @param string $file Input file name
  880. * @param string $ext Extension of target file
  881. */
  882. function dol_convert_file($file,$ext='png')
  883. {
  884. global $langs;
  885. $image=new Imagick();
  886. $ret = $image->readImage($file);
  887. if ($ret)
  888. {
  889. $ret = $image->setImageFormat($ext);
  890. if ($ret)
  891. {
  892. $count = $image->getNumberImages();
  893. $ret = $image->writeImages($file . "." . $ext, true);
  894. if ($ret) return $count;
  895. else return -3;
  896. }
  897. else
  898. {
  899. return -2;
  900. }
  901. }
  902. else
  903. {
  904. return -1;
  905. }
  906. return 1;
  907. }
  908. /**
  909. * Compress a file
  910. *
  911. * @param string $inputfile Source file name
  912. * @param string $outputfile Target file name
  913. * @param string $mode 'gz' or 'bz'
  914. */
  915. function dol_compress_file($inputfile, $outputfile, $mode="gz")
  916. {
  917. try
  918. {
  919. $data = implode("", file($inputfile));
  920. if ($mode == 'gz') $compressdata = gzencode($data, 9);
  921. elseif ($mode == 'bz') $compressdata = bzcompress($data, 9);
  922. $fp = fopen($outputfile, "w");
  923. fwrite($fp, $compressdata);
  924. fclose($fp);
  925. }
  926. catch (Exception $e)
  927. {
  928. global $langs, $errormsg;
  929. $langs->load("errors");
  930. dol_syslog("Failed to open file ".$outputfile,LOG_ERR);
  931. $errormsg=$langs->trans("ErrorFailedToWriteInDir");
  932. return -1;
  933. }
  934. }
  935. ?>