dolibarr  18.0.6
files.lib.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2008-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2012-2021 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2012-2016 Juanjo Menent <jmenent@2byte.es>
5  * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
6  * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
7  * Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr>
8  * Copyright (C) 2023 Lenin Rivas <lenin.rivas777@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <https://www.gnu.org/licenses/>.
22  * or see https://www.gnu.org/
23  */
24 
37 function dol_basename($pathfile)
38 {
39  return preg_replace('/^.*\/([^\/]+)$/', '$1', rtrim($pathfile, '/'));
40 }
41 
62 function dol_dir_list($path, $types = "all", $recursive = 0, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0, $nohook = 0, $relativename = "", $donotfollowsymlinks = 0, $nbsecondsold = 0)
63 {
64  global $db, $hookmanager;
65  global $object;
66 
67  if ($recursive <= 1) { // Avoid too verbose log
68  dol_syslog("files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter));
69  //print 'xxx'."files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter);
70  }
71 
72  $loaddate = ($mode == 1 || $mode == 2 || $nbsecondsold) ? true : false;
73  $loadsize = ($mode == 1 || $mode == 3) ?true : false;
74  $loadperm = ($mode == 1 || $mode == 4) ?true : false;
75 
76  // Clean parameters
77  $path = preg_replace('/([\\/]+)$/i', '', $path);
78  $newpath = dol_osencode($path);
79  $now = dol_now();
80 
81  $reshook = 0;
82  $file_list = array();
83 
84  if (is_object($hookmanager) && !$nohook) {
85  $hookmanager->resArray = array();
86 
87  $hookmanager->initHooks(array('fileslib'));
88 
89  $parameters = array(
90  'path' => $newpath,
91  'types'=> $types,
92  'recursive' => $recursive,
93  'filter' => $filter,
94  'excludefilter' => $excludefilter,
95  'sortcriteria' => $sortcriteria,
96  'sortorder' => $sortorder,
97  'loaddate' => $loaddate,
98  'loadsize' => $loadsize,
99  'mode' => $mode
100  );
101  $reshook = $hookmanager->executeHooks('getDirList', $parameters, $object);
102  }
103 
104  // $hookmanager->resArray may contain array stacked by other modules
105  if (empty($reshook)) {
106  if (!is_dir($newpath)) {
107  return array();
108  }
109 
110  if ($dir = opendir($newpath)) {
111  $filedate = '';
112  $filesize = '';
113  $fileperm = '';
114  while (false !== ($file = readdir($dir))) { // $file is always a basename (into directory $newpath)
115  if (!utf8_check($file)) {
116  $file = utf8_encode($file); // To be sure data is stored in utf8 in memory
117  }
118  $fullpathfile = ($newpath ? $newpath.'/' : '').$file;
119 
120  $qualified = 1;
121 
122  // Define excludefilterarray
123  $excludefilterarray = array('^\.');
124  if (is_array($excludefilter)) {
125  $excludefilterarray = array_merge($excludefilterarray, $excludefilter);
126  } elseif ($excludefilter) {
127  $excludefilterarray[] = $excludefilter;
128  }
129  // Check if file is qualified
130  foreach ($excludefilterarray as $filt) {
131  if (preg_match('/'.$filt.'/i', $file) || preg_match('/'.$filt.'/i', $fullpathfile)) {
132  $qualified = 0;
133  break;
134  }
135  }
136  //print $fullpathfile.' '.$file.' '.$qualified.'<br>';
137 
138  if ($qualified) {
139  $isdir = is_dir(dol_osencode($path."/".$file));
140  // Check whether this is a file or directory and whether we're interested in that type
141  if ($isdir && (($types == "directories") || ($types == "all") || $recursive > 0)) {
142  // Add entry into file_list array
143  if (($types == "directories") || ($types == "all")) {
144  if ($loaddate || $sortcriteria == 'date') {
145  $filedate = dol_filemtime($path."/".$file);
146  }
147  if ($loadsize || $sortcriteria == 'size') {
148  $filesize = dol_filesize($path."/".$file);
149  }
150  if ($loadperm || $sortcriteria == 'perm') {
151  $fileperm = dol_fileperm($path."/".$file);
152  }
153 
154  if (!$filter || preg_match('/'.$filter.'/i', $file)) { // We do not search key $filter into all $path, only into $file part
155  $reg = array();
156  preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg);
157  $level1name = (isset($reg[1]) ? $reg[1] : '');
158  $file_list[] = array(
159  "name" => $file,
160  "path" => $path,
161  "level1name" => $level1name,
162  "relativename" => ($relativename ? $relativename.'/' : '').$file,
163  "fullname" => $path.'/'.$file,
164  "date" => $filedate,
165  "size" => $filesize,
166  "perm" => $fileperm,
167  "type" => 'dir'
168  );
169  }
170  }
171 
172  // if we're in a directory and we want recursive behavior, call this function again
173  if ($recursive > 0) {
174  if (empty($donotfollowsymlinks) || !is_link($path."/".$file)) {
175  //var_dump('eee '. $path."/".$file. ' '.is_dir($path."/".$file).' '.is_link($path."/".$file));
176  $file_list = array_merge($file_list, dol_dir_list($path."/".$file, $types, $recursive + 1, $filter, $excludefilter, $sortcriteria, $sortorder, $mode, $nohook, ($relativename != '' ? $relativename.'/' : '').$file, $donotfollowsymlinks, $nbsecondsold));
177  }
178  }
179  } elseif (!$isdir && (($types == "files") || ($types == "all"))) {
180  // Add file into file_list array
181  if ($loaddate || $sortcriteria == 'date') {
182  $filedate = dol_filemtime($path."/".$file);
183  }
184  if ($loadsize || $sortcriteria == 'size') {
185  $filesize = dol_filesize($path."/".$file);
186  }
187 
188  if (!$filter || preg_match('/'.$filter.'/i', $file)) { // We do not search key $filter into $path, only into $file
189  if (empty($nbsecondsold) || $filedate <= ($now - $nbsecondsold)) {
190  preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg);
191  $level1name = (isset($reg[1]) ? $reg[1] : '');
192  $file_list[] = array(
193  "name" => $file,
194  "path" => $path,
195  "level1name" => $level1name,
196  "relativename" => ($relativename ? $relativename.'/' : '').$file,
197  "fullname" => $path.'/'.$file,
198  "date" => $filedate,
199  "size" => $filesize,
200  "type" => 'file'
201  );
202  }
203  }
204  }
205  }
206  }
207  closedir($dir);
208 
209  // Obtain a list of columns
210  if (!empty($sortcriteria) && $sortorder) {
211  $file_list = dol_sort_array($file_list, $sortcriteria, ($sortorder == SORT_ASC ? 'asc' : 'desc'));
212  }
213  }
214  }
215 
216  if (is_object($hookmanager) && is_array($hookmanager->resArray)) {
217  $file_list = array_merge($file_list, $hookmanager->resArray);
218  }
219 
220  return $file_list;
221 }
222 
223 
237 function dol_dir_list_in_database($path, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0)
238 {
239  global $conf, $db;
240 
241  $sql = " SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams,";
242  $sql .= " date_c, tms as date_m, fk_user_c, fk_user_m, acl, position, share";
243  if ($mode) {
244  $sql .= ", description";
245  }
246  $sql .= " FROM ".MAIN_DB_PREFIX."ecm_files";
247  $sql .= " WHERE entity = ".$conf->entity;
248  if (preg_match('/%$/', $path)) {
249  $sql .= " AND filepath LIKE '".$db->escape($path)."'";
250  } else {
251  $sql .= " AND filepath = '".$db->escape($path)."'";
252  }
253 
254  $resql = $db->query($sql);
255  if ($resql) {
256  $file_list = array();
257  $num = $db->num_rows($resql);
258  $i = 0;
259  while ($i < $num) {
260  $obj = $db->fetch_object($resql);
261  if ($obj) {
262  $reg = array();
263  preg_match('/([^\/]+)\/[^\/]+$/', DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename, $reg);
264  $level1name = (isset($reg[1]) ? $reg[1] : '');
265  $file_list[] = array(
266  "rowid" => $obj->rowid,
267  "label" => $obj->label, // md5
268  "name" => $obj->filename,
269  "path" => DOL_DATA_ROOT.'/'.$obj->filepath,
270  "level1name" => $level1name,
271  "fullname" => DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,
272  "fullpath_orig" => $obj->fullpath_orig,
273  "date_c" => $db->jdate($obj->date_c),
274  "date_m" => $db->jdate($obj->date_m),
275  "type" => 'file',
276  "keywords" => $obj->keywords,
277  "cover" => $obj->cover,
278  "position" => (int) $obj->position,
279  "acl" => $obj->acl,
280  "share" => $obj->share,
281  "description" => ($mode ? $obj->description : '')
282  );
283  }
284  $i++;
285  }
286 
287  // Obtain a list of columns
288  if (!empty($sortcriteria)) {
289  $myarray = array();
290  foreach ($file_list as $key => $row) {
291  $myarray[$key] = (isset($row[$sortcriteria]) ? $row[$sortcriteria] : '');
292  }
293  // Sort the data
294  if ($sortorder) {
295  array_multisort($myarray, $sortorder, $file_list);
296  }
297  }
298 
299  return $file_list;
300  } else {
301  dol_print_error($db);
302  return array();
303  }
304 }
305 
306 
315 function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
316 {
317  global $conf, $db, $user;
318 
319  $filearrayindatabase = dol_dir_list_in_database($relativedir, '', null, 'name', SORT_ASC);
320 
321  // TODO Remove this when PRODUCT_USE_OLD_PATH_FOR_PHOTO will be removed
322  global $modulepart;
323  if ($modulepart == 'produit' && getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
324  global $object;
325  if (!empty($object->id)) {
326  if (isModEnabled("product")) {
327  $upload_dirold = $conf->product->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos";
328  } else {
329  $upload_dirold = $conf->service->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos";
330  }
331 
332  $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dirold);
333  $relativedirold = preg_replace('/^[\\/]/', '', $relativedirold);
334 
335  $filearrayindatabase = array_merge($filearrayindatabase, dol_dir_list_in_database($relativedirold, '', null, 'name', SORT_ASC));
336  }
337  }
338 
339  //var_dump($relativedir);
340  //var_dump($filearray);
341  //var_dump($filearrayindatabase);
342 
343  // Complete filearray with properties found into $filearrayindatabase
344  foreach ($filearray as $key => $val) {
345  $tmpfilename = preg_replace('/\.noexe$/', '', $filearray[$key]['name']);
346  $found = 0;
347  // Search if it exists into $filearrayindatabase
348  foreach ($filearrayindatabase as $key2 => $val2) {
349  if (($filearrayindatabase[$key2]['path'] == $filearray[$key]['path']) && ($filearrayindatabase[$key2]['name'] == $tmpfilename)) {
350  $filearray[$key]['position_name'] = ($filearrayindatabase[$key2]['position'] ? $filearrayindatabase[$key2]['position'] : '0').'_'.$filearrayindatabase[$key2]['name'];
351  $filearray[$key]['position'] = $filearrayindatabase[$key2]['position'];
352  $filearray[$key]['cover'] = $filearrayindatabase[$key2]['cover'];
353  $filearray[$key]['keywords'] = $filearrayindatabase[$key2]['keywords'];
354  $filearray[$key]['acl'] = $filearrayindatabase[$key2]['acl'];
355  $filearray[$key]['rowid'] = $filearrayindatabase[$key2]['rowid'];
356  $filearray[$key]['label'] = $filearrayindatabase[$key2]['label'];
357  $filearray[$key]['share'] = $filearrayindatabase[$key2]['share'];
358  $found = 1;
359  break;
360  }
361  }
362 
363  if (!$found) { // This happen in transition toward version 6, or if files were added manually into os dir.
364  $filearray[$key]['position'] = '999999'; // File not indexed are at end. So if we add a file, it will not replace an existing position
365  $filearray[$key]['cover'] = 0;
366  $filearray[$key]['acl'] = '';
367 
368  $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filearray[$key]['fullname']);
369 
370  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filename)) { // If not a tmp file
371  dol_syslog("list_of_documents We found a file called '".$filearray[$key]['name']."' not indexed into database. We add it");
372  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
373  $ecmfile = new EcmFiles($db);
374 
375  // Add entry into database
376  $filename = basename($rel_filename);
377  $rel_dir = dirname($rel_filename);
378  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
379  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
380 
381  $ecmfile->filepath = $rel_dir;
382  $ecmfile->filename = $filename;
383  $ecmfile->label = md5_file(dol_osencode($filearray[$key]['fullname'])); // $destfile is a full path to file
384  $ecmfile->fullpath_orig = $filearray[$key]['fullname'];
385  $ecmfile->gen_or_uploaded = 'unknown';
386  $ecmfile->description = ''; // indexed content
387  $ecmfile->keywords = ''; // keyword content
388  $result = $ecmfile->create($user);
389  if ($result < 0) {
390  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
391  } else {
392  $filearray[$key]['rowid'] = $result;
393  }
394  } else {
395  $filearray[$key]['rowid'] = 0; // Should not happened
396  }
397  }
398  }
399  //var_dump($filearray); var_dump($relativedir.' - tmpfilename='.$tmpfilename.' - found='.$found);
400 }
401 
402 
410 function dol_compare_file($a, $b)
411 {
412  global $sortorder, $sortfield;
413 
414  $sortorder = strtoupper($sortorder);
415 
416  if ($sortorder == 'ASC') {
417  $retup = -1;
418  $retdown = 1;
419  } else {
420  $retup = 1;
421  $retdown = -1;
422  }
423 
424  if ($sortfield == 'name') {
425  if ($a->name == $b->name) {
426  return 0;
427  }
428  return ($a->name < $b->name) ? $retup : $retdown;
429  }
430  if ($sortfield == 'date') {
431  if ($a->date == $b->date) {
432  return 0;
433  }
434  return ($a->date < $b->date) ? $retup : $retdown;
435  }
436  if ($sortfield == 'size') {
437  if ($a->size == $b->size) {
438  return 0;
439  }
440  return ($a->size < $b->size) ? $retup : $retdown;
441  }
442 
443  return 0;
444 }
445 
446 
453 function dol_is_dir($folder)
454 {
455  $newfolder = dol_osencode($folder);
456  if (is_dir($newfolder)) {
457  return true;
458  } else {
459  return false;
460  }
461 }
462 
469 function dol_is_dir_empty($dir)
470 {
471  if (!is_readable($dir)) {
472  return false;
473  }
474  return (count(scandir($dir)) == 2);
475 }
476 
483 function dol_is_file($pathoffile)
484 {
485  $newpathoffile = dol_osencode($pathoffile);
486  return is_file($newpathoffile);
487 }
488 
495 function dol_is_link($pathoffile)
496 {
497  $newpathoffile = dol_osencode($pathoffile);
498  return is_link($newpathoffile);
499 }
500 
507 function dol_is_url($url)
508 {
509  $tmpprot = array('file', 'http', 'https', 'ftp', 'zlib', 'data', 'ssh', 'ssh2', 'ogg', 'expect');
510  foreach ($tmpprot as $prot) {
511  if (preg_match('/^'.$prot.':/i', $url)) {
512  return true;
513  }
514  }
515  return false;
516 }
517 
524 function dol_dir_is_emtpy($folder)
525 {
526  $newfolder = dol_osencode($folder);
527  if (is_dir($newfolder)) {
528  $handle = opendir($newfolder);
529  $folder_content = '';
530  while ((gettype($name = readdir($handle)) != "boolean")) {
531  $name_array[] = $name;
532  }
533  foreach ($name_array as $temp) {
534  $folder_content .= $temp;
535  }
536 
537  closedir($handle);
538 
539  if ($folder_content == "...") {
540  return true;
541  } else {
542  return false;
543  }
544  } else {
545  return true; // Dir does not exists
546  }
547 }
548 
556 function dol_count_nb_of_line($file)
557 {
558  $nb = 0;
559 
560  $newfile = dol_osencode($file);
561  //print 'x'.$file;
562  $fp = fopen($newfile, 'r');
563  if ($fp) {
564  while (!feof($fp)) {
565  $line = fgets($fp);
566  // We increase count only if read was success. We need test because feof return true only after fgets so we do n+1 fgets for a file with n lines.
567  if (!$line === false) {
568  $nb++;
569  }
570  }
571  fclose($fp);
572  } else {
573  $nb = -1;
574  }
575 
576  return $nb;
577 }
578 
579 
587 function dol_filesize($pathoffile)
588 {
589  $newpathoffile = dol_osencode($pathoffile);
590  return filesize($newpathoffile);
591 }
592 
599 function dol_filemtime($pathoffile)
600 {
601  $newpathoffile = dol_osencode($pathoffile);
602  return @filemtime($newpathoffile); // @Is to avoid errors if files does not exists
603 }
604 
611 function dol_fileperm($pathoffile)
612 {
613  $newpathoffile = dol_osencode($pathoffile);
614  return fileperms($newpathoffile);
615 }
616 
629 function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask = 0, $indexdatabase = 0, $arrayreplacementisregex = 0)
630 {
631  global $conf;
632 
633  dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase." arrayreplacementisregex=".$arrayreplacementisregex);
634 
635  if (empty($srcfile)) {
636  return -1;
637  }
638  if (empty($destfile)) {
639  $destfile = $srcfile;
640  }
641 
642  $destexists = dol_is_file($destfile);
643  if (($destfile != $srcfile) && $destexists) {
644  return 0;
645  }
646 
647  $srcexists = dol_is_file($srcfile);
648  if (!$srcexists) {
649  dol_syslog("files.lib.php::dolReplaceInFile failed to read src file", LOG_WARNING);
650  return -3;
651  }
652 
653  $tmpdestfile = $destfile.'.tmp';
654 
655  $newpathofsrcfile = dol_osencode($srcfile);
656  $newpathoftmpdestfile = dol_osencode($tmpdestfile);
657  $newpathofdestfile = dol_osencode($destfile);
658  $newdirdestfile = dirname($newpathofdestfile);
659 
660  if ($destexists && !is_writable($newpathofdestfile)) {
661  dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to overwrite target file", LOG_WARNING);
662  return -1;
663  }
664  if (!is_writable($newdirdestfile)) {
665  dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
666  return -2;
667  }
668 
669  dol_delete_file($tmpdestfile);
670 
671  // Create $newpathoftmpdestfile from $newpathofsrcfile
672  $content = file_get_contents($newpathofsrcfile, 'r');
673 
674  if (empty($arrayreplacementisregex)) {
675  $content = make_substitutions($content, $arrayreplacement, null);
676  } else {
677  foreach ($arrayreplacement as $key => $value) {
678  $content = preg_replace($key, $value, $content);
679  }
680  }
681 
682  file_put_contents($newpathoftmpdestfile, $content);
683  dolChmod($newpathoftmpdestfile, $newmask);
684 
685  // Rename
686  $result = dol_move($newpathoftmpdestfile, $newpathofdestfile, $newmask, (($destfile == $srcfile) ? 1 : 0), 0, $indexdatabase);
687  if (!$result) {
688  dol_syslog("files.lib.php::dolReplaceInFile failed to move tmp file to final dest", LOG_WARNING);
689  return -3;
690  }
691  if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) {
692  $newmask = $conf->global->MAIN_UMASK;
693  }
694  if (empty($newmask)) { // This should no happen
695  dol_syslog("Warning: dolReplaceInFile called with empty value for newmask and no default value defined", LOG_WARNING);
696  $newmask = '0664';
697  }
698 
699  dolChmod($newpathofdestfile, $newmask);
700 
701  return 1;
702 }
703 
704 
717 function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 0)
718 {
719  global $conf, $db, $user;
720 
721  dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
722 
723  if (empty($srcfile) || empty($destfile)) {
724  return -1;
725  }
726 
727  $destexists = dol_is_file($destfile);
728  if (!$overwriteifexists && $destexists) {
729  return 0;
730  }
731 
732  $newpathofsrcfile = dol_osencode($srcfile);
733  $newpathofdestfile = dol_osencode($destfile);
734  $newdirdestfile = dirname($newpathofdestfile);
735 
736  if ($destexists && !is_writable($newpathofdestfile)) {
737  dol_syslog("files.lib.php::dol_copy failed Permission denied to overwrite target file", LOG_WARNING);
738  return -1;
739  }
740  if (!is_writable($newdirdestfile)) {
741  dol_syslog("files.lib.php::dol_copy failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
742  return -2;
743  }
744 
745  // Check virus
746  $testvirusarray = array();
747  if ($testvirus) {
748  $testvirusarray = dolCheckVirus($srcfile);
749  if (count($testvirusarray)) {
750  dol_syslog("files.lib.php::dol_copy canceled because a virus was found into source file. we ignore the copy request.", LOG_WARNING);
751  return -3;
752  }
753  }
754 
755  // Copy with overwriting if exists
756  $result = @copy($newpathofsrcfile, $newpathofdestfile);
757  //$result=copy($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
758  if (!$result) {
759  dol_syslog("files.lib.php::dol_copy failed to copy", LOG_WARNING);
760  return -3;
761  }
762  if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) {
763  $newmask = $conf->global->MAIN_UMASK;
764  }
765  if (empty($newmask)) { // This should no happen
766  dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
767  $newmask = '0664';
768  }
769 
770  dolChmod($newpathofdestfile, $newmask);
771 
772  if ($result && $indexdatabase) {
773  // Add entry into ecm database
774  $rel_filetocopyafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $newpathofdestfile);
775  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetocopyafter)) { // If not a tmp file
776  $rel_filetocopyafter = preg_replace('/^[\\/]/', '', $rel_filetocopyafter);
777  //var_dump($rel_filetorenamebefore.' - '.$rel_filetocopyafter);exit;
778 
779  dol_syslog("Try to copy also entries in database for: ".$rel_filetocopyafter, LOG_DEBUG);
780  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
781 
782  $ecmfiletarget = new EcmFiles($db);
783  $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetocopyafter);
784  if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created.
785  dol_syslog("ECM dest file found, remove it", LOG_DEBUG);
786  $ecmfiletarget->delete($user);
787  } else {
788  dol_syslog("ECM dest file not found, create it", LOG_DEBUG);
789  }
790 
791  $ecmSrcfile = new EcmFiles($db);
792  $resultecm = $ecmSrcfile->fetch(0, '', $srcfile);
793  if ($resultecm) {
794  dol_syslog("Fetch src file ok", LOG_DEBUG);
795  } else {
796  dol_syslog("Fetch src file error", LOG_DEBUG);
797  }
798 
799  $ecmfile = new EcmFiles($db);
800  $filename = basename($rel_filetocopyafter);
801  $rel_dir = dirname($rel_filetocopyafter);
802  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
803  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
804 
805  $ecmfile->filepath = $rel_dir;
806  $ecmfile->filename = $filename;
807  $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
808  $ecmfile->fullpath_orig = $srcfile;
809  $ecmfile->gen_or_uploaded = 'copy';
810  $ecmfile->description = $ecmSrcfile->description;
811  $ecmfile->keywords = $ecmSrcfile->keywords;
812  $resultecm = $ecmfile->create($user);
813  if ($resultecm < 0) {
814  dol_syslog("Create ECM file ok", LOG_DEBUG);
815  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
816  } else {
817  dol_syslog("Create ECM file error", LOG_DEBUG);
818  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
819  }
820 
821  if ($resultecm > 0) {
822  $result = 1;
823  } else {
824  $result = -1;
825  }
826  }
827  }
828 
829  return $result;
830 }
831 
845 function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null, $excludesubdir = 0, $excludefileext = null)
846 {
847  global $conf;
848 
849  $result = 0;
850 
851  dol_syslog("files.lib.php::dolCopyDir srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
852 
853  if (empty($srcfile) || empty($destfile)) {
854  return -1;
855  }
856 
857  $destexists = dol_is_dir($destfile);
858  //if (! $overwriteifexists && $destexists) return 0; // The overwriteifexists is for files only, so propagated to dol_copy only.
859 
860  if (!$destexists) {
861  // We must set mask just before creating dir, becaause it can be set differently by dol_copy
862  umask(0);
863  $dirmaskdec = octdec($newmask);
864  if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) {
865  $dirmaskdec = octdec($conf->global->MAIN_UMASK);
866  }
867  $dirmaskdec |= octdec('0200'); // Set w bit required to be able to create content for recursive subdirs files
868  dol_mkdir($destfile, '', decoct($dirmaskdec));
869  }
870 
871  $ossrcfile = dol_osencode($srcfile);
872  $osdestfile = dol_osencode($destfile);
873 
874  // Recursive function to copy all subdirectories and contents:
875  if (is_dir($ossrcfile)) {
876  $dir_handle = opendir($ossrcfile);
877  while ($file = readdir($dir_handle)) {
878  if ($file != "." && $file != ".." && !is_link($ossrcfile."/".$file)) {
879  if (is_dir($ossrcfile."/".$file)) {
880  if (empty($excludesubdir) || ($excludesubdir == 2 && strlen($file) == 2)) {
881  $newfile = $file;
882  // Replace destination filename with a new one
883  if (is_array($arrayreplacement)) {
884  foreach ($arrayreplacement as $key => $val) {
885  $newfile = str_replace($key, $val, $newfile);
886  }
887  }
888  //var_dump("xxx dolCopyDir $srcfile/$file, $destfile/$file, $newmask, $overwriteifexists");
889  $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists, $arrayreplacement, $excludesubdir, $excludefileext);
890  }
891  } else {
892  $newfile = $file;
893 
894  if (is_array($excludefileext)) {
895  $extension = pathinfo($file, PATHINFO_EXTENSION);
896  if (in_array($extension, $excludefileext)) {
897  //print "We exclude the file ".$file." because its extension is inside list ".join(', ', $excludefileext); exit;
898  continue;
899  }
900  }
901 
902  // Replace destination filename with a new one
903  if (is_array($arrayreplacement)) {
904  foreach ($arrayreplacement as $key => $val) {
905  $newfile = str_replace($key, $val, $newfile);
906  }
907  }
908  $tmpresult = dol_copy($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists);
909  }
910  // Set result
911  if ($result > 0 && $tmpresult >= 0) {
912  // Do nothing, so we don't set result to 0 if tmpresult is 0 and result was success in a previous pass
913  } else {
914  $result = $tmpresult;
915  }
916  if ($result < 0) {
917  break;
918  }
919  }
920  }
921  closedir($dir_handle);
922  } else {
923  // Source directory does not exists
924  $result = -2;
925  }
926 
927  return $result;
928 }
929 
930 
948 function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1, $moreinfo = array())
949 {
950  global $user, $db, $conf;
951  $result = false;
952 
953  dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
954  $srcexists = dol_is_file($srcfile);
955  $destexists = dol_is_file($destfile);
956 
957  if (!$srcexists) {
958  dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request.");
959  return false;
960  }
961 
962  if ($overwriteifexists || !$destexists) {
963  $newpathofsrcfile = dol_osencode($srcfile);
964  $newpathofdestfile = dol_osencode($destfile);
965 
966  // Check virus
967  $testvirusarray = array();
968  if ($testvirus) {
969  $testvirusarray = dolCheckVirus($newpathofsrcfile);
970  if (count($testvirusarray)) {
971  dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. we ignore the move request.", LOG_WARNING);
972  return false;
973  }
974  }
975 
976  global $dolibarr_main_restrict_os_commands;
977  if (!empty($dolibarr_main_restrict_os_commands)) {
978  $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
979  $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
980  if (in_array(basename($destfile), $arrayofallowedcommand)) {
981  //$langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
982  //setEventMessages($langs->trans("ErrorFilenameReserved", basename($destfile)), null, 'errors');
983  dol_syslog("files.lib.php::dol_move canceled because target filename ".basename($destfile)." is using a reserved command name. we ignore the move request.", LOG_WARNING);
984  return false;
985  }
986  }
987 
988  $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
989  if (!$result) {
990  if ($destexists) {
991  dol_syslog("files.lib.php::dol_move Failed. We try to delete target first and move after.", LOG_WARNING);
992  // We force delete and try again. Rename function sometimes fails to replace dest file with some windows NTFS partitions.
993  dol_delete_file($destfile);
994  $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
995  } else {
996  dol_syslog("files.lib.php::dol_move Failed.", LOG_WARNING);
997  }
998  }
999 
1000  // Move ok
1001  if ($result && $indexdatabase) {
1002  // Rename entry into ecm database
1003  $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile);
1004  $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile);
1005  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) { // If not a tmp file
1006  $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore);
1007  $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter);
1008  //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);exit;
1009 
1010  dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG);
1011  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1012 
1013  $ecmfiletarget = new EcmFiles($db);
1014  $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetorenameafter);
1015  if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created.
1016  $ecmfiletarget->delete($user);
1017  }
1018 
1019  $ecmfile = new EcmFiles($db);
1020  $resultecm = $ecmfile->fetch(0, '', $rel_filetorenamebefore);
1021  if ($resultecm > 0) { // If an entry was found for src file, we use it to move entry
1022  $filename = basename($rel_filetorenameafter);
1023  $rel_dir = dirname($rel_filetorenameafter);
1024  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1025  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1026 
1027  $ecmfile->filepath = $rel_dir;
1028  $ecmfile->filename = $filename;
1029 
1030  $resultecm = $ecmfile->update($user);
1031  } elseif ($resultecm == 0) { // If no entry were found for src files, create/update target file
1032  $filename = basename($rel_filetorenameafter);
1033  $rel_dir = dirname($rel_filetorenameafter);
1034  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1035  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1036 
1037  $ecmfile->filepath = $rel_dir;
1038  $ecmfile->filename = $filename;
1039  $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
1040  $ecmfile->fullpath_orig = $srcfile;
1041  $ecmfile->gen_or_uploaded = 'uploaded';
1042  if (!empty($moreinfo) && !empty($moreinfo['description'])) {
1043  $ecmfile->description = $moreinfo['description']; // indexed content
1044  } else {
1045  $ecmfile->description = ''; // indexed content
1046  }
1047  if (!empty($moreinfo) && !empty($moreinfo['keywords'])) {
1048  $ecmfile->keywords = $moreinfo['keywords']; // indexed content
1049  } else {
1050  $ecmfile->keywords = ''; // keyword content
1051  }
1052  if (!empty($moreinfo) && !empty($moreinfo['note_private'])) {
1053  $ecmfile->note_private = $moreinfo['note_private'];
1054  }
1055  if (!empty($moreinfo) && !empty($moreinfo['note_public'])) {
1056  $ecmfile->note_public = $moreinfo['note_public'];
1057  }
1058  if (!empty($moreinfo) && !empty($moreinfo['src_object_type'])) {
1059  $ecmfile->src_object_type = $moreinfo['src_object_type'];
1060  }
1061  if (!empty($moreinfo) && !empty($moreinfo['src_object_id'])) {
1062  $ecmfile->src_object_id = $moreinfo['src_object_id'];
1063  }
1064 
1065  $resultecm = $ecmfile->create($user);
1066  if ($resultecm < 0) {
1067  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1068  }
1069  } elseif ($resultecm < 0) {
1070  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1071  }
1072 
1073  if ($resultecm > 0) {
1074  $result = true;
1075  } else {
1076  $result = false;
1077  }
1078  }
1079  }
1080 
1081  if (empty($newmask)) {
1082  $newmask = empty($conf->global->MAIN_UMASK) ? '0755' : $conf->global->MAIN_UMASK;
1083  }
1084 
1085  // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too)
1086  // to allow mask usage for dir, we shoul introduce a new param "isdir" to 1 to complete newmask like this
1087  // if ($isdir) $newmaskdec |= octdec('0111'); // Set x bit required for directories
1088  dolChmod($newpathofdestfile, $newmask);
1089  }
1090 
1091  return $result;
1092 }
1093 
1105 function dol_move_dir($srcdir, $destdir, $overwriteifexists = 1, $indexdatabase = 1, $renamedircontent = 1)
1106 {
1107 
1108  global $user, $db, $conf;
1109  $result = false;
1110 
1111  dol_syslog("files.lib.php::dol_move_dir srcdir=".$srcdir." destdir=".$destdir." overwritifexists=".$overwriteifexists." indexdatabase=".$indexdatabase." renamedircontent=".$renamedircontent);
1112  $srcexists = dol_is_dir($srcdir);
1113  $srcbasename = basename($srcdir);
1114  $destexists = dol_is_dir($destdir);
1115 
1116  if (!$srcexists) {
1117  dol_syslog("files.lib.php::dol_move_dir srcdir does not exists. we ignore the move request.");
1118  return false;
1119  }
1120 
1121  if ($overwriteifexists || !$destexists) {
1122  $newpathofsrcdir = dol_osencode($srcdir);
1123  $newpathofdestdir = dol_osencode($destdir);
1124 
1125  $result = @rename($newpathofsrcdir, $newpathofdestdir);
1126 
1127  if ($result && $renamedircontent) {
1128  if (file_exists($newpathofdestdir)) {
1129  $destbasename = basename($newpathofdestdir);
1130  $files = dol_dir_list($newpathofdestdir);
1131  if (!empty($files) && is_array($files)) {
1132  foreach ($files as $key => $file) {
1133  if (!file_exists($file["fullname"])) continue;
1134  $filepath = $file["path"];
1135  $oldname = $file["name"];
1136 
1137  $newname = str_replace($srcbasename, $destbasename, $oldname);
1138  if (!empty($newname) && $newname !== $oldname) {
1139  if ($file["type"] == "dir") {
1140  $res = dol_move_dir($filepath.'/'.$oldname, $filepath.'/'.$newname, $overwriteifexists, $indexdatabase, $renamedircontent);
1141  } else {
1142  $res = dol_move($filepath.'/'.$oldname, $filepath.'/'.$newname, 0, $overwriteifexists, 0, $indexdatabase);
1143  }
1144  if (!$res) {
1145  return $result;
1146  }
1147  }
1148  }
1149  $result = true;
1150  }
1151  }
1152  }
1153  }
1154  return $result;
1155 }
1156 
1164 function dol_unescapefile($filename)
1165 {
1166  // Remove path information and dots around the filename, to prevent uploading
1167  // into different directories or replacing hidden system files.
1168  // Also remove control characters and spaces (\x00..\x20) around the filename:
1169  return trim(basename($filename), ".\x00..\x20");
1170 }
1171 
1172 
1179 function dolCheckVirus($src_file)
1180 {
1181  global $conf, $db;
1182 
1183  if (!empty($conf->global->MAIN_ANTIVIRUS_COMMAND)) {
1184  if (!class_exists('AntiVir')) {
1185  require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
1186  }
1187  $antivir = new AntiVir($db);
1188  $result = $antivir->dol_avscan_file($src_file);
1189  if ($result < 0) { // If virus or error, we stop here
1190  $reterrors = $antivir->errors;
1191  return $reterrors;
1192  }
1193  }
1194  return array();
1195 }
1196 
1197 
1218 function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile', $upload_dir = '')
1219 {
1220  global $conf, $db, $user, $langs;
1221  global $object, $hookmanager;
1222 
1223  $reshook = 0;
1224  $file_name = $dest_file;
1225  $successcode = 1;
1226 
1227  if (empty($nohook)) {
1228  $reshook = $hookmanager->initHooks(array('fileslib'));
1229 
1230  $parameters = array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
1231  $reshook = $hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
1232  }
1233 
1234  if (empty($reshook)) {
1235  // If an upload error has been reported
1236  if ($uploaderrorcode) {
1237  switch ($uploaderrorcode) {
1238  case UPLOAD_ERR_INI_SIZE: // 1
1239  return 'ErrorFileSizeTooLarge';
1240  case UPLOAD_ERR_FORM_SIZE: // 2
1241  return 'ErrorFileSizeTooLarge';
1242  case UPLOAD_ERR_PARTIAL: // 3
1243  return 'ErrorPartialFile';
1244  case UPLOAD_ERR_NO_TMP_DIR: //
1245  return 'ErrorNoTmpDir';
1246  case UPLOAD_ERR_CANT_WRITE:
1247  return 'ErrorFailedToWriteInDir';
1248  case UPLOAD_ERR_EXTENSION:
1249  return 'ErrorUploadBlockedByAddon';
1250  default:
1251  break;
1252  }
1253  }
1254 
1255  // Security:
1256  // If we need to make a virus scan
1257  if (empty($disablevirusscan) && file_exists($src_file)) {
1258  $checkvirusarray = dolCheckVirus($src_file);
1259  if (count($checkvirusarray)) {
1260  dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
1261  return 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray);
1262  }
1263  }
1264 
1265  // Security:
1266  // Disallow file with some extensions. We rename them.
1267  // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
1268  if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) {
1269  // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
1270  $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
1271  if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
1272  $publicmediasdirwithslash .= '/';
1273  }
1274 
1275  if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
1276  $file_name .= '.noexe';
1277  $successcode = 2;
1278  }
1279  }
1280 
1281  // Security:
1282  // We refuse cache files/dirs, upload using .. and pipes into filenames.
1283  if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
1284  dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
1285  return -1;
1286  }
1287 
1288  // Security:
1289  // We refuse cache files/dirs, upload using .. and pipes into filenames.
1290  if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
1291  dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
1292  return -2;
1293  }
1294  }
1295 
1296  if ($reshook < 0) { // At least one blocking error returned by one hook
1297  $errmsg = join(',', $hookmanager->errors);
1298  if (empty($errmsg)) {
1299  $errmsg = 'ErrorReturnedBySomeHooks'; // Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
1300  }
1301  return $errmsg;
1302  } elseif (empty($reshook)) {
1303  // The file functions must be in OS filesystem encoding.
1304  $src_file_osencoded = dol_osencode($src_file);
1305  $file_name_osencoded = dol_osencode($file_name);
1306 
1307  // Check if destination dir is writable
1308  if (!is_writable(dirname($file_name_osencoded))) {
1309  dol_syslog("Files.lib::dol_move_uploaded_file Dir ".dirname($file_name_osencoded)." is not writable. Return 'ErrorDirNotWritable'", LOG_WARNING);
1310  return 'ErrorDirNotWritable';
1311  }
1312 
1313  // Check if destination file already exists
1314  if (!$allowoverwrite) {
1315  if (file_exists($file_name_osencoded)) {
1316  dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
1317  return 'ErrorFileAlreadyExists';
1318  }
1319  } else { // We are allowed to erase
1320  if (is_dir($file_name_osencoded)) { // If there is a directory with name of file to create
1321  dol_syslog("Files.lib::dol_move_uploaded_file A directory with name ".$file_name." already exists. Return 'ErrorDirWithFileNameAlreadyExists'", LOG_WARNING);
1322  return 'ErrorDirWithFileNameAlreadyExists';
1323  }
1324  }
1325 
1326  // Move file
1327  $return = move_uploaded_file($src_file_osencoded, $file_name_osencoded);
1328  if ($return) {
1329  dolChmod($file_name_osencoded);
1330  dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG);
1331  return $successcode; // Success
1332  } else {
1333  dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
1334  return -3; // Unknown error
1335  }
1336  }
1337 
1338  return $successcode; // Success
1339 }
1340 
1356 function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1, $nolog = 0)
1357 {
1358  global $db, $conf, $user, $langs;
1359  global $hookmanager;
1360 
1361  // Load translation files required by the page
1362  $langs->loadLangs(array('other', 'errors'));
1363 
1364  if (empty($nolog)) {
1365  dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook);
1366  }
1367 
1368  // Security:
1369  // We refuse transversal using .. and pipes into filenames.
1370  if ((!$allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file)) {
1371  dol_syslog("Refused to delete file ".$file, LOG_WARNING);
1372  return false;
1373  }
1374 
1375  $reshook = 0;
1376  if (empty($nohook)) {
1377  $hookmanager->initHooks(array('fileslib'));
1378 
1379  $parameters = array(
1380  'file' => $file,
1381  'disableglob'=> $disableglob,
1382  'nophperrors' => $nophperrors
1383  );
1384  $reshook = $hookmanager->executeHooks('deleteFile', $parameters, $object);
1385  }
1386 
1387  if (empty($nohook) && $reshook != 0) { // reshook = 0 to do standard actions, 1 = ok and replace, -1 = ko
1388  dol_syslog("reshook=".$reshook);
1389  if ($reshook < 0) {
1390  return false;
1391  }
1392  return true;
1393  } else {
1394  $file_osencoded = dol_osencode($file); // New filename encoded in OS filesystem encoding charset
1395  if (empty($disableglob) && !empty($file_osencoded)) {
1396  $ok = true;
1397  $globencoded = str_replace('[', '\[', $file_osencoded);
1398  $globencoded = str_replace(']', '\]', $globencoded);
1399  $listofdir = glob($globencoded);
1400  if (!empty($listofdir) && is_array($listofdir)) {
1401  foreach ($listofdir as $filename) {
1402  if ($nophperrors) {
1403  $ok = @unlink($filename);
1404  } else {
1405  $ok = unlink($filename);
1406  }
1407 
1408  // If it fails and it is because of the missing write permission on parent dir
1409  if (!$ok && file_exists(dirname($filename)) && !(fileperms(dirname($filename)) & 0200)) {
1410  dol_syslog("Error in deletion, but parent directory exists with no permission to write, we try to change permission on parent directory and retry...", LOG_DEBUG);
1411  dolChmod(dirname($filename), decoct(fileperms(dirname($filename)) | 0200));
1412  // Now we retry deletion
1413  if ($nophperrors) {
1414  $ok = @unlink($filename);
1415  } else {
1416  $ok = unlink($filename);
1417  }
1418  }
1419 
1420  if ($ok) {
1421  if (empty($nolog)) {
1422  dol_syslog("Removed file ".$filename, LOG_DEBUG);
1423  }
1424 
1425  // Delete entry into ecm database
1426  $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename);
1427  if (!preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) { // If not a tmp file
1428  if (is_object($db) && $indexdatabase) { // $db may not be defined when lib is in a context with define('NOREQUIREDB',1)
1429  $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete);
1430  $rel_filetodelete = preg_replace('/\.noexe$/', '', $rel_filetodelete);
1431 
1432  dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG);
1433  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1434  $ecmfile = new EcmFiles($db);
1435  $result = $ecmfile->fetch(0, '', $rel_filetodelete);
1436  if ($result >= 0 && $ecmfile->id > 0) {
1437  $result = $ecmfile->delete($user);
1438  }
1439  if ($result < 0) {
1440  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1441  }
1442  }
1443  }
1444  } else {
1445  dol_syslog("Failed to remove file ".$filename, LOG_WARNING);
1446  // TODO Failure to remove can be because file was already removed or because of permission
1447  // If error because it does not exists, we should return true, and we should return false if this is a permission problem
1448  }
1449  }
1450  } else {
1451  dol_syslog("No files to delete found", LOG_DEBUG);
1452  }
1453  } else {
1454  $ok = false;
1455  if ($nophperrors) {
1456  $ok = @unlink($file_osencoded);
1457  } else {
1458  $ok = unlink($file_osencoded);
1459  }
1460  if ($ok) {
1461  if (empty($nolog)) {
1462  dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
1463  }
1464  } else {
1465  dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
1466  }
1467  }
1468 
1469  return $ok;
1470  }
1471 }
1472 
1482 function dol_delete_dir($dir, $nophperrors = 0)
1483 {
1484  // Security:
1485  // We refuse transversal using .. and pipes into filenames.
1486  if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) {
1487  dol_syslog("Refused to delete dir ".$dir.' (contains invalid char sequence)', LOG_WARNING);
1488  return false;
1489  }
1490 
1491  $dir_osencoded = dol_osencode($dir);
1492  return ($nophperrors ? @rmdir($dir_osencoded) : rmdir($dir_osencoded));
1493 }
1494 
1507 function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0, $indexdatabase = 1, $nolog = 0)
1508 {
1509  if (empty($nolog)) {
1510  dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG);
1511  }
1512  if (dol_is_dir($dir)) {
1513  $dir_osencoded = dol_osencode($dir);
1514  if ($handle = opendir("$dir_osencoded")) {
1515  while (false !== ($item = readdir($handle))) {
1516  if (!utf8_check($item)) {
1517  $item = utf8_encode($item); // should be useless
1518  }
1519 
1520  if ($item != "." && $item != "..") {
1521  if (is_dir(dol_osencode("$dir/$item")) && !is_link(dol_osencode("$dir/$item"))) {
1522  $count = dol_delete_dir_recursive("$dir/$item", $count, $nophperrors, 0, $countdeleted, $indexdatabase, $nolog);
1523  } else {
1524  $result = dol_delete_file("$dir/$item", 1, $nophperrors, 0, null, false, $indexdatabase, $nolog);
1525  $count++;
1526  if ($result) {
1527  $countdeleted++;
1528  }
1529  //else print 'Error on '.$item."\n";
1530  }
1531  }
1532  }
1533  closedir($handle);
1534 
1535  // Delete also the main directory
1536  if (empty($onlysub)) {
1537  $result = dol_delete_dir($dir, $nophperrors);
1538  $count++;
1539  if ($result) {
1540  $countdeleted++;
1541  }
1542  //else print 'Error on '.$dir."\n";
1543  }
1544  }
1545  }
1546 
1547  return $count;
1548 }
1549 
1550 
1559 function dol_delete_preview($object)
1560 {
1561  global $langs, $conf;
1562 
1563  // Define parent dir of elements
1564  $element = $object->element;
1565 
1566  if ($object->element == 'order_supplier') {
1567  $dir = $conf->fournisseur->commande->dir_output;
1568  } elseif ($object->element == 'invoice_supplier') {
1569  $dir = $conf->fournisseur->facture->dir_output;
1570  } elseif ($object->element == 'project') {
1571  $dir = $conf->project->dir_output;
1572  } elseif ($object->element == 'shipping') {
1573  $dir = $conf->expedition->dir_output.'/sending';
1574  } elseif ($object->element == 'delivery') {
1575  $dir = $conf->expedition->dir_output.'/receipt';
1576  } elseif ($object->element == 'fichinter') {
1577  $dir = $conf->ficheinter->dir_output;
1578  } else {
1579  $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1580  }
1581 
1582  if (empty($dir)) {
1583  return 'ErrorObjectNoSupportedByFunction';
1584  }
1585 
1586  $refsan = dol_sanitizeFileName($object->ref);
1587  $dir = $dir."/".$refsan;
1588  $filepreviewnew = $dir."/".$refsan.".pdf_preview.png";
1589  $filepreviewnewbis = $dir."/".$refsan.".pdf_preview-0.png";
1590  $filepreviewold = $dir."/".$refsan.".pdf.png";
1591 
1592  // For new preview files
1593  if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) {
1594  if (!dol_delete_file($filepreviewnew, 1)) {
1595  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnew);
1596  return 0;
1597  }
1598  }
1599  if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) {
1600  if (!dol_delete_file($filepreviewnewbis, 1)) {
1601  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis);
1602  return 0;
1603  }
1604  }
1605  // For old preview files
1606  if (file_exists($filepreviewold) && is_writable($filepreviewold)) {
1607  if (!dol_delete_file($filepreviewold, 1)) {
1608  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewold);
1609  return 0;
1610  }
1611  } else {
1612  $multiple = $filepreviewold.".";
1613  for ($i = 0; $i < 20; $i++) {
1614  $preview = $multiple.$i;
1615 
1616  if (file_exists($preview) && is_writable($preview)) {
1617  if (!dol_delete_file($preview, 1)) {
1618  $object->error = $langs->trans("ErrorFailedToOpenFile", $preview);
1619  return 0;
1620  }
1621  }
1622  }
1623  }
1624 
1625  return 1;
1626 }
1627 
1636 function dol_meta_create($object)
1637 {
1638  global $conf;
1639 
1640  // Create meta file
1641  if (empty($conf->global->MAIN_DOC_CREATE_METAFILE)) {
1642  return 0; // By default, no metafile.
1643  }
1644 
1645  // Define parent dir of elements
1646  $element = $object->element;
1647 
1648  if ($object->element == 'order_supplier') {
1649  $dir = $conf->fournisseur->dir_output.'/commande';
1650  } elseif ($object->element == 'invoice_supplier') {
1651  $dir = $conf->fournisseur->dir_output.'/facture';
1652  } elseif ($object->element == 'project') {
1653  $dir = $conf->project->dir_output;
1654  } elseif ($object->element == 'shipping') {
1655  $dir = $conf->expedition->dir_output.'/sending';
1656  } elseif ($object->element == 'delivery') {
1657  $dir = $conf->expedition->dir_output.'/receipt';
1658  } elseif ($object->element == 'fichinter') {
1659  $dir = $conf->ficheinter->dir_output;
1660  } else {
1661  $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1662  }
1663 
1664  if ($dir) {
1665  $object->fetch_thirdparty();
1666 
1667  $objectref = dol_sanitizeFileName($object->ref);
1668  $dir = $dir."/".$objectref;
1669  $file = $dir."/".$objectref.".meta";
1670 
1671  if (!is_dir($dir)) {
1672  dol_mkdir($dir);
1673  }
1674 
1675  if (is_dir($dir)) {
1676  if (is_countable($object->lines) && count($object->lines) > 0) {
1677  $nblines = count($object->lines);
1678  }
1679  $client = $object->thirdparty->name." ".$object->thirdparty->address." ".$object->thirdparty->zip." ".$object->thirdparty->town;
1680  $meta = "REFERENCE=\"".$object->ref."\"
1681  DATE=\"" . dol_print_date($object->date, '')."\"
1682  NB_ITEMS=\"" . $nblines."\"
1683  CLIENT=\"" . $client."\"
1684  AMOUNT_EXCL_TAX=\"" . $object->total_ht."\"
1685  AMOUNT=\"" . $object->total_ttc."\"\n";
1686 
1687  for ($i = 0; $i < $nblines; $i++) {
1688  //Pour les articles
1689  $meta .= "ITEM_".$i."_QUANTITY=\"".$object->lines[$i]->qty."\"
1690  ITEM_" . $i."_AMOUNT_WO_TAX=\"".$object->lines[$i]->total_ht."\"
1691  ITEM_" . $i."_VAT=\"".$object->lines[$i]->tva_tx."\"
1692  ITEM_" . $i."_DESCRIPTION=\"".str_replace("\r\n", "", nl2br($object->lines[$i]->desc))."\"
1693  ";
1694  }
1695  }
1696 
1697  $fp = fopen($file, "w");
1698  fputs($fp, $meta);
1699  fclose($fp);
1700 
1701  dolChmod($file);
1702 
1703  return 1;
1704  } else {
1705  dol_syslog('FailedToDetectDirInDolMetaCreateFor'.$object->element, LOG_WARNING);
1706  }
1707 
1708  return 0;
1709 }
1710 
1711 
1712 
1721 function dol_init_file_process($pathtoscan = '', $trackid = '')
1722 {
1723  $listofpaths = array();
1724  $listofnames = array();
1725  $listofmimes = array();
1726 
1727  if ($pathtoscan) {
1728  $listoffiles = dol_dir_list($pathtoscan, 'files');
1729  foreach ($listoffiles as $key => $val) {
1730  $listofpaths[] = $val['fullname'];
1731  $listofnames[] = $val['name'];
1732  $listofmimes[] = dol_mimetype($val['name']);
1733  }
1734  }
1735  $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1736  $_SESSION["listofpaths".$keytoavoidconflict] = join(';', $listofpaths);
1737  $_SESSION["listofnames".$keytoavoidconflict] = join(';', $listofnames);
1738  $_SESSION["listofmimes".$keytoavoidconflict] = join(';', $listofmimes);
1739 }
1740 
1741 
1759 function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null)
1760 {
1761 
1762  global $db, $user, $conf, $langs;
1763 
1764  $res = 0;
1765 
1766  if (!empty($_FILES[$varfiles])) { // For view $_FILES[$varfiles]['error']
1767  dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG);
1768  $maxfilesinform = getDolGlobalInt("MAIN_SECURITY_MAX_ATTACHMENT_ON_FORMS", 10);
1769  if (is_array($_FILES[$varfiles]["name"]) && count($_FILES[$varfiles]["name"]) > $maxfilesinform) {
1770  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1771  setEventMessages($langs->trans("ErrorTooMuchFileInForm", $maxfilesinform), null, "errors");
1772  return -1;
1773  }
1774  $result = dol_mkdir($upload_dir);
1775  // var_dump($result);exit;
1776  if ($result >= 0) {
1777  $TFile = $_FILES[$varfiles];
1778  if (!is_array($TFile['name'])) {
1779  foreach ($TFile as $key => &$val) {
1780  $val = array($val);
1781  }
1782  }
1783 
1784  $nbfile = count($TFile['name']);
1785  $nbok = 0;
1786  for ($i = 0; $i < $nbfile; $i++) {
1787  if (empty($TFile['name'][$i])) {
1788  continue; // For example, when submitting a form with no file name
1789  }
1790 
1791  // Define $destfull (path to file including filename) and $destfile (only filename)
1792  $destfull = $upload_dir."/".$TFile['name'][$i];
1793  $destfile = $TFile['name'][$i];
1794  $destfilewithoutext = preg_replace('/\.[^\.]+$/', '', $destfile);
1795 
1796  if ($savingdocmask && strpos($savingdocmask, $destfilewithoutext) !== 0) {
1797  $destfull = $upload_dir."/".preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask);
1798  $destfile = preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask);
1799  }
1800 
1801  $filenameto = basename($destfile);
1802  if (preg_match('/^\./', $filenameto)) {
1803  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1804  setEventMessages($langs->trans("ErrorFilenameCantStartWithDot", $filenameto), null, 'errors');
1805  break;
1806  }
1807 
1808  // dol_sanitizeFileName the file name and lowercase extension
1809  $info = pathinfo($destfull);
1810  $destfull = $info['dirname'].'/'.dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1811  $info = pathinfo($destfile);
1812  $destfile = dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1813 
1814  // We apply dol_string_nohtmltag also to clean file names (this remove duplicate spaces) because
1815  // this function is also applied when we rename and when we make try to download file (by the GETPOST(filename, 'alphanohtml') call).
1816  $destfile = dol_string_nohtmltag($destfile);
1817  $destfull = dol_string_nohtmltag($destfull);
1818 
1819  // Check that filename is not the one of a reserved allowed CLI command
1820  global $dolibarr_main_restrict_os_commands;
1821  if (!empty($dolibarr_main_restrict_os_commands)) {
1822  $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
1823  $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
1824  if (in_array($destfile, $arrayofallowedcommand)) {
1825  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1826  setEventMessages($langs->trans("ErrorFilenameReserved", $destfile), null, 'errors');
1827  return -1;
1828  }
1829  }
1830 
1831  // Move file from temp directory to final directory. A .noexe may also be appended on file name.
1832  $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir);
1833 
1834  if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists'
1835  include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
1836 
1837  $tmparraysize = getDefaultImageSizes();
1838  $maxwidthsmall = $tmparraysize['maxwidthsmall'];
1839  $maxheightsmall = $tmparraysize['maxheightsmall'];
1840  $maxwidthmini = $tmparraysize['maxwidthmini'];
1841  $maxheightmini = $tmparraysize['maxheightmini'];
1842  //$quality = $tmparraysize['quality'];
1843  $quality = 50; // For thumbs, we force quality to 50
1844 
1845  // Generate thumbs.
1846  if ($generatethumbs) {
1847  if (image_format_supported($destfull) == 1) {
1848  // Create thumbs
1849  // We can't use $object->addThumbs here because there is no $object known
1850 
1851  // Used on logon for example
1852  $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', $quality, "thumbs");
1853  // Create mini thumbs for image (Ratio is near 16/9)
1854  // Used on menu or for setup page for example
1855  $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', $quality, "thumbs");
1856  }
1857  }
1858 
1859  // Update session
1860  if (empty($donotupdatesession)) {
1861  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1862  $formmail = new FormMail($db);
1863  $formmail->trackid = $trackid;
1864  $formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
1865  }
1866 
1867  // Update index table of files (llx_ecm_files)
1868  if ($donotupdatesession == 1) {
1869  $sharefile = 0;
1870  if ($TFile['type'][$i] == 'application/pdf' && strpos($_SERVER["REQUEST_URI"], 'product') !== false && !empty($conf->global->PRODUCT_ALLOW_EXTERNAL_DOWNLOAD)) $sharefile = 1;
1871  $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', $sharefile, $object);
1872  if ($result < 0) {
1873  if ($allowoverwrite) {
1874  // Do not show error message. We can have an error due to DB_ERROR_RECORD_ALREADY_EXISTS
1875  } else {
1876  setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', null, 'warnings');
1877  }
1878  }
1879  }
1880 
1881  $nbok++;
1882  } else {
1883  $langs->load("errors");
1884  if ($resupload < 0) { // Unknown error
1885  setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
1886  } elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) { // Files infected by a virus
1887  setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors');
1888  } else // Known error
1889  {
1890  setEventMessages($langs->trans($resupload), null, 'errors');
1891  }
1892  }
1893  }
1894  if ($nbok > 0) {
1895  $res = 1;
1896  setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs');
1897  }
1898  } else {
1899  setEventMessages($langs->trans("ErrorFailedToCreateDir", $upload_dir), null, 'errors');
1900  }
1901  } elseif ($link) {
1902  require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
1903  $linkObject = new Link($db);
1904  $linkObject->entity = $conf->entity;
1905  $linkObject->url = $link;
1906  $linkObject->objecttype = GETPOST('objecttype', 'alpha');
1907  $linkObject->objectid = GETPOST('objectid', 'int');
1908  $linkObject->label = GETPOST('label', 'alpha');
1909  $res = $linkObject->create($user);
1910  $langs->load('link');
1911  if ($res > 0) {
1912  setEventMessages($langs->trans("LinkComplete"), null, 'mesgs');
1913  } else {
1914  setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors');
1915  }
1916  } else {
1917  $langs->load("errors");
1918  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
1919  }
1920 
1921  return $res;
1922 }
1923 
1924 
1936 function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '')
1937 {
1938  global $db, $user, $conf, $langs, $_FILES;
1939 
1940  $keytodelete = $filenb;
1941  $keytodelete--;
1942 
1943  $listofpaths = array();
1944  $listofnames = array();
1945  $listofmimes = array();
1946  $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1947  if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
1948  $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
1949  }
1950  if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
1951  $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
1952  }
1953  if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
1954  $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
1955  }
1956 
1957  if ($keytodelete >= 0) {
1958  $pathtodelete = $listofpaths[$keytodelete];
1959  $filetodelete = $listofnames[$keytodelete];
1960  if (empty($donotdeletefile)) {
1961  $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file
1962  } else {
1963  $result = 0;
1964  }
1965  if ($result >= 0) {
1966  if (empty($donotdeletefile)) {
1967  $langs->load("other");
1968  setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs');
1969  }
1970  if (empty($donotupdatesession)) {
1971  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1972  $formmail = new FormMail($db);
1973  $formmail->trackid = $trackid;
1974  $formmail->remove_attached_files($keytodelete);
1975  }
1976  }
1977  }
1978 }
1979 
1980 
1994 function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null)
1995 {
1996  global $db, $user, $conf;
1997 
1998  $result = 0;
1999 
2000  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2001 
2002  if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir
2003  $filename = basename(preg_replace('/\.noexe$/', '', $file));
2004  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2005  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2006 
2007  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
2008  $ecmfile = new EcmFiles($db);
2009  $ecmfile->filepath = $rel_dir;
2010  $ecmfile->filename = $filename;
2011  $ecmfile->label = md5_file(dol_osencode($dir.'/'.$file)); // MD5 of file content
2012  $ecmfile->fullpath_orig = $fullpathorig;
2013  $ecmfile->gen_or_uploaded = $mode;
2014  $ecmfile->description = ''; // indexed content
2015  $ecmfile->keywords = ''; // keyword content
2016 
2017  if (is_object($object) && $object->id > 0) {
2018  $ecmfile->src_object_id = $object->id;
2019  if (isset($object->table_element)) {
2020  $ecmfile->src_object_type = $object->table_element;
2021  } else {
2022  dol_syslog('Error: object ' . get_class($object) . ' has no table_element attribute.');
2023  return -1;
2024  }
2025  if (isset($object->src_object_description)) $ecmfile->description = $object->src_object_description;
2026  if (isset($object->src_object_keywords)) $ecmfile->keywords = $object->src_object_keywords;
2027  }
2028 
2029  if (!empty($conf->global->MAIN_FORCE_SHARING_ON_ANY_UPLOADED_FILE)) {
2030  $setsharekey = 1;
2031  }
2032 
2033  if ($setsharekey) {
2034  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
2035  $ecmfile->share = getRandomPassword(true);
2036  }
2037 
2038  $result = $ecmfile->create($user);
2039  if ($result < 0) {
2040  dol_syslog($ecmfile->error);
2041  }
2042  }
2043 
2044  return $result;
2045 }
2046 
2055 function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded')
2056 {
2057  global $conf, $db, $user;
2058 
2059  $error = 0;
2060 
2061  if (empty($dir)) {
2062  dol_syslog("deleteFilesIntoDatabaseIndex: dir parameter can't be empty", LOG_ERR);
2063  return -1;
2064  }
2065 
2066  $db->begin();
2067 
2068  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2069 
2070  $filename = basename($file);
2071  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2072  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2073 
2074  if (!$error) {
2075  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'ecm_files';
2076  $sql .= ' WHERE entity = '.$conf->entity;
2077  $sql .= " AND filepath = '".$db->escape($rel_dir)."'";
2078  if ($file) {
2079  $sql .= " AND filename = '".$db->escape($file)."'";
2080  }
2081  if ($mode) {
2082  $sql .= " AND gen_or_uploaded = '".$db->escape($mode)."'";
2083  }
2084 
2085  $resql = $db->query($sql);
2086  if (!$resql) {
2087  $error++;
2088  dol_syslog(__METHOD__.' '.$db->lasterror(), LOG_ERR);
2089  }
2090  }
2091 
2092  // Commit or rollback
2093  if ($error) {
2094  $db->rollback();
2095  return -1 * $error;
2096  } else {
2097  $db->commit();
2098  return 1;
2099  }
2100 }
2101 
2102 
2114 function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '')
2115 {
2116  if (class_exists('Imagick')) {
2117  $image = new Imagick();
2118  try {
2119  $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : '');
2120  //var_dump($filetoconvert);
2121  $ret = $image->readImage($filetoconvert);
2122  } catch (Exception $e) {
2123  $ext = pathinfo($fileinput, PATHINFO_EXTENSION);
2124  dol_syslog("Failed to read image using Imagick (Try to install package 'apt-get install php-imagick ghostscript' and check there is no policy to disable ".$ext." convertion in /etc/ImageMagick*/policy.xml): ".$e->getMessage(), LOG_WARNING);
2125  return 0;
2126  }
2127  if ($ret) {
2128  $ret = $image->setImageFormat($ext);
2129  if ($ret) {
2130  if (empty($fileoutput)) {
2131  $fileoutput = $fileinput.".".$ext;
2132  }
2133 
2134  $count = $image->getNumberImages();
2135 
2136  if (!dol_is_file($fileoutput) || is_writeable($fileoutput)) {
2137  try {
2138  $ret = $image->writeImages($fileoutput, true);
2139  } catch (Exception $e) {
2140  dol_syslog($e->getMessage(), LOG_WARNING);
2141  }
2142  } else {
2143  dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR);
2144  }
2145  if ($ret) {
2146  return $count;
2147  } else {
2148  return -3;
2149  }
2150  } else {
2151  return -2;
2152  }
2153  } else {
2154  return -1;
2155  }
2156  } else {
2157  return 0;
2158  }
2159 }
2160 
2161 
2173 function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring = null)
2174 {
2175  global $conf;
2176 
2177  $foundhandler = 0;
2178 
2179  try {
2180  dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile);
2181 
2182  $data = implode("", file(dol_osencode($inputfile)));
2183  if ($mode == 'gz' && function_exists('gzencode')) {
2184  $foundhandler = 1;
2185  $compressdata = gzencode($data, 9);
2186  } elseif ($mode == 'bz' && function_exists('bzcompress')) {
2187  $foundhandler = 1;
2188  $compressdata = bzcompress($data, 9);
2189  } elseif ($mode == 'zstd' && function_exists('zstd_compress')) {
2190  $foundhandler = 1;
2191  $compressdata = zstd_compress($data, 9);
2192  } elseif ($mode == 'zip') {
2193  if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) {
2194  $foundhandler = 1;
2195 
2196  $rootPath = realpath($inputfile);
2197 
2198  dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath);
2199  $zip = new ZipArchive;
2200 
2201  if ($zip->open($outputfile, ZipArchive::CREATE) !== true) {
2202  $errorstring = "dol_compress_file failure - Failed to open file ".$outputfile."\n";
2203  dol_syslog($errorstring, LOG_ERR);
2204 
2205  global $errormsg;
2206  $errormsg = $errorstring;
2207 
2208  return -6;
2209  }
2210 
2211  // Create recursive directory iterator
2213  $files = new RecursiveIteratorIterator(
2214  new RecursiveDirectoryIterator($rootPath),
2215  RecursiveIteratorIterator::LEAVES_ONLY
2216  );
2217 
2218  foreach ($files as $name => $file) {
2219  // Skip directories (they would be added automatically)
2220  if (!$file->isDir()) {
2221  // Get real and relative path for current file
2222  $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2223  $fileName = $file->getFilename();
2224  $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2225 
2226  //$relativePath = substr($fileFullRealPath, strlen($rootPath) + 1);
2227  $relativePath = substr(($filePath ? $filePath.'/' : '').$fileName, strlen($rootPath) + 1);
2228 
2229  // Add current file to archive
2230  $zip->addFile($fileFullRealPath, $relativePath);
2231  }
2232  }
2233 
2234  // Zip archive will be created only after closing object
2235  $zip->close();
2236 
2237  dol_syslog("dol_compress_file success - ".count($zip->numFiles)." files");
2238  return 1;
2239  }
2240 
2241  if (defined('ODTPHP_PATHTOPCLZIP')) {
2242  $foundhandler = 1;
2243 
2244  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2245  $archive = new PclZip($outputfile);
2246  $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2247 
2248  if ($result === 0) {
2249  global $errormsg;
2250  $errormsg = $archive->errorInfo(true);
2251 
2252  if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) {
2253  $errorstring = "PCLZIP_ERR_WRITE_OPEN_FAIL";
2254  dol_syslog("dol_compress_file error - archive->errorCode() = PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR);
2255  return -4;
2256  }
2257 
2258  $errorstring = "dol_compress_file error archive->errorCode = ".$archive->errorCode()." errormsg=".$errormsg;
2259  dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR);
2260  return -3;
2261  } else {
2262  dol_syslog("dol_compress_file success - ".count($result)." files");
2263  return 1;
2264  }
2265  }
2266  }
2267 
2268  if ($foundhandler) {
2269  $fp = fopen($outputfile, "w");
2270  fwrite($fp, $compressdata);
2271  fclose($fp);
2272  return 1;
2273  } else {
2274  $errorstring = "Try to zip with format ".$mode." with no handler for this format";
2275  dol_syslog($errorstring, LOG_ERR);
2276 
2277  global $errormsg;
2278  $errormsg = $errorstring;
2279  return -2;
2280  }
2281  } catch (Exception $e) {
2282  global $langs, $errormsg;
2283  $langs->load("errors");
2284  $errormsg = $langs->trans("ErrorFailedToWriteInDir");
2285 
2286  $errorstring = "Failed to open file ".$outputfile;
2287  dol_syslog($errorstring, LOG_ERR);
2288  return -1;
2289  }
2290 }
2291 
2300 function dol_uncompress($inputfile, $outputdir)
2301 {
2302  global $conf, $langs, $db;
2303 
2304  $fileinfo = pathinfo($inputfile);
2305  $fileinfo["extension"] = strtolower($fileinfo["extension"]);
2306 
2307  if ($fileinfo["extension"] == "zip") {
2308  if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS)) {
2309  dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
2310  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2311  $archive = new PclZip($inputfile);
2312 
2313  // We create output dir manually, so it uses the correct permission (When created by the archive->extract, dir is rwx for everybody).
2314  dol_mkdir(dol_sanitizePathName($outputdir));
2315 
2316  // Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
2317  $result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
2318 
2319  if (!is_array($result) && $result <= 0) {
2320  return array('error'=>$archive->errorInfo(true));
2321  } else {
2322  $ok = 1;
2323  $errmsg = '';
2324  // Loop on each file to check result for unzipping file
2325  foreach ($result as $key => $val) {
2326  if ($val['status'] == 'path_creation_fail') {
2327  $langs->load("errors");
2328  $ok = 0;
2329  $errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
2330  break;
2331  }
2332  }
2333 
2334  if ($ok) {
2335  return array();
2336  } else {
2337  return array('error'=>$errmsg);
2338  }
2339  }
2340  }
2341 
2342  if (class_exists('ZipArchive')) { // Must install php-zip to have it
2343  dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
2344  $zip = new ZipArchive;
2345  $res = $zip->open($inputfile);
2346  if ($res === true) {
2347  //$zip->extractTo($outputdir.'/');
2348  // We must extract one file at time so we can check that file name does not contain '..' to avoid transversal path of zip built for example using
2349  // python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
2350  // with -l is the range of dot to go back in path.
2351  // and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
2352  for ($i = 0; $i < $zip->numFiles; $i++) {
2353  if (preg_match('/\.\./', $zip->getNameIndex($i))) {
2354  dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
2355  continue; // Discard the file
2356  }
2357  $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
2358  }
2359 
2360  $zip->close();
2361  return array();
2362  } else {
2363  return array('error'=>'ErrUnzipFails');
2364  }
2365  }
2366 
2367  return array('error'=>'ErrNoZipEngine');
2368  } elseif (in_array($fileinfo["extension"], array('gz', 'bz2', 'zst'))) {
2369  include_once DOL_DOCUMENT_ROOT."/core/class/utils.class.php";
2370  $utils = new Utils($db);
2371 
2372  dol_mkdir(dol_sanitizePathName($outputdir));
2373  $outputfilename = escapeshellcmd(dol_sanitizePathName($outputdir).'/'.dol_sanitizeFileName($fileinfo["filename"]));
2374  dol_delete_file($outputfilename.'.tmp');
2375  dol_delete_file($outputfilename.'.err');
2376 
2377  $extension = strtolower(pathinfo($fileinfo["filename"], PATHINFO_EXTENSION));
2378  if ($extension == "tar") {
2379  $cmd = 'tar -C '.escapeshellcmd(dol_sanitizePathName($outputdir)).' -xvf '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2380 
2381  $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, $outputfilename.'.err', 0);
2382  if ($resarray["result"] != 0) {
2383  $resarray["error"] .= file_get_contents($outputfilename.'.err');
2384  }
2385  } else {
2386  $program = "";
2387  if ($fileinfo["extension"] == "gz") {
2388  $program = 'gzip';
2389  } elseif ($fileinfo["extension"] == "bz2") {
2390  $program = 'bzip2';
2391  } elseif ($fileinfo["extension"] == "zst") {
2392  $program = 'zstd';
2393  } else {
2394  return array('error'=>'ErrorBadFileExtension');
2395  }
2396  $cmd = $program.' -dc '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2397  $cmd .= ' > '.$outputfilename;
2398 
2399  $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, null, 1, $outputfilename.'.err');
2400  if ($resarray["result"] != 0) {
2401  $errfilecontent = @file_get_contents($outputfilename.'.err');
2402  if ($errfilecontent) {
2403  $resarray["error"] .= " - ".$errfilecontent;
2404  }
2405  }
2406  }
2407  return $resarray["result"] != 0 ? array('error' => $resarray["error"]) : array();
2408  }
2409 
2410  return array('error'=>'ErrorBadFileExtension');
2411 }
2412 
2413 
2426 function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '', $rootdirinzip = '', $newmask = 0)
2427 {
2428  global $conf;
2429 
2430  $foundhandler = 0;
2431 
2432  dol_syslog("Try to zip dir ".$inputdir." into ".$outputfile." mode=".$mode);
2433 
2434  if (!dol_is_dir(dirname($outputfile)) || !is_writable(dirname($outputfile))) {
2435  global $langs, $errormsg;
2436  $langs->load("errors");
2437  $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile);
2438  return -3;
2439  }
2440 
2441  try {
2442  if ($mode == 'gz') {
2443  $foundhandler = 0;
2444  } elseif ($mode == 'bz') {
2445  $foundhandler = 0;
2446  } elseif ($mode == 'zip') {
2447  /*if (defined('ODTPHP_PATHTOPCLZIP'))
2448  {
2449  $foundhandler=0; // TODO implement this
2450 
2451  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2452  $archive = new PclZip($outputfile);
2453  $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2454  //$archive->add($inputfile);
2455  return 1;
2456  }
2457  else*/
2458  //if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS))
2459 
2460  if (class_exists('ZipArchive')) {
2461  $foundhandler = 1;
2462 
2463  // Initialize archive object
2464  $zip = new ZipArchive();
2465  $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
2466  if ($result !== true) {
2467  global $langs, $errormsg;
2468  $langs->load("errors");
2469  $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile);
2470  return -4;
2471  }
2472 
2473  // Create recursive directory iterator
2474  // This does not return symbolic links
2476  $files = new RecursiveIteratorIterator(
2477  new RecursiveDirectoryIterator($inputdir),
2478  RecursiveIteratorIterator::LEAVES_ONLY
2479  );
2480 
2481  //var_dump($inputdir);
2482  foreach ($files as $name => $file) {
2483  // Skip directories (they would be added automatically)
2484  if (!$file->isDir()) {
2485  // Get real and relative path for current file
2486  $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2487  $fileName = $file->getFilename();
2488  $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2489 
2490  //$relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($fileFullRealPath, strlen($inputdir) + 1);
2491  $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr(($filePath ? $filePath.'/' : '').$fileName, strlen($inputdir) + 1);
2492 
2493  //var_dump($filePath);var_dump($fileFullRealPath);var_dump($relativePath);
2494  if (empty($excludefiles) || !preg_match($excludefiles, $fileFullRealPath)) {
2495  // Add current file to archive
2496  $zip->addFile($fileFullRealPath, $relativePath);
2497  }
2498  }
2499  }
2500 
2501  // Zip archive will be created only after closing object
2502  $zip->close();
2503 
2504  if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) {
2505  $newmask = $conf->global->MAIN_UMASK;
2506  }
2507  if (empty($newmask)) { // This should no happen
2508  dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
2509  $newmask = '0664';
2510  }
2511 
2512  dolChmod($outputfile, $newmask);
2513 
2514  return 1;
2515  }
2516  }
2517 
2518  if (!$foundhandler) {
2519  dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR);
2520  return -2;
2521  } else {
2522  return 0;
2523  }
2524  } catch (Exception $e) {
2525  global $langs, $errormsg;
2526  $langs->load("errors");
2527  dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
2528  dol_syslog($e->getMessage(), LOG_ERR);
2529  $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile).' - '.$e->getMessage();
2530  return -1;
2531  }
2532 }
2533 
2534 
2535 
2546 function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$', '^\.'), $nohook = false, $mode = '')
2547 {
2548  $tmparray = dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook);
2549  return isset($tmparray[0])?$tmparray[0]:null;
2550 }
2551 
2565 function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = '', $refname = '', $mode = 'read')
2566 {
2567  global $conf, $db, $user, $hookmanager;
2568  global $dolibarr_main_data_root, $dolibarr_main_document_root_alt;
2569  global $object;
2570 
2571  if (!is_object($fuser)) {
2572  $fuser = $user;
2573  }
2574 
2575  if (empty($modulepart)) {
2576  return 'ErrorBadParameter';
2577  }
2578  if (empty($entity)) {
2579  if (!isModEnabled('multicompany')) {
2580  $entity = 1;
2581  } else {
2582  $entity = 0;
2583  }
2584  }
2585  // Fix modulepart for backward compatibility
2586  if ($modulepart == 'users') {
2587  $modulepart = 'user';
2588  }
2589  if ($modulepart == 'tva') {
2590  $modulepart = 'tax-vat';
2591  }
2592  // Fix modulepart delivery
2593  if ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) {
2594  $modulepart = 'delivery';
2595  }
2596 
2597  //print 'dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity;
2598  dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
2599 
2600  // We define $accessallowed and $sqlprotectagainstexternals
2601  $accessallowed = 0;
2602  $sqlprotectagainstexternals = '';
2603  $ret = array();
2604 
2605  // Find the subdirectory name as the reference. For example original_file='10/myfile.pdf' -> refname='10'
2606  if (empty($refname)) {
2607  $refname = basename(dirname($original_file)."/");
2608  if ($refname == 'thumbs' || $refname == 'temp') {
2609  // If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10'
2610  $refname = basename(dirname(dirname($original_file))."/");
2611  }
2612  }
2613 
2614  // Define possible keys to use for permission check
2615  $lire = 'lire';
2616  $read = 'read';
2617  $download = 'download';
2618  if ($mode == 'write') {
2619  $lire = 'creer';
2620  $read = 'write';
2621  $download = 'upload';
2622  }
2623 
2624  // Wrapping for miscellaneous medias files
2625  if ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) {
2626  if (empty($entity) || empty($conf->medias->multidir_output[$entity])) {
2627  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2628  }
2629  $accessallowed = 1;
2630  $original_file = $conf->medias->multidir_output[$entity].'/'.$original_file;
2631  } elseif ($modulepart == 'logs' && !empty($dolibarr_main_data_root)) {
2632  // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
2633  $accessallowed = ($user->admin && basename($original_file) == $original_file && preg_match('/^dolibarr.*\.(log|json)$/', basename($original_file)));
2634  $original_file = $dolibarr_main_data_root.'/'.$original_file;
2635  } elseif ($modulepart == 'doctemplates' && !empty($dolibarr_main_data_root)) {
2636  // Wrapping for doctemplates
2637  $accessallowed = $user->admin;
2638  $original_file = $dolibarr_main_data_root.'/doctemplates/'.$original_file;
2639  } elseif ($modulepart == 'doctemplateswebsite' && !empty($dolibarr_main_data_root)) {
2640  // Wrapping for doctemplates of websites
2641  $accessallowed = ($fuser->rights->website->write && preg_match('/\.jpg$/i', basename($original_file)));
2642  $original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file;
2643  } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) {
2644  // Wrapping for *.zip package files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
2645  // Dir for custom dirs
2646  $tmp = explode(',', $dolibarr_main_document_root_alt);
2647  $dirins = $tmp[0];
2648 
2649  $accessallowed = ($user->admin && preg_match('/^module_.*\.zip$/', basename($original_file)));
2650  $original_file = $dirins.'/'.$original_file;
2651  } elseif ($modulepart == 'mycompany' && !empty($conf->mycompany->dir_output)) {
2652  // Wrapping for some images
2653  $accessallowed = 1;
2654  $original_file = $conf->mycompany->dir_output.'/'.$original_file;
2655  } elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output)) {
2656  // Wrapping for users photos (user photos are allowed to any connected users)
2657  $accessallowed = 0;
2658  if (preg_match('/^\d+\/photos\//', $original_file)) {
2659  $accessallowed = 1;
2660  }
2661  $original_file = $conf->user->dir_output.'/'.$original_file;
2662  } elseif ($modulepart == 'userphotopublic' && !empty($conf->user->dir_output)) {
2663  // Wrapping for users photos that were set to public by their owner (public user photos can be read with the public link and securekey)
2664  $accessok = false;
2665  $reg = array();
2666  if (preg_match('/^(\d+)\/photos\//', $original_file, $reg)) {
2667  if ($reg[1]) {
2668  $tmpobject = new User($db);
2669  $tmpobject->fetch($reg[1], '', '', 1);
2670  if (getDolUserInt('USER_ENABLE_PUBLIC', 0, $tmpobject)) {
2671  $securekey = GETPOST('securekey', 'alpha', 1);
2672  // Security check
2673  global $dolibarr_main_cookie_cryptkey, $dolibarr_main_instance_unique_id;
2674  $valuetouse = $dolibarr_main_instance_unique_id ? $dolibarr_main_instance_unique_id : $dolibarr_main_cookie_cryptkey; // Use $dolibarr_main_instance_unique_id first then $dolibarr_main_cookie_cryptkey
2675  $encodedsecurekey = dol_hash($valuetouse.'uservirtualcard'.$tmpobject->id.'-'.$tmpobject->login, 'md5');
2676  if ($encodedsecurekey == $securekey) {
2677  $accessok = true;
2678  }
2679  }
2680  }
2681  }
2682  if ($accessok) {
2683  $accessallowed = 1;
2684  }
2685  $original_file = $conf->user->dir_output.'/'.$original_file;
2686  } elseif (($modulepart == 'companylogo') && !empty($conf->mycompany->dir_output)) {
2687  // Wrapping for company logos (company logos are allowed to anyboby, they are public)
2688  $accessallowed = 1;
2689  $original_file = $conf->mycompany->dir_output.'/logos/'.$original_file;
2690  } elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output)) {
2691  // Wrapping for members photos
2692  $accessallowed = 0;
2693  if (preg_match('/^\d+\/photos\//', $original_file)) {
2694  $accessallowed = 1;
2695  }
2696  $original_file = $conf->adherent->dir_output.'/'.$original_file;
2697  } elseif ($modulepart == 'apercufacture' && !empty($conf->facture->multidir_output[$entity])) {
2698  // Wrapping for invoices (user need permission to read invoices)
2699  if ($fuser->hasRight('facture', $lire)) {
2700  $accessallowed = 1;
2701  }
2702  $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2703  } elseif ($modulepart == 'apercupropal' && !empty($conf->propal->multidir_output[$entity])) {
2704  // Wrapping pour les apercu propal
2705  if ($fuser->hasRight('propal', $lire)) {
2706  $accessallowed = 1;
2707  }
2708  $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
2709  } elseif ($modulepart == 'apercucommande' && !empty($conf->commande->multidir_output[$entity])) {
2710  // Wrapping pour les apercu commande
2711  if ($fuser->hasRight('commande', $lire)) {
2712  $accessallowed = 1;
2713  }
2714  $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
2715  } elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output)) {
2716  // Wrapping pour les apercu intervention
2717  if ($fuser->hasRight('ficheinter', $lire)) {
2718  $accessallowed = 1;
2719  }
2720  $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2721  } elseif (($modulepart == 'apercucontract') && !empty($conf->contrat->multidir_output[$entity])) {
2722  // Wrapping pour les apercu contrat
2723  if ($fuser->hasRight('contrat', $lire)) {
2724  $accessallowed = 1;
2725  }
2726  $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
2727  } elseif (($modulepart == 'apercusupplier_proposal' || $modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output)) {
2728  // Wrapping pour les apercu supplier proposal
2729  if ($fuser->hasRight('supplier_proposal', $lire)) {
2730  $accessallowed = 1;
2731  }
2732  $original_file = $conf->supplier_proposal->dir_output.'/'.$original_file;
2733  } elseif (($modulepart == 'apercusupplier_order' || $modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output)) {
2734  // Wrapping pour les apercu supplier order
2735  if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2736  $accessallowed = 1;
2737  }
2738  $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
2739  } elseif (($modulepart == 'apercusupplier_invoice' || $modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output)) {
2740  // Wrapping pour les apercu supplier invoice
2741  if ($fuser->hasRight('fournisseur', $lire)) {
2742  $accessallowed = 1;
2743  }
2744  $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
2745  } elseif (($modulepart == 'holiday') && !empty($conf->holiday->dir_output)) {
2746  if ($fuser->hasRight('holiday', $read) || !empty($fuser->rights->holiday->readall) || preg_match('/^specimen/i', $original_file)) {
2747  $accessallowed = 1;
2748  // If we known $id of holiday, call checkUserAccessToObject to check permission on properties and hierarchy of leave request
2749  if ($refname && empty($fuser->rights->holiday->readall) && !preg_match('/^specimen/i', $original_file)) {
2750  include_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
2751  $tmpholiday = new Holiday($db);
2752  $tmpholiday->fetch('', $refname);
2753  $accessallowed = checkUserAccessToObject($user, array('holiday'), $tmpholiday, 'holiday', '', '', 'rowid', '');
2754  }
2755  }
2756  $original_file = $conf->holiday->dir_output.'/'.$original_file;
2757  } elseif (($modulepart == 'expensereport') && !empty($conf->expensereport->dir_output)) {
2758  if ($fuser->hasRight('expensereport', $lire) || !empty($fuser->rights->expensereport->readall) || preg_match('/^specimen/i', $original_file)) {
2759  $accessallowed = 1;
2760  // If we known $id of expensereport, call checkUserAccessToObject to check permission on properties and hierarchy of expense report
2761  if ($refname && empty($fuser->rights->expensereport->readall) && !preg_match('/^specimen/i', $original_file)) {
2762  include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
2763  $tmpexpensereport = new ExpenseReport($db);
2764  $tmpexpensereport->fetch('', $refname);
2765  $accessallowed = checkUserAccessToObject($user, array('expensereport'), $tmpexpensereport, 'expensereport', '', '', 'rowid', '');
2766  }
2767  }
2768  $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2769  } elseif (($modulepart == 'apercuexpensereport') && !empty($conf->expensereport->dir_output)) {
2770  // Wrapping pour les apercu expense report
2771  if ($fuser->hasRight('expensereport', $lire)) {
2772  $accessallowed = 1;
2773  }
2774  $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2775  } elseif ($modulepart == 'propalstats' && !empty($conf->propal->multidir_temp[$entity])) {
2776  // Wrapping pour les images des stats propales
2777  if ($fuser->hasRight('propal', $lire)) {
2778  $accessallowed = 1;
2779  }
2780  $original_file = $conf->propal->multidir_temp[$entity].'/'.$original_file;
2781  } elseif ($modulepart == 'orderstats' && !empty($conf->commande->dir_temp)) {
2782  // Wrapping pour les images des stats commandes
2783  if ($fuser->hasRight('commande', $lire)) {
2784  $accessallowed = 1;
2785  }
2786  $original_file = $conf->commande->dir_temp.'/'.$original_file;
2787  } elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2788  if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2789  $accessallowed = 1;
2790  }
2791  $original_file = $conf->fournisseur->commande->dir_temp.'/'.$original_file;
2792  } elseif ($modulepart == 'billstats' && !empty($conf->facture->dir_temp)) {
2793  // Wrapping pour les images des stats factures
2794  if ($fuser->hasRight('facture', $lire)) {
2795  $accessallowed = 1;
2796  }
2797  $original_file = $conf->facture->dir_temp.'/'.$original_file;
2798  } elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2799  if ($fuser->hasRight('fournisseur', 'facture', $lire)) {
2800  $accessallowed = 1;
2801  }
2802  $original_file = $conf->fournisseur->facture->dir_temp.'/'.$original_file;
2803  } elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp)) {
2804  // Wrapping pour les images des stats expeditions
2805  if ($fuser->hasRight('expedition', $lire)) {
2806  $accessallowed = 1;
2807  }
2808  $original_file = $conf->expedition->dir_temp.'/'.$original_file;
2809  } elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp)) {
2810  // Wrapping pour les images des stats expeditions
2811  if ($fuser->hasRight('deplacement', $lire)) {
2812  $accessallowed = 1;
2813  }
2814  $original_file = $conf->deplacement->dir_temp.'/'.$original_file;
2815  } elseif ($modulepart == 'memberstats' && !empty($conf->adherent->dir_temp)) {
2816  // Wrapping pour les images des stats expeditions
2817  if ($fuser->hasRight('adherent', $lire)) {
2818  $accessallowed = 1;
2819  }
2820  $original_file = $conf->adherent->dir_temp.'/'.$original_file;
2821  } elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) {
2822  // Wrapping pour les images des stats produits
2823  if ($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) {
2824  $accessallowed = 1;
2825  }
2826  $original_file = (!empty($conf->product->multidir_temp[$entity]) ? $conf->product->multidir_temp[$entity] : $conf->service->multidir_temp[$entity]).'/'.$original_file;
2827  } elseif (in_array($modulepart, array('tax', 'tax-vat', 'tva')) && !empty($conf->tax->dir_output)) {
2828  // Wrapping for taxes
2829  if ($fuser->hasRight('tax', 'charges', $lire)) {
2830  $accessallowed = 1;
2831  }
2832  $modulepartsuffix = str_replace('tax-', '', $modulepart);
2833  $original_file = $conf->tax->dir_output.'/'.($modulepartsuffix != 'tax' ? $modulepartsuffix.'/' : '').$original_file;
2834  } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
2835  // Wrapping for events
2836  if ($fuser->hasRight('agenda', 'myactions', $read)) {
2837  $accessallowed = 1;
2838  // If we known $id of project, call checkUserAccessToObject to check permission on the given agenda event on properties and assigned users
2839  if ($refname && !preg_match('/^specimen/i', $original_file)) {
2840  include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
2841  $tmpobject = new ActionComm($db);
2842  $tmpobject->fetch((int) $refname);
2843  $accessallowed = checkUserAccessToObject($user, array('agenda'), $tmpobject->id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id', '');
2844  if ($user->socid && $tmpobject->socid) {
2845  $accessallowed = checkUserAccessToObject($user, array('societe'), $tmpobject->socid);
2846  }
2847  }
2848  }
2849  $original_file = $conf->agenda->dir_output.'/'.$original_file;
2850  } elseif ($modulepart == 'category' && !empty($conf->categorie->multidir_output[$entity])) {
2851  // Wrapping for categories (categories are allowed if user has permission to read categories or to work on TakePos)
2852  if (empty($entity) || empty($conf->categorie->multidir_output[$entity])) {
2853  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2854  }
2855  if ($fuser->hasRight("categorie", $lire) || $fuser->hasRight("takepos", "run")) {
2856  $accessallowed = 1;
2857  }
2858  $original_file = $conf->categorie->multidir_output[$entity].'/'.$original_file;
2859  } elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) {
2860  // Wrapping pour les prelevements
2861  if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i', $original_file)) {
2862  $accessallowed = 1;
2863  }
2864  $original_file = $conf->prelevement->dir_output.'/'.$original_file;
2865  } elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp)) {
2866  // Wrapping pour les graph energie
2867  $accessallowed = 1;
2868  $original_file = $conf->stock->dir_temp.'/'.$original_file;
2869  } elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp)) {
2870  // Wrapping pour les graph fournisseurs
2871  $accessallowed = 1;
2872  $original_file = $conf->fournisseur->dir_temp.'/'.$original_file;
2873  } elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp)) {
2874  // Wrapping pour les graph des produits
2875  $accessallowed = 1;
2876  $original_file = $conf->product->multidir_temp[$entity].'/'.$original_file;
2877  } elseif ($modulepart == 'barcode') {
2878  // Wrapping pour les code barre
2879  $accessallowed = 1;
2880  // If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
2881  //$original_file=$conf->barcode->dir_temp.'/'.$original_file;
2882  $original_file = '';
2883  } elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp)) {
2884  // Wrapping pour les icones de background des mailings
2885  $accessallowed = 1;
2886  $original_file = $conf->mailing->dir_temp.'/'.$original_file;
2887  } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
2888  // Wrapping pour le scanner
2889  $accessallowed = 1;
2890  $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
2891  } elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output)) {
2892  // Wrapping pour les images fckeditor
2893  $accessallowed = 1;
2894  $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
2895  } elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) {
2896  // Wrapping for users
2897  $canreaduser = (!empty($fuser->admin) || $fuser->rights->user->user->{$lire});
2898  if ($fuser->id == (int) $refname) {
2899  $canreaduser = 1;
2900  } // A user can always read its own card
2901  if ($canreaduser || preg_match('/^specimen/i', $original_file)) {
2902  $accessallowed = 1;
2903  }
2904  $original_file = $conf->user->dir_output.'/'.$original_file;
2905  } elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->multidir_output[$entity])) {
2906  // Wrapping for third parties
2907  if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
2908  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2909  }
2910  if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i', $original_file)) {
2911  $accessallowed = 1;
2912  }
2913  $original_file = $conf->societe->multidir_output[$entity].'/'.$original_file;
2914  $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe').")";
2915  } elseif ($modulepart == 'contact' && !empty($conf->societe->multidir_output[$entity])) {
2916  // Wrapping for contact
2917  if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
2918  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2919  }
2920  if ($fuser->hasRight('societe', $lire)) {
2921  $accessallowed = 1;
2922  }
2923  $original_file = $conf->societe->multidir_output[$entity].'/contact/'.$original_file;
2924  } elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->multidir_output[$entity])) {
2925  // Wrapping for invoices
2926  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2927  $accessallowed = 1;
2928  }
2929  $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2930  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('invoice').")";
2931  } elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) {
2932  // Wrapping for mass actions
2933  if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
2934  $accessallowed = 1;
2935  }
2936  $original_file = $conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2937  } elseif ($modulepart == 'massfilesarea_orders') {
2938  if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
2939  $accessallowed = 1;
2940  }
2941  $original_file = $conf->commande->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2942  } elseif ($modulepart == 'massfilesarea_sendings') {
2943  if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
2944  $accessallowed = 1;
2945  }
2946  $original_file = $conf->expedition->dir_output.'/sending/temp/massgeneration/'.$user->id.'/'.$original_file;
2947  } elseif ($modulepart == 'massfilesarea_invoices') {
2948  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2949  $accessallowed = 1;
2950  }
2951  $original_file = $conf->facture->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2952  } elseif ($modulepart == 'massfilesarea_expensereport') {
2953  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2954  $accessallowed = 1;
2955  }
2956  $original_file = $conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2957  } elseif ($modulepart == 'massfilesarea_interventions') {
2958  if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
2959  $accessallowed = 1;
2960  }
2961  $original_file = $conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2962  } elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) {
2963  if ($fuser->hasRight('supplier_proposal', $lire) || preg_match('/^specimen/i', $original_file)) {
2964  $accessallowed = 1;
2965  }
2966  $original_file = $conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2967  } elseif ($modulepart == 'massfilesarea_supplier_order') {
2968  if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
2969  $accessallowed = 1;
2970  }
2971  $original_file = $conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2972  } elseif ($modulepart == 'massfilesarea_supplier_invoice') {
2973  if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2974  $accessallowed = 1;
2975  }
2976  $original_file = $conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2977  } elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) {
2978  if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
2979  $accessallowed = 1;
2980  }
2981  $original_file = $conf->contrat->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2982  } elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) {
2983  // Wrapping for interventions
2984  if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
2985  $accessallowed = 1;
2986  }
2987  $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2988  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2989  } elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) {
2990  // Wrapping pour les deplacements et notes de frais
2991  if ($fuser->hasRight('deplacement', $lire) || preg_match('/^specimen/i', $original_file)) {
2992  $accessallowed = 1;
2993  }
2994  $original_file = $conf->deplacement->dir_output.'/'.$original_file;
2995  //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2996  } elseif (($modulepart == 'propal' || $modulepart == 'propale') && isset($conf->propal->multidir_output[$entity])) {
2997  // Wrapping pour les propales
2998  if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
2999  $accessallowed = 1;
3000  }
3001  $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
3002  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('propal').")";
3003  } elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->multidir_output[$entity])) {
3004  // Wrapping pour les commandes
3005  if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) {
3006  $accessallowed = 1;
3007  }
3008  $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
3009  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")";
3010  } elseif ($modulepart == 'project' && !empty($conf->project->multidir_output[$entity])) {
3011  // Wrapping pour les projets
3012  if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3013  $accessallowed = 1;
3014  // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3015  if ($refname && !preg_match('/^specimen/i', $original_file)) {
3016  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
3017  $tmpproject = new Project($db);
3018  $tmpproject->fetch('', $refname);
3019  $accessallowed = checkUserAccessToObject($user, array('projet'), $tmpproject->id, 'projet&project', '', '', 'rowid', '');
3020  }
3021  }
3022  $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3023  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3024  } elseif ($modulepart == 'project_task' && !empty($conf->project->multidir_output[$entity])) {
3025  if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3026  $accessallowed = 1;
3027  // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3028  if ($refname && !preg_match('/^specimen/i', $original_file)) {
3029  include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
3030  $tmptask = new Task($db);
3031  $tmptask->fetch('', $refname);
3032  $accessallowed = checkUserAccessToObject($user, array('projet_task'), $tmptask->id, 'projet_task&project', '', '', 'rowid', '');
3033  }
3034  }
3035  $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3036  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3037  } elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) {
3038  // Wrapping pour les commandes fournisseurs
3039  if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) {
3040  $accessallowed = 1;
3041  }
3042  $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
3043  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3044  } elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) {
3045  // Wrapping pour les factures fournisseurs
3046  if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) {
3047  $accessallowed = 1;
3048  }
3049  $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
3050  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3051  } elseif ($modulepart == 'supplier_payment') {
3052  // Wrapping pour les rapport de paiements
3053  if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) {
3054  $accessallowed = 1;
3055  }
3056  $original_file = $conf->fournisseur->payment->dir_output.'/'.$original_file;
3057  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3058  } elseif ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) {
3059  // Wrapping pour les rapport de paiements
3060  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3061  $accessallowed = 1;
3062  }
3063  if ($fuser->socid > 0) {
3064  $original_file = $conf->facture->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file;
3065  } else {
3066  $original_file = $conf->facture->dir_output.'/payments/'.$original_file;
3067  }
3068  } elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) {
3069  // Wrapping for accounting exports
3070  if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i', $original_file)) {
3071  $accessallowed = 1;
3072  }
3073  $original_file = $conf->accounting->dir_output.'/'.$original_file;
3074  } elseif (($modulepart == 'expedition' || $modulepart == 'shipment') && !empty($conf->expedition->dir_output)) {
3075  // Wrapping pour les expedition
3076  if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
3077  $accessallowed = 1;
3078  }
3079  $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'sending/') === 0 ? '' : 'sending/').$original_file;
3080  //$original_file = $conf->expedition->dir_output."/".$original_file;
3081  } elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output)) {
3082  // Delivery Note Wrapping
3083  if ($fuser->hasRight('expedition', 'delivery', $lire) || preg_match('/^specimen/i', $original_file)) {
3084  $accessallowed = 1;
3085  }
3086  $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'receipt/') === 0 ? '' : 'receipt/').$original_file;
3087  } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
3088  // Wrapping pour les actions
3089  if ($fuser->hasRight('agenda', 'myactions', $read) || preg_match('/^specimen/i', $original_file)) {
3090  $accessallowed = 1;
3091  }
3092  $original_file = $conf->agenda->dir_output.'/'.$original_file;
3093  } elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) {
3094  // Wrapping pour les actions
3095  if ($fuser->hasRight('agenda', 'allactions', $read) || preg_match('/^specimen/i', $original_file)) {
3096  $accessallowed = 1;
3097  }
3098  $original_file = $conf->agenda->dir_temp."/".$original_file;
3099  } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
3100  // Wrapping pour les produits et services
3101  if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) {
3102  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3103  }
3104  if (($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) || preg_match('/^specimen/i', $original_file)) {
3105  $accessallowed = 1;
3106  }
3107  if (isModEnabled("product")) {
3108  $original_file = $conf->product->multidir_output[$entity].'/'.$original_file;
3109  } elseif (isModEnabled("service")) {
3110  $original_file = $conf->service->multidir_output[$entity].'/'.$original_file;
3111  }
3112  } elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') {
3113  // Wrapping pour les lots produits
3114  if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) {
3115  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3116  }
3117  if (($fuser->hasRight('produit', $lire)) || preg_match('/^specimen/i', $original_file)) {
3118  $accessallowed = 1;
3119  }
3120  if (isModEnabled('productbatch')) {
3121  $original_file = $conf->productbatch->multidir_output[$entity].'/'.$original_file;
3122  }
3123  } elseif ($modulepart == 'movement' || $modulepart == 'mouvement') {
3124  // Wrapping for stock movements
3125  if (empty($entity) || empty($conf->stock->multidir_output[$entity])) {
3126  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3127  }
3128  if (($fuser->hasRight('stock', $lire) || $fuser->hasRight('stock', 'movement', $lire) || $fuser->hasRight('stock', 'mouvement', $lire)) || preg_match('/^specimen/i', $original_file)) {
3129  $accessallowed = 1;
3130  }
3131  if (isModEnabled('stock')) {
3132  $original_file = $conf->stock->multidir_output[$entity].'/movement/'.$original_file;
3133  }
3134  } elseif ($modulepart == 'contract' && !empty($conf->contrat->multidir_output[$entity])) {
3135  // Wrapping pour les contrats
3136  if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) {
3137  $accessallowed = 1;
3138  }
3139  $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
3140  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract').")";
3141  } elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) {
3142  // Wrapping pour les dons
3143  if ($fuser->hasRight('don', $lire) || preg_match('/^specimen/i', $original_file)) {
3144  $accessallowed = 1;
3145  }
3146  $original_file = $conf->don->dir_output.'/'.$original_file;
3147  } elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) {
3148  // Wrapping pour les dons
3149  if ($fuser->hasRight('resource', $read) || preg_match('/^specimen/i', $original_file)) {
3150  $accessallowed = 1;
3151  }
3152  $original_file = $conf->resource->dir_output.'/'.$original_file;
3153  } elseif (($modulepart == 'remisecheque' || $modulepart == 'chequereceipt') && !empty($conf->bank->dir_output)) {
3154  // Wrapping pour les remises de cheques
3155  if ($fuser->hasRight('banque', $lire) || preg_match('/^specimen/i', $original_file)) {
3156  $accessallowed = 1;
3157  }
3158 
3159  $original_file = $conf->bank->dir_output.'/checkdeposits/'.$original_file; // original_file should contains relative path so include the get_exdir result
3160  } elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) {
3161  // Wrapping for bank
3162  if ($fuser->hasRight('banque', $lire)) {
3163  $accessallowed = 1;
3164  }
3165  $original_file = $conf->bank->dir_output.'/'.$original_file;
3166  } elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) {
3167  // Wrapping for export module
3168  // Note that a test may not be required because we force the dir of download on the directory of the user that export
3169  $accessallowed = $user->rights->export->lire;
3170  $original_file = $conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file;
3171  } elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) {
3172  // Wrapping for import module
3173  $accessallowed = $user->rights->import->run;
3174  $original_file = $conf->import->dir_temp.'/'.$original_file;
3175  } elseif ($modulepart == 'recruitment' && !empty($conf->recruitment->dir_output)) {
3176  // Wrapping for recruitment module
3177  $accessallowed = $user->hasRight('recruitment', 'recruitmentjobposition', 'read');
3178  $original_file = $conf->recruitment->dir_output.'/'.$original_file;
3179  } elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) {
3180  // Wrapping for wysiwyg editor
3181  $accessallowed = 1;
3182  $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
3183  } elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) {
3184  // Wrapping for backups
3185  if ($fuser->admin) {
3186  $accessallowed = 1;
3187  }
3188  $original_file = $conf->admin->dir_output.'/'.$original_file;
3189  } elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) {
3190  // Wrapping for upload file test
3191  if ($fuser->admin) {
3192  $accessallowed = 1;
3193  }
3194  $original_file = $conf->admin->dir_temp.'/'.$original_file;
3195  } elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) {
3196  // Wrapping pour BitTorrent
3197  $accessallowed = 1;
3198  $dir = 'files';
3199  if (dol_mimetype($original_file) == 'application/x-bittorrent') {
3200  $dir = 'torrents';
3201  }
3202  $original_file = $conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
3203  } elseif ($modulepart == 'member' && !empty($conf->adherent->dir_output)) {
3204  // Wrapping pour Foundation module
3205  if ($fuser->hasRight('adherent', $lire) || preg_match('/^specimen/i', $original_file)) {
3206  $accessallowed = 1;
3207  }
3208  $original_file = $conf->adherent->dir_output.'/'.$original_file;
3209  } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
3210  // Wrapping for Scanner
3211  $accessallowed = 1;
3212  $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
3213  // If modulepart=module_user_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser
3214  // If modulepart=module_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp
3215  // If modulepart=module_user Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser
3216  // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3217  // If modulepart=module-abc Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3218  } else {
3219  // GENERIC Wrapping
3220  //var_dump($modulepart);
3221  //var_dump($original_file);
3222  if (preg_match('/^specimen/i', $original_file)) {
3223  $accessallowed = 1; // If link to a file called specimen. Test must be done before changing $original_file int full path.
3224  }
3225  if ($fuser->admin) {
3226  $accessallowed = 1; // If user is admin
3227  }
3228 
3229  $tmpmodulepart = explode('-', $modulepart);
3230  if (!empty($tmpmodulepart[1])) {
3231  $modulepart = $tmpmodulepart[0];
3232  $original_file = $tmpmodulepart[1].'/'.$original_file;
3233  }
3234 
3235  // Define $accessallowed
3236  $reg = array();
3237  if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) {
3238  $tmpmodule = $reg[1];
3239  if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3240  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3241  exit;
3242  }
3243  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3244  $accessallowed = 1;
3245  }
3246  $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
3247  } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) {
3248  $tmpmodule = $reg[1];
3249  if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3250  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3251  exit;
3252  }
3253  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3254  $accessallowed = 1;
3255  }
3256  $original_file = $conf->$tmpmodule->dir_temp.'/'.$original_file;
3257  } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) {
3258  $tmpmodule = $reg[1];
3259  if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3260  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3261  exit;
3262  }
3263  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3264  $accessallowed = 1;
3265  }
3266  $original_file = $conf->$tmpmodule->dir_output.'/'.$fuser->id.'/'.$original_file;
3267  } elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) {
3268  $tmpmodule = $reg[1];
3269  if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3270  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3271  exit;
3272  }
3273  if ($fuser->hasRight($tmpmodule, $lire) || preg_match('/^specimen/i', $original_file)) {
3274  $accessallowed = 1;
3275  }
3276  $original_file = $conf->$tmpmodule->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3277  } else {
3278  if (empty($conf->$modulepart->dir_output)) { // modulepart not supported
3279  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.'). The module for this modulepart value may not be activated.');
3280  exit;
3281  }
3282 
3283  // Check fuser->rights->modulepart->myobject->read and fuser->rights->modulepart->read
3284  $partsofdirinoriginalfile = explode('/', $original_file);
3285  if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use)
3286  $partofdirinoriginalfile = $partsofdirinoriginalfile[0];
3287  if ($partofdirinoriginalfile && ($fuser->hasRight($modulepart, $partofdirinoriginalfile, 'lire') || $fuser->hasRight($modulepart, $partofdirinoriginalfile, 'read'))) {
3288  $accessallowed = 1;
3289  }
3290  }
3291  if ($fuser->hasRight($modulepart, $lire) || $fuser->hasRight($modulepart, $read)) {
3292  $accessallowed = 1;
3293  }
3294 
3295  if (is_array($conf->$modulepart->multidir_output) && !empty($conf->$modulepart->multidir_output[$entity])) {
3296  $original_file = $conf->$modulepart->multidir_output[$entity].'/'.$original_file;
3297  } else {
3298  $original_file = $conf->$modulepart->dir_output.'/'.$original_file;
3299  }
3300  }
3301 
3302  $parameters = array(
3303  'modulepart' => $modulepart,
3304  'original_file' => $original_file,
3305  'entity' => $entity,
3306  'fuser' => $fuser,
3307  'refname' => '',
3308  'mode' => $mode
3309  );
3310  $reshook = $hookmanager->executeHooks('checkSecureAccess', $parameters, $object);
3311  if ($reshook > 0) {
3312  if (!empty($hookmanager->resArray['original_file'])) {
3313  $original_file = $hookmanager->resArray['original_file'];
3314  }
3315  if (!empty($hookmanager->resArray['accessallowed'])) {
3316  $accessallowed = $hookmanager->resArray['accessallowed'];
3317  }
3318  if (!empty($hookmanager->resArray['sqlprotectagainstexternals'])) {
3319  $sqlprotectagainstexternals = $hookmanager->resArray['sqlprotectagainstexternals'];
3320  }
3321  }
3322  }
3323 
3324  $ret = array(
3325  'accessallowed' => ($accessallowed ? 1 : 0),
3326  'sqlprotectagainstexternals' => $sqlprotectagainstexternals,
3327  'original_file' => $original_file
3328  );
3329 
3330  return $ret;
3331 }
3332 
3341 function dol_filecache($directory, $filename, $object)
3342 {
3343  if (!dol_is_dir($directory)) {
3344  dol_mkdir($directory);
3345  }
3346  $cachefile = $directory.$filename;
3347  file_put_contents($cachefile, serialize($object), LOCK_EX);
3348  dolChmod($cachefile, '0644');
3349 }
3350 
3359 function dol_cache_refresh($directory, $filename, $cachetime)
3360 {
3361  $now = dol_now();
3362  $cachefile = $directory.$filename;
3363  $refresh = !file_exists($cachefile) || ($now - $cachetime) > dol_filemtime($cachefile);
3364  return $refresh;
3365 }
3366 
3374 function dol_readcachefile($directory, $filename)
3375 {
3376  $cachefile = $directory.$filename;
3377  $object = unserialize(file_get_contents($cachefile));
3378  return $object;
3379 }
3380 
3387 function dirbasename($pathfile)
3388 {
3389  return preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'\//', '', $pathfile);
3390 }
3391 
3392 
3404 function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
3405 {
3406  global $conffile;
3407 
3408  $exclude = 'install';
3409 
3410  foreach ($dir->md5file as $file) { // $file is a simpleXMLElement
3411  $filename = $path.$file['name'];
3412  $file_list['insignature'][] = $filename;
3413  $expectedsize = (empty($file['size']) ? '' : $file['size']);
3414  $expectedmd5 = (string) $file;
3415 
3416  //if (preg_match('#'.$exclude.'#', $filename)) continue;
3417 
3418  if (!file_exists($pathref.'/'.$filename)) {
3419  $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize);
3420  } else {
3421  $md5_local = md5_file($pathref.'/'.$filename);
3422 
3423  if ($conffile == '/etc/dolibarr/conf.php' && $filename == '/filefunc.inc.php') { // For install with deb or rpm, we ignore test on filefunc.inc.php that was modified by package
3424  $checksumconcat[] = $expectedmd5;
3425  } else {
3426  if ($md5_local != $expectedmd5) {
3427  $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize, 'md5'=>(string) $md5_local);
3428  }
3429  $checksumconcat[] = $md5_local;
3430  }
3431  }
3432  }
3433 
3434  foreach ($dir->dir as $subdir) { // $subdir['name'] is '' or '/accountancy/admin' for example
3435  getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat);
3436  }
3437 
3438  return $file_list;
3439 }
3440 
3448 function dragAndDropFileUpload($htmlname)
3449 {
3450  global $object, $langs;
3451 
3452  $out = "";
3453  $out .= '<div id="'.$htmlname.'Message" class="dragDropAreaMessage hidden"><span>'.img_picto("", 'download').'<br>'.$langs->trans("DropFileToAddItToObject").'</span></div>';
3454  $out .= "\n<!-- JS CODE TO ENABLE DRAG AND DROP OF FILE -->\n";
3455  $out .= "<script>";
3456  $out .= '
3457  jQuery(document).ready(function() {
3458  var enterTargetDragDrop = null;
3459 
3460  $("#'.$htmlname.'").addClass("cssDragDropArea");
3461 
3462  $(".cssDragDropArea").on("dragenter", function(ev, ui) {
3463  var dataTransfer = ev.originalEvent.dataTransfer;
3464  var dataTypes = dataTransfer.types;
3465  //console.log(dataTransfer);
3466  //console.log(dataTypes);
3467 
3468  if (!dataTypes || ($.inArray(\'Files\', dataTypes) === -1)) {
3469  // The element dragged is not a file, so we avoid the "dragenter"
3470  ev.preventDefault();
3471  return false;
3472  }
3473 
3474  // Entering drop area. Highlight area
3475  console.log("dragAndDropFileUpload: We add class highlightDragDropArea")
3476  enterTargetDragDrop = ev.target;
3477  $(this).addClass("highlightDragDropArea");
3478  $("#'.$htmlname.'Message").removeClass("hidden");
3479  ev.preventDefault();
3480  });
3481 
3482  $(".cssDragDropArea").on("dragleave", function(ev) {
3483  // Going out of drop area. Remove Highlight
3484  if (enterTargetDragDrop == ev.target){
3485  console.log("dragAndDropFileUpload: We remove class highlightDragDropArea")
3486  $("#'.$htmlname.'Message").addClass("hidden");
3487  $(this).removeClass("highlightDragDropArea");
3488  }
3489  });
3490 
3491  $(".cssDragDropArea").on("dragover", function(ev) {
3492  ev.preventDefault();
3493  return false;
3494  });
3495 
3496  $(".cssDragDropArea").on("drop", function(e) {
3497  console.log("Trigger event file dropped. fk_element='.dol_escape_js($object->id).' element='.dol_escape_js($object->element).'");
3498  e.preventDefault();
3499  fd = new FormData();
3500  fd.append("fk_element", "'.dol_escape_js($object->id).'");
3501  fd.append("element", "'.dol_escape_js($object->element).'");
3502  fd.append("token", "'.currentToken().'");
3503  fd.append("action", "linkit");
3504 
3505  var dataTransfer = e.originalEvent.dataTransfer;
3506 
3507  if (dataTransfer.files && dataTransfer.files.length){
3508  var droppedFiles = e.originalEvent.dataTransfer.files;
3509  $.each(droppedFiles, function(index,file){
3510  fd.append("files[]", file,file.name)
3511  });
3512  }
3513  $(".cssDragDropArea").removeClass("highlightDragDropArea");
3514  counterdragdrop = 0;
3515  $.ajax({
3516  url: "'.DOL_URL_ROOT.'/core/ajax/fileupload.php",
3517  type: "POST",
3518  processData: false,
3519  contentType: false,
3520  data: fd,
3521  success:function() {
3522  console.log("Uploaded.", arguments);
3523  /* arguments[0] is the json string of files */
3524  /* arguments[1] is the value for variable "success", can be 0 or 1 */
3525  let listoffiles = JSON.parse(arguments[0]);
3526  console.log(listoffiles);
3527  let nboferror = 0;
3528  for (let i = 0; i < listoffiles.length; i++) {
3529  console.log(listoffiles[i].error);
3530  if (listoffiles[i].error) {
3531  nboferror++;
3532  }
3533  }
3534  console.log(nboferror);
3535  if (nboferror > 0) {
3536  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorOnAtLeastOneFileUpload:warnings";
3537  } else {
3538  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=UploadFileDragDropSuccess:mesgs";
3539  }
3540  },
3541  error:function() {
3542  console.log("Error Uploading.", arguments)
3543  if (arguments[0].status == 403) {
3544  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadPermissionDenied:errors";
3545  }
3546  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadFileDragDropPermissionDenied:errors";
3547  },
3548  })
3549  });
3550  });
3551  ';
3552  $out .= "</script>\n";
3553  return $out;
3554 }
Class to manage agenda events (actions)
Class to scan for virus.
Class to manage ECM files.
Class to manage Trips and Expenses.
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Class of the module paid holiday.
Class to manage projects.
Class to manage tasks.
Definition: task.class.php:40
Class to manage Dolibarr users.
Definition: user.class.php:48
Class to manage utility methods.
Definition: utils.class.php:31
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
dirbasename($pathfile)
Return the relative dirname (relative to DOL_DATA_ROOT) of a full path string.
Definition: files.lib.php:3387
dol_is_link($pathoffile)
Return if path is a symbolic link.
Definition: files.lib.php:495
dol_compare_file($a, $b)
Fast compare of 2 files identified by their properties ->name, ->date and ->size.
Definition: files.lib.php:410
dol_meta_create($object)
Create a meta file with document file into same directory.
Definition: files.lib.php:1636
dolCheckVirus($src_file)
Check virus into a file.
Definition: files.lib.php:1179
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition: files.lib.php:37
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
Definition: files.lib.php:948
getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path='', $pathref='', &$checksumconcat=array())
Function to get list of updated or modified files.
Definition: files.lib.php:3404
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:599
dol_filesize($pathoffile)
Return size of a file.
Definition: files.lib.php:587
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
Definition: files.lib.php:1507
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1356
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Make control on an uploaded file from an GUI page and move it to final destination.
Definition: files.lib.php:1218
dol_move_dir($srcdir, $destdir, $overwriteifexists=1, $indexdatabase=1, $renamedircontent=1)
Move a directory into another name.
Definition: files.lib.php:1105
dol_fileperm($pathoffile)
Return permissions of a file.
Definition: files.lib.php:611
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
Definition: files.lib.php:1482
dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser='', $refname='', $mode='read')
Security check when accessing to a document (used by document.php, viewimage.php and webservices to g...
Definition: files.lib.php:2565
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
Definition: files.lib.php:2300
dol_init_file_process($pathtoscan='', $trackid='')
Scan a directory and init $_SESSION to manage uploaded files with list of all found files.
Definition: files.lib.php:1721
addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded', $setsharekey=0, $object=null)
Add a file into database index.
Definition: files.lib.php:1994
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
Definition: files.lib.php:2114
dol_most_recent_file($dir, $regexfilter='', $excludefilter=array('(\.meta|_preview.*\.png)$', '^\.'), $nohook=false, $mode='')
Return file(s) into a directory (by default most recent)
Definition: files.lib.php:2546
dol_is_url($url)
Return if path is an URL.
Definition: files.lib.php:507
dol_filecache($directory, $filename, $object)
Store object in file.
Definition: files.lib.php:3341
dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:237
dragAndDropFileUpload($htmlname)
Function to manage the drag and drop of a file.
Definition: files.lib.php:3448
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:483
dol_count_nb_of_line($file)
Count number of lines in a file.
Definition: files.lib.php:556
dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
Definition: files.lib.php:629
dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
Definition: files.lib.php:717
dol_unescapefile($filename)
Unescape a file submitted by upload.
Definition: files.lib.php:1164
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
dol_dir_is_emtpy($folder)
Test if a folder is empty.
Definition: files.lib.php:524
dol_remove_file_process($filenb, $donotupdatesession=0, $donotdeletefile=1, $trackid='')
Remove an uploaded file (for example after submitting a new file a mail form).
Definition: files.lib.php:1936
dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null, $excludesubdir=0, $excludefileext=null)
Copy a dir to another dir.
Definition: files.lib.php:845
deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded')
Delete files into database index using search criterias.
Definition: files.lib.php:2055
dol_readcachefile($directory, $filename)
Read object from cachefile.
Definition: files.lib.php:3374
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:453
completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
Complete $filearray with data from database.
Definition: files.lib.php:315
dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesession=0, $varfiles='addedfile', $savingdocmask='', $link=null, $trackid='', $generatethumbs=1, $object=null)
Get and save an upload file (for example after submitting a new file a mail form).
Definition: files.lib.php:1759
dol_cache_refresh($directory, $filename, $cachetime)
Test if Refresh needed.
Definition: files.lib.php:3359
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1559
dol_is_dir_empty($dir)
Return if path is empty.
Definition: files.lib.php:469
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
isModEnabled($module)
Is Dolibarr module enabled.
utf8_check($str)
Check if a string is in UTF8.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
vignette($file, $maxWidth=160, $maxHeight=120, $extName='_small', $quality=50, $outdir='thumbs', $targetformat=0)
Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
Definition: images.lib.php:509
getDefaultImageSizes()
Return default values for image sizes.
Definition: images.lib.php:38
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Definition: images.lib.php:80
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
checkUserAccessToObject($user, array $featuresarray, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='', $dbt_select='rowid', $parenttableforentity='')
Check that access by a given user to an object is ok.
dol_hash($chain, $type='0')
Returns a hash (non reversible encryption) of a string.