dolibarr  19.0.0-dev
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 
947 function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1)
948 {
949  global $user, $db, $conf;
950  $result = false;
951 
952  dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
953  $srcexists = dol_is_file($srcfile);
954  $destexists = dol_is_file($destfile);
955 
956  if (!$srcexists) {
957  dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request.");
958  return false;
959  }
960 
961  if ($overwriteifexists || !$destexists) {
962  $newpathofsrcfile = dol_osencode($srcfile);
963  $newpathofdestfile = dol_osencode($destfile);
964 
965  // Check virus
966  $testvirusarray = array();
967  if ($testvirus) {
968  $testvirusarray = dolCheckVirus($newpathofsrcfile);
969  if (count($testvirusarray)) {
970  dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. we ignore the move request.", LOG_WARNING);
971  return false;
972  }
973  }
974 
975  global $dolibarr_main_restrict_os_commands;
976  if (!empty($dolibarr_main_restrict_os_commands)) {
977  $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
978  $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
979  if (in_array(basename($destfile), $arrayofallowedcommand)) {
980  //$langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
981  //setEventMessages($langs->trans("ErrorFilenameReserved", basename($destfile)), null, 'errors');
982  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);
983  return false;
984  }
985  }
986 
987  $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
988  if (!$result) {
989  if ($destexists) {
990  dol_syslog("files.lib.php::dol_move Failed. We try to delete target first and move after.", LOG_WARNING);
991  // We force delete and try again. Rename function sometimes fails to replace dest file with some windows NTFS partitions.
992  dol_delete_file($destfile);
993  $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
994  } else {
995  dol_syslog("files.lib.php::dol_move Failed.", LOG_WARNING);
996  }
997  }
998 
999  // Move ok
1000  if ($result && $indexdatabase) {
1001  // Rename entry into ecm database
1002  $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile);
1003  $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile);
1004  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) { // If not a tmp file
1005  $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore);
1006  $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter);
1007  //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);exit;
1008 
1009  dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG);
1010  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1011 
1012  $ecmfiletarget = new EcmFiles($db);
1013  $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetorenameafter);
1014  if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created.
1015  $ecmfiletarget->delete($user);
1016  }
1017 
1018  $ecmfile = new EcmFiles($db);
1019  $resultecm = $ecmfile->fetch(0, '', $rel_filetorenamebefore);
1020  if ($resultecm > 0) { // If an entry was found for src file, we use it to move entry
1021  $filename = basename($rel_filetorenameafter);
1022  $rel_dir = dirname($rel_filetorenameafter);
1023  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1024  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1025 
1026  $ecmfile->filepath = $rel_dir;
1027  $ecmfile->filename = $filename;
1028 
1029  $resultecm = $ecmfile->update($user);
1030  } elseif ($resultecm == 0) { // If no entry were found for src files, create/update target file
1031  $filename = basename($rel_filetorenameafter);
1032  $rel_dir = dirname($rel_filetorenameafter);
1033  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1034  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1035 
1036  $ecmfile->filepath = $rel_dir;
1037  $ecmfile->filename = $filename;
1038  $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
1039  $ecmfile->fullpath_orig = $srcfile;
1040  $ecmfile->gen_or_uploaded = 'unknown';
1041  $ecmfile->description = ''; // indexed content
1042  $ecmfile->keywords = ''; // keyword content
1043  $resultecm = $ecmfile->create($user);
1044  if ($resultecm < 0) {
1045  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1046  }
1047  } elseif ($resultecm < 0) {
1048  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1049  }
1050 
1051  if ($resultecm > 0) {
1052  $result = true;
1053  } else {
1054  $result = false;
1055  }
1056  }
1057  }
1058 
1059  if (empty($newmask)) {
1060  $newmask = empty($conf->global->MAIN_UMASK) ? '0755' : $conf->global->MAIN_UMASK;
1061  }
1062 
1063  // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too)
1064  // to allow mask usage for dir, we shoul introduce a new param "isdir" to 1 to complete newmask like this
1065  // if ($isdir) $newmaskdec |= octdec('0111'); // Set x bit required for directories
1066  dolChmod($newpathofdestfile, $newmask);
1067  }
1068 
1069  return $result;
1070 }
1071 
1083 function dol_move_dir($srcdir, $destdir, $overwriteifexists = 1, $indexdatabase = 1, $renamedircontent = 1)
1084 {
1085 
1086  global $user, $db, $conf;
1087  $result = false;
1088 
1089  dol_syslog("files.lib.php::dol_move_dir srcdir=".$srcdir." destdir=".$destdir." overwritifexists=".$overwriteifexists." indexdatabase=".$indexdatabase." renamedircontent=".$renamedircontent);
1090  $srcexists = dol_is_dir($srcdir);
1091  $srcbasename = basename($srcdir);
1092  $destexists = dol_is_dir($destdir);
1093 
1094  if (!$srcexists) {
1095  dol_syslog("files.lib.php::dol_move_dir srcdir does not exists. we ignore the move request.");
1096  return false;
1097  }
1098 
1099  if ($overwriteifexists || !$destexists) {
1100  $newpathofsrcdir = dol_osencode($srcdir);
1101  $newpathofdestdir = dol_osencode($destdir);
1102 
1103  $result = @rename($newpathofsrcdir, $newpathofdestdir);
1104 
1105  if ($result && $renamedircontent) {
1106  if (file_exists($newpathofdestdir)) {
1107  $destbasename = basename($newpathofdestdir);
1108  $files = dol_dir_list($newpathofdestdir);
1109  if (!empty($files) && is_array($files)) {
1110  foreach ($files as $key => $file) {
1111  if (!file_exists($file["fullname"])) continue;
1112  $filepath = $file["path"];
1113  $oldname = $file["name"];
1114 
1115  $newname = str_replace($srcbasename, $destbasename, $oldname);
1116  if (!empty($newname) && $newname !== $oldname) {
1117  if ($file["type"] == "dir") {
1118  $res = dol_move_dir($filepath.'/'.$oldname, $filepath.'/'.$newname, $overwriteifexists, $indexdatabase, $renamedircontent);
1119  } else {
1120  $res = dol_move($filepath.'/'.$oldname, $filepath.'/'.$newname, 0, $overwriteifexists, 0, $indexdatabase);
1121  }
1122  if (!$res) {
1123  return $result;
1124  }
1125  }
1126  }
1127  $result = true;
1128  }
1129  }
1130  }
1131  }
1132  return $result;
1133 }
1134 
1142 function dol_unescapefile($filename)
1143 {
1144  // Remove path information and dots around the filename, to prevent uploading
1145  // into different directories or replacing hidden system files.
1146  // Also remove control characters and spaces (\x00..\x20) around the filename:
1147  return trim(basename($filename), ".\x00..\x20");
1148 }
1149 
1150 
1157 function dolCheckVirus($src_file)
1158 {
1159  global $conf, $db;
1160 
1161  if (!empty($conf->global->MAIN_ANTIVIRUS_COMMAND)) {
1162  if (!class_exists('AntiVir')) {
1163  require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
1164  }
1165  $antivir = new AntiVir($db);
1166  $result = $antivir->dol_avscan_file($src_file);
1167  if ($result < 0) { // If virus or error, we stop here
1168  $reterrors = $antivir->errors;
1169  return $reterrors;
1170  }
1171  }
1172  return array();
1173 }
1174 
1175 
1196 function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile', $upload_dir = '')
1197 {
1198  global $conf, $db, $user, $langs;
1199  global $object, $hookmanager;
1200 
1201  $reshook = 0;
1202  $file_name = $dest_file;
1203  $successcode = 1;
1204 
1205  if (empty($nohook)) {
1206  $reshook = $hookmanager->initHooks(array('fileslib'));
1207 
1208  $parameters = array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
1209  $reshook = $hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
1210  }
1211 
1212  if (empty($reshook)) {
1213  // If an upload error has been reported
1214  if ($uploaderrorcode) {
1215  switch ($uploaderrorcode) {
1216  case UPLOAD_ERR_INI_SIZE: // 1
1217  return 'ErrorFileSizeTooLarge';
1218  case UPLOAD_ERR_FORM_SIZE: // 2
1219  return 'ErrorFileSizeTooLarge';
1220  case UPLOAD_ERR_PARTIAL: // 3
1221  return 'ErrorPartialFile';
1222  case UPLOAD_ERR_NO_TMP_DIR: //
1223  return 'ErrorNoTmpDir';
1224  case UPLOAD_ERR_CANT_WRITE:
1225  return 'ErrorFailedToWriteInDir';
1226  case UPLOAD_ERR_EXTENSION:
1227  return 'ErrorUploadBlockedByAddon';
1228  default:
1229  break;
1230  }
1231  }
1232 
1233  // Security:
1234  // If we need to make a virus scan
1235  if (empty($disablevirusscan) && file_exists($src_file)) {
1236  $checkvirusarray = dolCheckVirus($src_file);
1237  if (count($checkvirusarray)) {
1238  dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
1239  return 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray);
1240  }
1241  }
1242 
1243  // Security:
1244  // Disallow file with some extensions. We rename them.
1245  // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
1246  if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) {
1247  // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
1248  $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
1249  if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
1250  $publicmediasdirwithslash .= '/';
1251  }
1252 
1253  if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
1254  $file_name .= '.noexe';
1255  $successcode = 2;
1256  }
1257  }
1258 
1259  // Security:
1260  // We refuse cache files/dirs, upload using .. and pipes into filenames.
1261  if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
1262  dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
1263  return -1;
1264  }
1265 
1266  // Security:
1267  // We refuse cache files/dirs, upload using .. and pipes into filenames.
1268  if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
1269  dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
1270  return -2;
1271  }
1272  }
1273 
1274  if ($reshook < 0) { // At least one blocking error returned by one hook
1275  $errmsg = join(',', $hookmanager->errors);
1276  if (empty($errmsg)) {
1277  $errmsg = 'ErrorReturnedBySomeHooks'; // Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
1278  }
1279  return $errmsg;
1280  } elseif (empty($reshook)) {
1281  // The file functions must be in OS filesystem encoding.
1282  $src_file_osencoded = dol_osencode($src_file);
1283  $file_name_osencoded = dol_osencode($file_name);
1284 
1285  // Check if destination dir is writable
1286  if (!is_writable(dirname($file_name_osencoded))) {
1287  dol_syslog("Files.lib::dol_move_uploaded_file Dir ".dirname($file_name_osencoded)." is not writable. Return 'ErrorDirNotWritable'", LOG_WARNING);
1288  return 'ErrorDirNotWritable';
1289  }
1290 
1291  // Check if destination file already exists
1292  if (!$allowoverwrite) {
1293  if (file_exists($file_name_osencoded)) {
1294  dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
1295  return 'ErrorFileAlreadyExists';
1296  }
1297  } else { // We are allowed to erase
1298  if (is_dir($file_name_osencoded)) { // If there is a directory with name of file to create
1299  dol_syslog("Files.lib::dol_move_uploaded_file A directory with name ".$file_name." already exists. Return 'ErrorDirWithFileNameAlreadyExists'", LOG_WARNING);
1300  return 'ErrorDirWithFileNameAlreadyExists';
1301  }
1302  }
1303 
1304  // Move file
1305  $return = move_uploaded_file($src_file_osencoded, $file_name_osencoded);
1306  if ($return) {
1307  dolChmod($file_name_osencoded);
1308  dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG);
1309  return $successcode; // Success
1310  } else {
1311  dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
1312  return -3; // Unknown error
1313  }
1314  }
1315 
1316  return $successcode; // Success
1317 }
1318 
1334 function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1, $nolog = 0)
1335 {
1336  global $db, $conf, $user, $langs;
1337  global $hookmanager;
1338 
1339  // Load translation files required by the page
1340  $langs->loadLangs(array('other', 'errors'));
1341 
1342  if (empty($nolog)) {
1343  dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook);
1344  }
1345 
1346  // Security:
1347  // We refuse transversal using .. and pipes into filenames.
1348  if ((!$allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file)) {
1349  dol_syslog("Refused to delete file ".$file, LOG_WARNING);
1350  return false;
1351  }
1352 
1353  $reshook = 0;
1354  if (empty($nohook)) {
1355  $hookmanager->initHooks(array('fileslib'));
1356 
1357  $parameters = array(
1358  'file' => $file,
1359  'disableglob'=> $disableglob,
1360  'nophperrors' => $nophperrors
1361  );
1362  $reshook = $hookmanager->executeHooks('deleteFile', $parameters, $object);
1363  }
1364 
1365  if (empty($nohook) && $reshook != 0) { // reshook = 0 to do standard actions, 1 = ok and replace, -1 = ko
1366  dol_syslog("reshook=".$reshook);
1367  if ($reshook < 0) {
1368  return false;
1369  }
1370  return true;
1371  } else {
1372  $file_osencoded = dol_osencode($file); // New filename encoded in OS filesystem encoding charset
1373  if (empty($disableglob) && !empty($file_osencoded)) {
1374  $ok = true;
1375  $globencoded = str_replace('[', '\[', $file_osencoded);
1376  $globencoded = str_replace(']', '\]', $globencoded);
1377  $listofdir = glob($globencoded);
1378  if (!empty($listofdir) && is_array($listofdir)) {
1379  foreach ($listofdir as $filename) {
1380  if ($nophperrors) {
1381  $ok = @unlink($filename);
1382  } else {
1383  $ok = unlink($filename);
1384  }
1385 
1386  // If it fails and it is because of the missing write permission on parent dir
1387  if (!$ok && file_exists(dirname($filename)) && !(fileperms(dirname($filename)) & 0200)) {
1388  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);
1389  dolChmod(dirname($filename), decoct(fileperms(dirname($filename)) | 0200));
1390  // Now we retry deletion
1391  if ($nophperrors) {
1392  $ok = @unlink($filename);
1393  } else {
1394  $ok = unlink($filename);
1395  }
1396  }
1397 
1398  if ($ok) {
1399  if (empty($nolog)) {
1400  dol_syslog("Removed file ".$filename, LOG_DEBUG);
1401  }
1402 
1403  // Delete entry into ecm database
1404  $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename);
1405  if (!preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) { // If not a tmp file
1406  if (is_object($db) && $indexdatabase) { // $db may not be defined when lib is in a context with define('NOREQUIREDB',1)
1407  $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete);
1408  $rel_filetodelete = preg_replace('/\.noexe$/', '', $rel_filetodelete);
1409 
1410  dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG);
1411  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1412  $ecmfile = new EcmFiles($db);
1413  $result = $ecmfile->fetch(0, '', $rel_filetodelete);
1414  if ($result >= 0 && $ecmfile->id > 0) {
1415  $result = $ecmfile->delete($user);
1416  }
1417  if ($result < 0) {
1418  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1419  }
1420  }
1421  }
1422  } else {
1423  dol_syslog("Failed to remove file ".$filename, LOG_WARNING);
1424  // TODO Failure to remove can be because file was already removed or because of permission
1425  // If error because it does not exists, we should return true, and we should return false if this is a permission problem
1426  }
1427  }
1428  } else {
1429  dol_syslog("No files to delete found", LOG_DEBUG);
1430  }
1431  } else {
1432  $ok = false;
1433  if ($nophperrors) {
1434  $ok = @unlink($file_osencoded);
1435  } else {
1436  $ok = unlink($file_osencoded);
1437  }
1438  if ($ok) {
1439  if (empty($nolog)) {
1440  dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
1441  }
1442  } else {
1443  dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
1444  }
1445  }
1446 
1447  return $ok;
1448  }
1449 }
1450 
1460 function dol_delete_dir($dir, $nophperrors = 0)
1461 {
1462  // Security:
1463  // We refuse transversal using .. and pipes into filenames.
1464  if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) {
1465  dol_syslog("Refused to delete dir ".$dir.' (contains invalid char sequence)', LOG_WARNING);
1466  return false;
1467  }
1468 
1469  $dir_osencoded = dol_osencode($dir);
1470  return ($nophperrors ? @rmdir($dir_osencoded) : rmdir($dir_osencoded));
1471 }
1472 
1485 function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0, $indexdatabase = 1, $nolog = 0)
1486 {
1487  if (empty($nolog)) {
1488  dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG);
1489  }
1490  if (dol_is_dir($dir)) {
1491  $dir_osencoded = dol_osencode($dir);
1492  if ($handle = opendir("$dir_osencoded")) {
1493  while (false !== ($item = readdir($handle))) {
1494  if (!utf8_check($item)) {
1495  $item = utf8_encode($item); // should be useless
1496  }
1497 
1498  if ($item != "." && $item != "..") {
1499  if (is_dir(dol_osencode("$dir/$item")) && !is_link(dol_osencode("$dir/$item"))) {
1500  $count = dol_delete_dir_recursive("$dir/$item", $count, $nophperrors, 0, $countdeleted, $indexdatabase, $nolog);
1501  } else {
1502  $result = dol_delete_file("$dir/$item", 1, $nophperrors, 0, null, false, $indexdatabase, $nolog);
1503  $count++;
1504  if ($result) {
1505  $countdeleted++;
1506  }
1507  //else print 'Error on '.$item."\n";
1508  }
1509  }
1510  }
1511  closedir($handle);
1512 
1513  // Delete also the main directory
1514  if (empty($onlysub)) {
1515  $result = dol_delete_dir($dir, $nophperrors);
1516  $count++;
1517  if ($result) {
1518  $countdeleted++;
1519  }
1520  //else print 'Error on '.$dir."\n";
1521  }
1522  }
1523  }
1524 
1525  return $count;
1526 }
1527 
1528 
1537 function dol_delete_preview($object)
1538 {
1539  global $langs, $conf;
1540 
1541  // Define parent dir of elements
1542  $element = $object->element;
1543 
1544  if ($object->element == 'order_supplier') {
1545  $dir = $conf->fournisseur->commande->dir_output;
1546  } elseif ($object->element == 'invoice_supplier') {
1547  $dir = $conf->fournisseur->facture->dir_output;
1548  } elseif ($object->element == 'project') {
1549  $dir = $conf->project->dir_output;
1550  } elseif ($object->element == 'shipping') {
1551  $dir = $conf->expedition->dir_output.'/sending';
1552  } elseif ($object->element == 'delivery') {
1553  $dir = $conf->expedition->dir_output.'/receipt';
1554  } elseif ($object->element == 'fichinter') {
1555  $dir = $conf->ficheinter->dir_output;
1556  } else {
1557  $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1558  }
1559 
1560  if (empty($dir)) {
1561  return 'ErrorObjectNoSupportedByFunction';
1562  }
1563 
1564  $refsan = dol_sanitizeFileName($object->ref);
1565  $dir = $dir."/".$refsan;
1566  $filepreviewnew = $dir."/".$refsan.".pdf_preview.png";
1567  $filepreviewnewbis = $dir."/".$refsan.".pdf_preview-0.png";
1568  $filepreviewold = $dir."/".$refsan.".pdf.png";
1569 
1570  // For new preview files
1571  if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) {
1572  if (!dol_delete_file($filepreviewnew, 1)) {
1573  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnew);
1574  return 0;
1575  }
1576  }
1577  if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) {
1578  if (!dol_delete_file($filepreviewnewbis, 1)) {
1579  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis);
1580  return 0;
1581  }
1582  }
1583  // For old preview files
1584  if (file_exists($filepreviewold) && is_writable($filepreviewold)) {
1585  if (!dol_delete_file($filepreviewold, 1)) {
1586  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewold);
1587  return 0;
1588  }
1589  } else {
1590  $multiple = $filepreviewold.".";
1591  for ($i = 0; $i < 20; $i++) {
1592  $preview = $multiple.$i;
1593 
1594  if (file_exists($preview) && is_writable($preview)) {
1595  if (!dol_delete_file($preview, 1)) {
1596  $object->error = $langs->trans("ErrorFailedToOpenFile", $preview);
1597  return 0;
1598  }
1599  }
1600  }
1601  }
1602 
1603  return 1;
1604 }
1605 
1614 function dol_meta_create($object)
1615 {
1616  global $conf;
1617 
1618  // Create meta file
1619  if (empty($conf->global->MAIN_DOC_CREATE_METAFILE)) {
1620  return 0; // By default, no metafile.
1621  }
1622 
1623  // Define parent dir of elements
1624  $element = $object->element;
1625 
1626  if ($object->element == 'order_supplier') {
1627  $dir = $conf->fournisseur->dir_output.'/commande';
1628  } elseif ($object->element == 'invoice_supplier') {
1629  $dir = $conf->fournisseur->dir_output.'/facture';
1630  } elseif ($object->element == 'project') {
1631  $dir = $conf->project->dir_output;
1632  } elseif ($object->element == 'shipping') {
1633  $dir = $conf->expedition->dir_output.'/sending';
1634  } elseif ($object->element == 'delivery') {
1635  $dir = $conf->expedition->dir_output.'/receipt';
1636  } elseif ($object->element == 'fichinter') {
1637  $dir = $conf->ficheinter->dir_output;
1638  } else {
1639  $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1640  }
1641 
1642  if ($dir) {
1643  $object->fetch_thirdparty();
1644 
1645  $objectref = dol_sanitizeFileName($object->ref);
1646  $dir = $dir."/".$objectref;
1647  $file = $dir."/".$objectref.".meta";
1648 
1649  if (!is_dir($dir)) {
1650  dol_mkdir($dir);
1651  }
1652 
1653  if (is_dir($dir)) {
1654  if (is_countable($object->lines) && count($object->lines) > 0) {
1655  $nblines = count($object->lines);
1656  }
1657  $client = $object->thirdparty->name." ".$object->thirdparty->address." ".$object->thirdparty->zip." ".$object->thirdparty->town;
1658  $meta = "REFERENCE=\"".$object->ref."\"
1659  DATE=\"" . dol_print_date($object->date, '')."\"
1660  NB_ITEMS=\"" . $nblines."\"
1661  CLIENT=\"" . $client."\"
1662  AMOUNT_EXCL_TAX=\"" . $object->total_ht."\"
1663  AMOUNT=\"" . $object->total_ttc."\"\n";
1664 
1665  for ($i = 0; $i < $nblines; $i++) {
1666  //Pour les articles
1667  $meta .= "ITEM_".$i."_QUANTITY=\"".$object->lines[$i]->qty."\"
1668  ITEM_" . $i."_AMOUNT_WO_TAX=\"".$object->lines[$i]->total_ht."\"
1669  ITEM_" . $i."_VAT=\"".$object->lines[$i]->tva_tx."\"
1670  ITEM_" . $i."_DESCRIPTION=\"".str_replace("\r\n", "", nl2br($object->lines[$i]->desc))."\"
1671  ";
1672  }
1673  }
1674 
1675  $fp = fopen($file, "w");
1676  fputs($fp, $meta);
1677  fclose($fp);
1678 
1679  dolChmod($file);
1680 
1681  return 1;
1682  } else {
1683  dol_syslog('FailedToDetectDirInDolMetaCreateFor'.$object->element, LOG_WARNING);
1684  }
1685 
1686  return 0;
1687 }
1688 
1689 
1690 
1699 function dol_init_file_process($pathtoscan = '', $trackid = '')
1700 {
1701  $listofpaths = array();
1702  $listofnames = array();
1703  $listofmimes = array();
1704 
1705  if ($pathtoscan) {
1706  $listoffiles = dol_dir_list($pathtoscan, 'files');
1707  foreach ($listoffiles as $key => $val) {
1708  $listofpaths[] = $val['fullname'];
1709  $listofnames[] = $val['name'];
1710  $listofmimes[] = dol_mimetype($val['name']);
1711  }
1712  }
1713  $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1714  $_SESSION["listofpaths".$keytoavoidconflict] = join(';', $listofpaths);
1715  $_SESSION["listofnames".$keytoavoidconflict] = join(';', $listofnames);
1716  $_SESSION["listofmimes".$keytoavoidconflict] = join(';', $listofmimes);
1717 }
1718 
1719 
1737 function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null)
1738 {
1739 
1740  global $db, $user, $conf, $langs;
1741 
1742  $res = 0;
1743 
1744  if (!empty($_FILES[$varfiles])) { // For view $_FILES[$varfiles]['error']
1745  dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG);
1746  $maxfilesinform = getDolGlobalInt("MAIN_SECURITY_MAX_ATTACHMENT_ON_FORMS", 10);
1747  if (is_array($_FILES[$varfiles]["name"]) && count($_FILES[$varfiles]["name"]) > $maxfilesinform) {
1748  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1749  setEventMessages($langs->trans("ErrorTooMuchFileInForm", $maxfilesinform), null, "errors");
1750  return -1;
1751  }
1752  $result = dol_mkdir($upload_dir);
1753  // var_dump($result);exit;
1754  if ($result >= 0) {
1755  $TFile = $_FILES[$varfiles];
1756  if (!is_array($TFile['name'])) {
1757  foreach ($TFile as $key => &$val) {
1758  $val = array($val);
1759  }
1760  }
1761 
1762  $nbfile = count($TFile['name']);
1763  $nbok = 0;
1764  for ($i = 0; $i < $nbfile; $i++) {
1765  if (empty($TFile['name'][$i])) {
1766  continue; // For example, when submitting a form with no file name
1767  }
1768 
1769  // Define $destfull (path to file including filename) and $destfile (only filename)
1770  $destfull = $upload_dir."/".$TFile['name'][$i];
1771  $destfile = $TFile['name'][$i];
1772  $destfilewithoutext = preg_replace('/\.[^\.]+$/', '', $destfile);
1773 
1774  if ($savingdocmask && strpos($savingdocmask, $destfilewithoutext) !== 0) {
1775  $destfull = $upload_dir."/".preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask);
1776  $destfile = preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask);
1777  }
1778 
1779  $filenameto = basename($destfile);
1780  if (preg_match('/^\./', $filenameto)) {
1781  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1782  setEventMessages($langs->trans("ErrorFilenameCantStartWithDot", $filenameto), null, 'errors');
1783  break;
1784  }
1785 
1786  // dol_sanitizeFileName the file name and lowercase extension
1787  $info = pathinfo($destfull);
1788  $destfull = $info['dirname'].'/'.dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1789  $info = pathinfo($destfile);
1790  $destfile = dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1791 
1792  // We apply dol_string_nohtmltag also to clean file names (this remove duplicate spaces) because
1793  // this function is also applied when we rename and when we make try to download file (by the GETPOST(filename, 'alphanohtml') call).
1794  $destfile = dol_string_nohtmltag($destfile);
1795  $destfull = dol_string_nohtmltag($destfull);
1796 
1797  // Check that filename is not the one of a reserved allowed CLI command
1798  global $dolibarr_main_restrict_os_commands;
1799  if (!empty($dolibarr_main_restrict_os_commands)) {
1800  $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
1801  $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
1802  if (in_array($destfile, $arrayofallowedcommand)) {
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("ErrorFilenameReserved", $destfile), null, 'errors');
1805  return -1;
1806  }
1807  }
1808 
1809  // Move file from temp directory to final directory. A .noexe may also be appended on file name.
1810  $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir);
1811 
1812  if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists'
1813  include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
1814 
1815  $tmparraysize = getDefaultImageSizes();
1816  $maxwidthsmall = $tmparraysize['maxwidthsmall'];
1817  $maxheightsmall = $tmparraysize['maxheightsmall'];
1818  $maxwidthmini = $tmparraysize['maxwidthmini'];
1819  $maxheightmini = $tmparraysize['maxheightmini'];
1820  //$quality = $tmparraysize['quality'];
1821  $quality = 50; // For thumbs, we force quality to 50
1822 
1823  // Generate thumbs.
1824  if ($generatethumbs) {
1825  if (image_format_supported($destfull) == 1) {
1826  // Create thumbs
1827  // We can't use $object->addThumbs here because there is no $object known
1828 
1829  // Used on logon for example
1830  $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', $quality, "thumbs");
1831  // Create mini thumbs for image (Ratio is near 16/9)
1832  // Used on menu or for setup page for example
1833  $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', $quality, "thumbs");
1834  }
1835  }
1836 
1837  // Update session
1838  if (empty($donotupdatesession)) {
1839  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1840  $formmail = new FormMail($db);
1841  $formmail->trackid = $trackid;
1842  $formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
1843  }
1844 
1845  // Update index table of files (llx_ecm_files)
1846  if ($donotupdatesession == 1) {
1847  $sharefile = 0;
1848  if ($TFile['type'][$i] == 'application/pdf' && strpos($_SERVER["REQUEST_URI"], 'product') !== false && !empty($conf->global->PRODUCT_ALLOW_EXTERNAL_DOWNLOAD)) $sharefile = 1;
1849  $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', $sharefile, $object);
1850  if ($result < 0) {
1851  if ($allowoverwrite) {
1852  // Do not show error message. We can have an error due to DB_ERROR_RECORD_ALREADY_EXISTS
1853  } else {
1854  setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', null, 'warnings');
1855  }
1856  }
1857  }
1858 
1859  $nbok++;
1860  } else {
1861  $langs->load("errors");
1862  if ($resupload < 0) { // Unknown error
1863  setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
1864  } elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) { // Files infected by a virus
1865  setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors');
1866  } else // Known error
1867  {
1868  setEventMessages($langs->trans($resupload), null, 'errors');
1869  }
1870  }
1871  }
1872  if ($nbok > 0) {
1873  $res = 1;
1874  setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs');
1875  }
1876  } else {
1877  setEventMessages($langs->trans("ErrorFailedToCreateDir", $upload_dir), null, 'errors');
1878  }
1879  } elseif ($link) {
1880  require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
1881  $linkObject = new Link($db);
1882  $linkObject->entity = $conf->entity;
1883  $linkObject->url = $link;
1884  $linkObject->objecttype = GETPOST('objecttype', 'alpha');
1885  $linkObject->objectid = GETPOST('objectid', 'int');
1886  $linkObject->label = GETPOST('label', 'alpha');
1887  $res = $linkObject->create($user);
1888  $langs->load('link');
1889  if ($res > 0) {
1890  setEventMessages($langs->trans("LinkComplete"), null, 'mesgs');
1891  } else {
1892  setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors');
1893  }
1894  } else {
1895  $langs->load("errors");
1896  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
1897  }
1898 
1899  return $res;
1900 }
1901 
1902 
1914 function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '')
1915 {
1916  global $db, $user, $conf, $langs, $_FILES;
1917 
1918  $keytodelete = $filenb;
1919  $keytodelete--;
1920 
1921  $listofpaths = array();
1922  $listofnames = array();
1923  $listofmimes = array();
1924  $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1925  if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
1926  $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
1927  }
1928  if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
1929  $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
1930  }
1931  if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
1932  $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
1933  }
1934 
1935  if ($keytodelete >= 0) {
1936  $pathtodelete = $listofpaths[$keytodelete];
1937  $filetodelete = $listofnames[$keytodelete];
1938  if (empty($donotdeletefile)) {
1939  $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file
1940  } else {
1941  $result = 0;
1942  }
1943  if ($result >= 0) {
1944  if (empty($donotdeletefile)) {
1945  $langs->load("other");
1946  setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs');
1947  }
1948  if (empty($donotupdatesession)) {
1949  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1950  $formmail = new FormMail($db);
1951  $formmail->trackid = $trackid;
1952  $formmail->remove_attached_files($keytodelete);
1953  }
1954  }
1955  }
1956 }
1957 
1958 
1972 function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null)
1973 {
1974  global $db, $user, $conf;
1975 
1976  $result = 0;
1977 
1978  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
1979 
1980  if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir
1981  $filename = basename(preg_replace('/\.noexe$/', '', $file));
1982  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1983  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1984 
1985  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1986  $ecmfile = new EcmFiles($db);
1987  $ecmfile->filepath = $rel_dir;
1988  $ecmfile->filename = $filename;
1989  $ecmfile->label = md5_file(dol_osencode($dir.'/'.$file)); // MD5 of file content
1990  $ecmfile->fullpath_orig = $fullpathorig;
1991  $ecmfile->gen_or_uploaded = $mode;
1992  $ecmfile->description = ''; // indexed content
1993  $ecmfile->keywords = ''; // keyword content
1994 
1995  if (is_object($object) && $object->id > 0) {
1996  $ecmfile->src_object_id = $object->id;
1997  if (isset($object->table_element)) {
1998  $ecmfile->src_object_type = $object->table_element;
1999  } else {
2000  dol_syslog('Error: object ' . get_class($object) . ' has no table_element attribute.');
2001  return -1;
2002  }
2003  if (isset($object->src_object_description)) $ecmfile->description = $object->src_object_description;
2004  if (isset($object->src_object_keywords)) $ecmfile->keywords = $object->src_object_keywords;
2005  }
2006 
2007  if (!empty($conf->global->MAIN_FORCE_SHARING_ON_ANY_UPLOADED_FILE)) {
2008  $setsharekey = 1;
2009  }
2010 
2011  if ($setsharekey) {
2012  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
2013  $ecmfile->share = getRandomPassword(true);
2014  }
2015 
2016  $result = $ecmfile->create($user);
2017  if ($result < 0) {
2018  dol_syslog($ecmfile->error);
2019  }
2020  }
2021 
2022  return $result;
2023 }
2024 
2033 function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded')
2034 {
2035  global $conf, $db, $user;
2036 
2037  $error = 0;
2038 
2039  if (empty($dir)) {
2040  dol_syslog("deleteFilesIntoDatabaseIndex: dir parameter can't be empty", LOG_ERR);
2041  return -1;
2042  }
2043 
2044  $db->begin();
2045 
2046  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2047 
2048  $filename = basename($file);
2049  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2050  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2051 
2052  if (!$error) {
2053  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'ecm_files';
2054  $sql .= ' WHERE entity = '.$conf->entity;
2055  $sql .= " AND filepath = '".$db->escape($rel_dir)."'";
2056  if ($file) {
2057  $sql .= " AND filename = '".$db->escape($file)."'";
2058  }
2059  if ($mode) {
2060  $sql .= " AND gen_or_uploaded = '".$db->escape($mode)."'";
2061  }
2062 
2063  $resql = $db->query($sql);
2064  if (!$resql) {
2065  $error++;
2066  dol_syslog(__METHOD__.' '.$db->lasterror(), LOG_ERR);
2067  }
2068  }
2069 
2070  // Commit or rollback
2071  if ($error) {
2072  $db->rollback();
2073  return -1 * $error;
2074  } else {
2075  $db->commit();
2076  return 1;
2077  }
2078 }
2079 
2080 
2092 function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '')
2093 {
2094  if (class_exists('Imagick')) {
2095  $image = new Imagick();
2096  try {
2097  $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : '');
2098  //var_dump($filetoconvert);
2099  $ret = $image->readImage($filetoconvert);
2100  } catch (Exception $e) {
2101  $ext = pathinfo($fileinput, PATHINFO_EXTENSION);
2102  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);
2103  return 0;
2104  }
2105  if ($ret) {
2106  $ret = $image->setImageFormat($ext);
2107  if ($ret) {
2108  if (empty($fileoutput)) {
2109  $fileoutput = $fileinput.".".$ext;
2110  }
2111 
2112  $count = $image->getNumberImages();
2113 
2114  if (!dol_is_file($fileoutput) || is_writeable($fileoutput)) {
2115  try {
2116  $ret = $image->writeImages($fileoutput, true);
2117  } catch (Exception $e) {
2118  dol_syslog($e->getMessage(), LOG_WARNING);
2119  }
2120  } else {
2121  dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR);
2122  }
2123  if ($ret) {
2124  return $count;
2125  } else {
2126  return -3;
2127  }
2128  } else {
2129  return -2;
2130  }
2131  } else {
2132  return -1;
2133  }
2134  } else {
2135  return 0;
2136  }
2137 }
2138 
2139 
2151 function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring = null)
2152 {
2153  global $conf;
2154 
2155  $foundhandler = 0;
2156 
2157  try {
2158  dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile);
2159 
2160  $data = implode("", file(dol_osencode($inputfile)));
2161  if ($mode == 'gz' && function_exists('gzencode')) {
2162  $foundhandler = 1;
2163  $compressdata = gzencode($data, 9);
2164  } elseif ($mode == 'bz' && function_exists('bzcompress')) {
2165  $foundhandler = 1;
2166  $compressdata = bzcompress($data, 9);
2167  } elseif ($mode == 'zstd' && function_exists('zstd_compress')) {
2168  $foundhandler = 1;
2169  $compressdata = zstd_compress($data, 9);
2170  } elseif ($mode == 'zip') {
2171  if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) {
2172  $foundhandler = 1;
2173 
2174  $rootPath = realpath($inputfile);
2175 
2176  dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath);
2177  $zip = new ZipArchive;
2178 
2179  if ($zip->open($outputfile, ZipArchive::CREATE) !== true) {
2180  $errorstring = "dol_compress_file failure - Failed to open file ".$outputfile."\n";
2181  dol_syslog($errorstring, LOG_ERR);
2182 
2183  global $errormsg;
2184  $errormsg = $errorstring;
2185 
2186  return -6;
2187  }
2188 
2189  // Create recursive directory iterator
2191  $files = new RecursiveIteratorIterator(
2192  new RecursiveDirectoryIterator($rootPath),
2193  RecursiveIteratorIterator::LEAVES_ONLY
2194  );
2195 
2196  foreach ($files as $name => $file) {
2197  // Skip directories (they would be added automatically)
2198  if (!$file->isDir()) {
2199  // Get real and relative path for current file
2200  $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2201  $fileName = $file->getFilename();
2202  $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2203 
2204  //$relativePath = substr($fileFullRealPath, strlen($rootPath) + 1);
2205  $relativePath = substr(($filePath ? $filePath.'/' : '').$fileName, strlen($rootPath) + 1);
2206 
2207  // Add current file to archive
2208  $zip->addFile($fileFullRealPath, $relativePath);
2209  }
2210  }
2211 
2212  // Zip archive will be created only after closing object
2213  $zip->close();
2214 
2215  dol_syslog("dol_compress_file success - ".count($zip->numFiles)." files");
2216  return 1;
2217  }
2218 
2219  if (defined('ODTPHP_PATHTOPCLZIP')) {
2220  $foundhandler = 1;
2221 
2222  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2223  $archive = new PclZip($outputfile);
2224  $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2225 
2226  if ($result === 0) {
2227  global $errormsg;
2228  $errormsg = $archive->errorInfo(true);
2229 
2230  if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) {
2231  $errorstring = "PCLZIP_ERR_WRITE_OPEN_FAIL";
2232  dol_syslog("dol_compress_file error - archive->errorCode() = PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR);
2233  return -4;
2234  }
2235 
2236  $errorstring = "dol_compress_file error archive->errorCode = ".$archive->errorCode()." errormsg=".$errormsg;
2237  dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR);
2238  return -3;
2239  } else {
2240  dol_syslog("dol_compress_file success - ".count($result)." files");
2241  return 1;
2242  }
2243  }
2244  }
2245 
2246  if ($foundhandler) {
2247  $fp = fopen($outputfile, "w");
2248  fwrite($fp, $compressdata);
2249  fclose($fp);
2250  return 1;
2251  } else {
2252  $errorstring = "Try to zip with format ".$mode." with no handler for this format";
2253  dol_syslog($errorstring, LOG_ERR);
2254 
2255  global $errormsg;
2256  $errormsg = $errorstring;
2257  return -2;
2258  }
2259  } catch (Exception $e) {
2260  global $langs, $errormsg;
2261  $langs->load("errors");
2262  $errormsg = $langs->trans("ErrorFailedToWriteInDir");
2263 
2264  $errorstring = "Failed to open file ".$outputfile;
2265  dol_syslog($errorstring, LOG_ERR);
2266  return -1;
2267  }
2268 }
2269 
2278 function dol_uncompress($inputfile, $outputdir)
2279 {
2280  global $conf, $langs, $db;
2281 
2282  $fileinfo = pathinfo($inputfile);
2283  $fileinfo["extension"] = strtolower($fileinfo["extension"]);
2284 
2285  if ($fileinfo["extension"] == "zip") {
2286  if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS)) {
2287  dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
2288  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2289  $archive = new PclZip($inputfile);
2290 
2291  // We create output dir manually, so it uses the correct permission (When created by the archive->extract, dir is rwx for everybody).
2292  dol_mkdir(dol_sanitizePathName($outputdir));
2293 
2294  // Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
2295  $result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
2296 
2297  if (!is_array($result) && $result <= 0) {
2298  return array('error'=>$archive->errorInfo(true));
2299  } else {
2300  $ok = 1;
2301  $errmsg = '';
2302  // Loop on each file to check result for unzipping file
2303  foreach ($result as $key => $val) {
2304  if ($val['status'] == 'path_creation_fail') {
2305  $langs->load("errors");
2306  $ok = 0;
2307  $errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
2308  break;
2309  }
2310  }
2311 
2312  if ($ok) {
2313  return array();
2314  } else {
2315  return array('error'=>$errmsg);
2316  }
2317  }
2318  }
2319 
2320  if (class_exists('ZipArchive')) { // Must install php-zip to have it
2321  dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
2322  $zip = new ZipArchive;
2323  $res = $zip->open($inputfile);
2324  if ($res === true) {
2325  //$zip->extractTo($outputdir.'/');
2326  // 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
2327  // python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
2328  // with -l is the range of dot to go back in path.
2329  // and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
2330  for ($i = 0; $i < $zip->numFiles; $i++) {
2331  if (preg_match('/\.\./', $zip->getNameIndex($i))) {
2332  dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
2333  continue; // Discard the file
2334  }
2335  $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
2336  }
2337 
2338  $zip->close();
2339  return array();
2340  } else {
2341  return array('error'=>'ErrUnzipFails');
2342  }
2343  }
2344 
2345  return array('error'=>'ErrNoZipEngine');
2346  } elseif (in_array($fileinfo["extension"], array('gz', 'bz2', 'zst'))) {
2347  include_once DOL_DOCUMENT_ROOT."/core/class/utils.class.php";
2348  $utils = new Utils($db);
2349 
2350  dol_mkdir(dol_sanitizePathName($outputdir));
2351  $outputfilename = escapeshellcmd(dol_sanitizePathName($outputdir).'/'.dol_sanitizeFileName($fileinfo["filename"]));
2352  dol_delete_file($outputfilename.'.tmp');
2353  dol_delete_file($outputfilename.'.err');
2354 
2355  $extension = strtolower(pathinfo($fileinfo["filename"], PATHINFO_EXTENSION));
2356  if ($extension == "tar") {
2357  $cmd = 'tar -C '.escapeshellcmd(dol_sanitizePathName($outputdir)).' -xvf '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2358 
2359  $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, $outputfilename.'.err', 0);
2360  if ($resarray["result"] != 0) {
2361  $resarray["error"] .= file_get_contents($outputfilename.'.err');
2362  }
2363  } else {
2364  $program = "";
2365  if ($fileinfo["extension"] == "gz") {
2366  $program = 'gzip';
2367  } elseif ($fileinfo["extension"] == "bz2") {
2368  $program = 'bzip2';
2369  } elseif ($fileinfo["extension"] == "zst") {
2370  $program = 'zstd';
2371  } else {
2372  return array('error'=>'ErrorBadFileExtension');
2373  }
2374  $cmd = $program.' -dc '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2375  $cmd .= ' > '.$outputfilename;
2376 
2377  $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, null, 1, $outputfilename.'.err');
2378  if ($resarray["result"] != 0) {
2379  $errfilecontent = @file_get_contents($outputfilename.'.err');
2380  if ($errfilecontent) {
2381  $resarray["error"] .= " - ".$errfilecontent;
2382  }
2383  }
2384  }
2385  return $resarray["result"] != 0 ? array('error' => $resarray["error"]) : array();
2386  }
2387 
2388  return array('error'=>'ErrorBadFileExtension');
2389 }
2390 
2391 
2404 function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '', $rootdirinzip = '', $newmask = 0)
2405 {
2406  global $conf;
2407 
2408  $foundhandler = 0;
2409 
2410  dol_syslog("Try to zip dir ".$inputdir." into ".$outputfile." mode=".$mode);
2411 
2412  if (!dol_is_dir(dirname($outputfile)) || !is_writable(dirname($outputfile))) {
2413  global $langs, $errormsg;
2414  $langs->load("errors");
2415  $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile);
2416  return -3;
2417  }
2418 
2419  try {
2420  if ($mode == 'gz') {
2421  $foundhandler = 0;
2422  } elseif ($mode == 'bz') {
2423  $foundhandler = 0;
2424  } elseif ($mode == 'zip') {
2425  /*if (defined('ODTPHP_PATHTOPCLZIP'))
2426  {
2427  $foundhandler=0; // TODO implement this
2428 
2429  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2430  $archive = new PclZip($outputfile);
2431  $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2432  //$archive->add($inputfile);
2433  return 1;
2434  }
2435  else*/
2436  //if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS))
2437 
2438  if (class_exists('ZipArchive')) {
2439  $foundhandler = 1;
2440 
2441  // Initialize archive object
2442  $zip = new ZipArchive();
2443  $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
2444  if (!$result) {
2445  global $langs, $errormsg;
2446  $langs->load("errors");
2447  $errormsg = $langs->trans("ErrorFailedToWriteInFile", $outputfile);
2448  return -4;
2449  }
2450 
2451  // Create recursive directory iterator
2452  // This does not return symbolic links
2454  $files = new RecursiveIteratorIterator(
2455  new RecursiveDirectoryIterator($inputdir),
2456  RecursiveIteratorIterator::LEAVES_ONLY
2457  );
2458 
2459  //var_dump($inputdir);
2460  foreach ($files as $name => $file) {
2461  // Skip directories (they would be added automatically)
2462  if (!$file->isDir()) {
2463  // Get real and relative path for current file
2464  $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2465  $fileName = $file->getFilename();
2466  $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2467 
2468  //$relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($fileFullRealPath, strlen($inputdir) + 1);
2469  $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr(($filePath ? $filePath.'/' : '').$fileName, strlen($inputdir) + 1);
2470 
2471  //var_dump($filePath);var_dump($fileFullRealPath);var_dump($relativePath);
2472  if (empty($excludefiles) || !preg_match($excludefiles, $fileFullRealPath)) {
2473  // Add current file to archive
2474  $zip->addFile($fileFullRealPath, $relativePath);
2475  }
2476  }
2477  }
2478 
2479  // Zip archive will be created only after closing object
2480  $zip->close();
2481 
2482  if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) {
2483  $newmask = $conf->global->MAIN_UMASK;
2484  }
2485  if (empty($newmask)) { // This should no happen
2486  dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
2487  $newmask = '0664';
2488  }
2489 
2490  dolChmod($outputfile, $newmask);
2491 
2492  return 1;
2493  }
2494  }
2495 
2496  if (!$foundhandler) {
2497  dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR);
2498  return -2;
2499  } else {
2500  return 0;
2501  }
2502  } catch (Exception $e) {
2503  global $langs, $errormsg;
2504  $langs->load("errors");
2505  dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
2506  dol_syslog($e->getMessage(), LOG_ERR);
2507  $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile).' - '.$e->getMessage();
2508  return -1;
2509  }
2510 }
2511 
2512 
2513 
2524 function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$', '^\.'), $nohook = false, $mode = '')
2525 {
2526  $tmparray = dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook);
2527  return isset($tmparray[0])?$tmparray[0]:null;
2528 }
2529 
2543 function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = '', $refname = '', $mode = 'read')
2544 {
2545  global $conf, $db, $user, $hookmanager;
2546  global $dolibarr_main_data_root, $dolibarr_main_document_root_alt;
2547  global $object;
2548 
2549  if (!is_object($fuser)) {
2550  $fuser = $user;
2551  }
2552 
2553  if (empty($modulepart)) {
2554  return 'ErrorBadParameter';
2555  }
2556  if (empty($entity)) {
2557  if (!isModEnabled('multicompany')) {
2558  $entity = 1;
2559  } else {
2560  $entity = 0;
2561  }
2562  }
2563  // Fix modulepart for backward compatibility
2564  if ($modulepart == 'users') {
2565  $modulepart = 'user';
2566  }
2567  if ($modulepart == 'tva') {
2568  $modulepart = 'tax-vat';
2569  }
2570  // Fix modulepart delivery
2571  if ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) {
2572  $modulepart = 'delivery';
2573  }
2574 
2575  //print 'dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity;
2576  dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
2577 
2578  // We define $accessallowed and $sqlprotectagainstexternals
2579  $accessallowed = 0;
2580  $sqlprotectagainstexternals = '';
2581  $ret = array();
2582 
2583  // Find the subdirectory name as the reference. For example original_file='10/myfile.pdf' -> refname='10'
2584  if (empty($refname)) {
2585  $refname = basename(dirname($original_file)."/");
2586  if ($refname == 'thumbs') {
2587  // If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10'
2588  $refname = basename(dirname(dirname($original_file))."/");
2589  }
2590  }
2591 
2592  // Define possible keys to use for permission check
2593  $lire = 'lire';
2594  $read = 'read';
2595  $download = 'download';
2596  if ($mode == 'write') {
2597  $lire = 'creer';
2598  $read = 'write';
2599  $download = 'upload';
2600  }
2601 
2602  // Wrapping for miscellaneous medias files
2603  if ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) {
2604  if (empty($entity) || empty($conf->medias->multidir_output[$entity])) {
2605  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2606  }
2607  $accessallowed = 1;
2608  $original_file = $conf->medias->multidir_output[$entity].'/'.$original_file;
2609  } elseif ($modulepart == 'logs' && !empty($dolibarr_main_data_root)) {
2610  // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
2611  $accessallowed = ($user->admin && basename($original_file) == $original_file && preg_match('/^dolibarr.*\.(log|json)$/', basename($original_file)));
2612  $original_file = $dolibarr_main_data_root.'/'.$original_file;
2613  } elseif ($modulepart == 'doctemplates' && !empty($dolibarr_main_data_root)) {
2614  // Wrapping for doctemplates
2615  $accessallowed = $user->admin;
2616  $original_file = $dolibarr_main_data_root.'/doctemplates/'.$original_file;
2617  } elseif ($modulepart == 'doctemplateswebsite' && !empty($dolibarr_main_data_root)) {
2618  // Wrapping for doctemplates of websites
2619  $accessallowed = ($fuser->rights->website->write && preg_match('/\.jpg$/i', basename($original_file)));
2620  $original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file;
2621  } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) {
2622  // Wrapping for *.zip package files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
2623  // Dir for custom dirs
2624  $tmp = explode(',', $dolibarr_main_document_root_alt);
2625  $dirins = $tmp[0];
2626 
2627  $accessallowed = ($user->admin && preg_match('/^module_.*\.zip$/', basename($original_file)));
2628  $original_file = $dirins.'/'.$original_file;
2629  } elseif ($modulepart == 'mycompany' && !empty($conf->mycompany->dir_output)) {
2630  // Wrapping for some images
2631  $accessallowed = 1;
2632  $original_file = $conf->mycompany->dir_output.'/'.$original_file;
2633  } elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output)) {
2634  // Wrapping for users photos (user photos are allowed to any connected users)
2635  $accessallowed = 0;
2636  if (preg_match('/^\d+\/photos\//', $original_file)) {
2637  $accessallowed = 1;
2638  }
2639  $original_file = $conf->user->dir_output.'/'.$original_file;
2640  } elseif ($modulepart == 'userphotopublic' && !empty($conf->user->dir_output)) {
2641  // Wrapping for users photos that were set to public by their owner (public user photos can be read with the public link and securekey)
2642  $accessok = false;
2643  $reg = array();
2644  if (preg_match('/^(\d+)\/photos\//', $original_file, $reg)) {
2645  if ($reg[0]) {
2646  $tmpobject = new User($db);
2647  $tmpobject->fetch($reg[0], '', '', 1);
2648  if (getDolUserInt('USER_ENABLE_PUBLIC', 0, $tmpobject)) {
2649  $securekey = GETPOST('securekey', 'alpha', 1);
2650  // Security check
2651  global $dolibarr_main_instance_unique_id;
2652  $encodedsecurekey = dol_hash($dolibarr_main_instance_unique_id.'uservirtualcard'.$tmpobject->id.'-'.$tmpobject->login, 'md5');
2653  if ($encodedsecurekey == $securekey) {
2654  $accessok = true;
2655  }
2656  }
2657  }
2658  }
2659  if ($accessok) {
2660  $accessallowed = 1;
2661  }
2662  $original_file = $conf->user->dir_output.'/'.$original_file;
2663  } elseif (($modulepart == 'companylogo') && !empty($conf->mycompany->dir_output)) {
2664  // Wrapping for company logos (company logos are allowed to anyboby, they are public)
2665  $accessallowed = 1;
2666  $original_file = $conf->mycompany->dir_output.'/logos/'.$original_file;
2667  } elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output)) {
2668  // Wrapping for members photos
2669  $accessallowed = 0;
2670  if (preg_match('/^\d+\/photos\//', $original_file)) {
2671  $accessallowed = 1;
2672  }
2673  $original_file = $conf->adherent->dir_output.'/'.$original_file;
2674  } elseif ($modulepart == 'apercufacture' && !empty($conf->facture->multidir_output[$entity])) {
2675  // Wrapping for invoices (user need permission to read invoices)
2676  if ($fuser->hasRight('facture', $lire)) {
2677  $accessallowed = 1;
2678  }
2679  $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2680  } elseif ($modulepart == 'apercupropal' && !empty($conf->propal->multidir_output[$entity])) {
2681  // Wrapping pour les apercu propal
2682  if ($fuser->hasRight('propal', $lire)) {
2683  $accessallowed = 1;
2684  }
2685  $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
2686  } elseif ($modulepart == 'apercucommande' && !empty($conf->commande->multidir_output[$entity])) {
2687  // Wrapping pour les apercu commande
2688  if ($fuser->hasRight('commande', $lire)) {
2689  $accessallowed = 1;
2690  }
2691  $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
2692  } elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output)) {
2693  // Wrapping pour les apercu intervention
2694  if ($fuser->hasRight('ficheinter', $lire)) {
2695  $accessallowed = 1;
2696  }
2697  $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2698  } elseif (($modulepart == 'apercucontract') && !empty($conf->contrat->multidir_output[$entity])) {
2699  // Wrapping pour les apercu contrat
2700  if ($fuser->hasRight('contrat', $lire)) {
2701  $accessallowed = 1;
2702  }
2703  $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
2704  } elseif (($modulepart == 'apercusupplier_proposal' || $modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output)) {
2705  // Wrapping pour les apercu supplier proposal
2706  if ($fuser->hasRight('supplier_proposal', $lire)) {
2707  $accessallowed = 1;
2708  }
2709  $original_file = $conf->supplier_proposal->dir_output.'/'.$original_file;
2710  } elseif (($modulepart == 'apercusupplier_order' || $modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output)) {
2711  // Wrapping pour les apercu supplier order
2712  if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2713  $accessallowed = 1;
2714  }
2715  $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
2716  } elseif (($modulepart == 'apercusupplier_invoice' || $modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output)) {
2717  // Wrapping pour les apercu supplier invoice
2718  if ($fuser->hasRight('fournisseur', $lire)) {
2719  $accessallowed = 1;
2720  }
2721  $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
2722  } elseif (($modulepart == 'holiday') && !empty($conf->holiday->dir_output)) {
2723  if ($fuser->hasRight('holiday', $read) || !empty($fuser->rights->holiday->readall) || preg_match('/^specimen/i', $original_file)) {
2724  $accessallowed = 1;
2725  // If we known $id of holiday, call checkUserAccessToObject to check permission on properties and hierarchy of leave request
2726  if ($refname && empty($fuser->rights->holiday->readall) && !preg_match('/^specimen/i', $original_file)) {
2727  include_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
2728  $tmpholiday = new Holiday($db);
2729  $tmpholiday->fetch('', $refname);
2730  $accessallowed = checkUserAccessToObject($user, array('holiday'), $tmpholiday, 'holiday', '', '', 'rowid', '');
2731  }
2732  }
2733  $original_file = $conf->holiday->dir_output.'/'.$original_file;
2734  } elseif (($modulepart == 'expensereport') && !empty($conf->expensereport->dir_output)) {
2735  if ($fuser->hasRight('expensereport', $lire) || !empty($fuser->rights->expensereport->readall) || preg_match('/^specimen/i', $original_file)) {
2736  $accessallowed = 1;
2737  // If we known $id of expensereport, call checkUserAccessToObject to check permission on properties and hierarchy of expense report
2738  if ($refname && empty($fuser->rights->expensereport->readall) && !preg_match('/^specimen/i', $original_file)) {
2739  include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
2740  $tmpexpensereport = new ExpenseReport($db);
2741  $tmpexpensereport->fetch('', $refname);
2742  $accessallowed = checkUserAccessToObject($user, array('expensereport'), $tmpexpensereport, 'expensereport', '', '', 'rowid', '');
2743  }
2744  }
2745  $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2746  } elseif (($modulepart == 'apercuexpensereport') && !empty($conf->expensereport->dir_output)) {
2747  // Wrapping pour les apercu expense report
2748  if ($fuser->hasRight('expensereport', $lire)) {
2749  $accessallowed = 1;
2750  }
2751  $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2752  } elseif ($modulepart == 'propalstats' && !empty($conf->propal->multidir_temp[$entity])) {
2753  // Wrapping pour les images des stats propales
2754  if ($fuser->hasRight('propal', $lire)) {
2755  $accessallowed = 1;
2756  }
2757  $original_file = $conf->propal->multidir_temp[$entity].'/'.$original_file;
2758  } elseif ($modulepart == 'orderstats' && !empty($conf->commande->dir_temp)) {
2759  // Wrapping pour les images des stats commandes
2760  if ($fuser->hasRight('commande', $lire)) {
2761  $accessallowed = 1;
2762  }
2763  $original_file = $conf->commande->dir_temp.'/'.$original_file;
2764  } elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2765  if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2766  $accessallowed = 1;
2767  }
2768  $original_file = $conf->fournisseur->commande->dir_temp.'/'.$original_file;
2769  } elseif ($modulepart == 'billstats' && !empty($conf->facture->dir_temp)) {
2770  // Wrapping pour les images des stats factures
2771  if ($fuser->hasRight('facture', $lire)) {
2772  $accessallowed = 1;
2773  }
2774  $original_file = $conf->facture->dir_temp.'/'.$original_file;
2775  } elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2776  if ($fuser->hasRight('fournisseur', 'facture', $lire)) {
2777  $accessallowed = 1;
2778  }
2779  $original_file = $conf->fournisseur->facture->dir_temp.'/'.$original_file;
2780  } elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp)) {
2781  // Wrapping pour les images des stats expeditions
2782  if ($fuser->hasRight('expedition', $lire)) {
2783  $accessallowed = 1;
2784  }
2785  $original_file = $conf->expedition->dir_temp.'/'.$original_file;
2786  } elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp)) {
2787  // Wrapping pour les images des stats expeditions
2788  if ($fuser->hasRight('deplacement', $lire)) {
2789  $accessallowed = 1;
2790  }
2791  $original_file = $conf->deplacement->dir_temp.'/'.$original_file;
2792  } elseif ($modulepart == 'memberstats' && !empty($conf->adherent->dir_temp)) {
2793  // Wrapping pour les images des stats expeditions
2794  if ($fuser->hasRight('adherent', $lire)) {
2795  $accessallowed = 1;
2796  }
2797  $original_file = $conf->adherent->dir_temp.'/'.$original_file;
2798  } elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) {
2799  // Wrapping pour les images des stats produits
2800  if ($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) {
2801  $accessallowed = 1;
2802  }
2803  $original_file = (!empty($conf->product->multidir_temp[$entity]) ? $conf->product->multidir_temp[$entity] : $conf->service->multidir_temp[$entity]).'/'.$original_file;
2804  } elseif (in_array($modulepart, array('tax', 'tax-vat', 'tva')) && !empty($conf->tax->dir_output)) {
2805  // Wrapping for taxes
2806  if ($fuser->hasRight('tax', 'charges', $lire)) {
2807  $accessallowed = 1;
2808  }
2809  $modulepartsuffix = str_replace('tax-', '', $modulepart);
2810  $original_file = $conf->tax->dir_output.'/'.($modulepartsuffix != 'tax' ? $modulepartsuffix.'/' : '').$original_file;
2811  } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
2812  // Wrapping for events
2813  if ($fuser->hasRight('agenda', 'myactions', $read)) {
2814  $accessallowed = 1;
2815  // If we known $id of project, call checkUserAccessToObject to check permission on the given agenda event on properties and assigned users
2816  if ($refname && !preg_match('/^specimen/i', $original_file)) {
2817  include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
2818  $tmpobject = new ActionComm($db);
2819  $tmpobject->fetch((int) $refname);
2820  $accessallowed = checkUserAccessToObject($user, array('agenda'), $tmpobject->id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id', '');
2821  if ($user->socid && $tmpobject->socid) {
2822  $accessallowed = checkUserAccessToObject($user, array('societe'), $tmpobject->socid);
2823  }
2824  }
2825  }
2826  $original_file = $conf->agenda->dir_output.'/'.$original_file;
2827  } elseif ($modulepart == 'category' && !empty($conf->categorie->multidir_output[$entity])) {
2828  // Wrapping for categories (categories are allowed if user has permission to read categories or to work on TakePos)
2829  if (empty($entity) || empty($conf->categorie->multidir_output[$entity])) {
2830  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2831  }
2832  if ($fuser->hasRight("categorie", $lire) || $fuser->hasRight("takepos", "run")) {
2833  $accessallowed = 1;
2834  }
2835  $original_file = $conf->categorie->multidir_output[$entity].'/'.$original_file;
2836  } elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) {
2837  // Wrapping pour les prelevements
2838  if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i', $original_file)) {
2839  $accessallowed = 1;
2840  }
2841  $original_file = $conf->prelevement->dir_output.'/'.$original_file;
2842  } elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp)) {
2843  // Wrapping pour les graph energie
2844  $accessallowed = 1;
2845  $original_file = $conf->stock->dir_temp.'/'.$original_file;
2846  } elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp)) {
2847  // Wrapping pour les graph fournisseurs
2848  $accessallowed = 1;
2849  $original_file = $conf->fournisseur->dir_temp.'/'.$original_file;
2850  } elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp)) {
2851  // Wrapping pour les graph des produits
2852  $accessallowed = 1;
2853  $original_file = $conf->product->multidir_temp[$entity].'/'.$original_file;
2854  } elseif ($modulepart == 'barcode') {
2855  // Wrapping pour les code barre
2856  $accessallowed = 1;
2857  // If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
2858  //$original_file=$conf->barcode->dir_temp.'/'.$original_file;
2859  $original_file = '';
2860  } elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp)) {
2861  // Wrapping pour les icones de background des mailings
2862  $accessallowed = 1;
2863  $original_file = $conf->mailing->dir_temp.'/'.$original_file;
2864  } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
2865  // Wrapping pour le scanner
2866  $accessallowed = 1;
2867  $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
2868  } elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output)) {
2869  // Wrapping pour les images fckeditor
2870  $accessallowed = 1;
2871  $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
2872  } elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) {
2873  // Wrapping for users
2874  $canreaduser = (!empty($fuser->admin) || $fuser->rights->user->user->{$lire});
2875  if ($fuser->id == (int) $refname) {
2876  $canreaduser = 1;
2877  } // A user can always read its own card
2878  if ($canreaduser || preg_match('/^specimen/i', $original_file)) {
2879  $accessallowed = 1;
2880  }
2881  $original_file = $conf->user->dir_output.'/'.$original_file;
2882  } elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->multidir_output[$entity])) {
2883  // Wrapping for third parties
2884  if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
2885  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2886  }
2887  if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i', $original_file)) {
2888  $accessallowed = 1;
2889  }
2890  $original_file = $conf->societe->multidir_output[$entity].'/'.$original_file;
2891  $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe').")";
2892  } elseif ($modulepart == 'contact' && !empty($conf->societe->multidir_output[$entity])) {
2893  // Wrapping for contact
2894  if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
2895  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2896  }
2897  if ($fuser->hasRight('societe', $lire)) {
2898  $accessallowed = 1;
2899  }
2900  $original_file = $conf->societe->multidir_output[$entity].'/contact/'.$original_file;
2901  } elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->multidir_output[$entity])) {
2902  // Wrapping for invoices
2903  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2904  $accessallowed = 1;
2905  }
2906  $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2907  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('invoice').")";
2908  } elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) {
2909  // Wrapping for mass actions
2910  if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
2911  $accessallowed = 1;
2912  }
2913  $original_file = $conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2914  } elseif ($modulepart == 'massfilesarea_orders') {
2915  if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
2916  $accessallowed = 1;
2917  }
2918  $original_file = $conf->commande->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2919  } elseif ($modulepart == 'massfilesarea_sendings') {
2920  if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
2921  $accessallowed = 1;
2922  }
2923  $original_file = $conf->expedition->dir_output.'/sending/temp/massgeneration/'.$user->id.'/'.$original_file;
2924  } elseif ($modulepart == 'massfilesarea_invoices') {
2925  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2926  $accessallowed = 1;
2927  }
2928  $original_file = $conf->facture->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2929  } elseif ($modulepart == 'massfilesarea_expensereport') {
2930  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2931  $accessallowed = 1;
2932  }
2933  $original_file = $conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2934  } elseif ($modulepart == 'massfilesarea_interventions') {
2935  if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
2936  $accessallowed = 1;
2937  }
2938  $original_file = $conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2939  } elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) {
2940  if ($fuser->hasRight('supplier_proposal', $lire) || preg_match('/^specimen/i', $original_file)) {
2941  $accessallowed = 1;
2942  }
2943  $original_file = $conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2944  } elseif ($modulepart == 'massfilesarea_supplier_order') {
2945  if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
2946  $accessallowed = 1;
2947  }
2948  $original_file = $conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2949  } elseif ($modulepart == 'massfilesarea_supplier_invoice') {
2950  if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2951  $accessallowed = 1;
2952  }
2953  $original_file = $conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2954  } elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) {
2955  if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
2956  $accessallowed = 1;
2957  }
2958  $original_file = $conf->contrat->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2959  } elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) {
2960  // Wrapping for interventions
2961  if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
2962  $accessallowed = 1;
2963  }
2964  $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2965  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2966  } elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) {
2967  // Wrapping pour les deplacements et notes de frais
2968  if ($fuser->hasRight('deplacement', $lire) || preg_match('/^specimen/i', $original_file)) {
2969  $accessallowed = 1;
2970  }
2971  $original_file = $conf->deplacement->dir_output.'/'.$original_file;
2972  //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2973  } elseif (($modulepart == 'propal' || $modulepart == 'propale') && isset($conf->propal->multidir_output[$entity])) {
2974  // Wrapping pour les propales
2975  if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
2976  $accessallowed = 1;
2977  }
2978  $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
2979  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('propal').")";
2980  } elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->multidir_output[$entity])) {
2981  // Wrapping pour les commandes
2982  if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) {
2983  $accessallowed = 1;
2984  }
2985  $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
2986  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")";
2987  } elseif ($modulepart == 'project' && !empty($conf->project->multidir_output[$entity])) {
2988  // Wrapping pour les projets
2989  if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
2990  $accessallowed = 1;
2991  // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
2992  if ($refname && !preg_match('/^specimen/i', $original_file)) {
2993  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
2994  $tmpproject = new Project($db);
2995  $tmpproject->fetch('', $refname);
2996  $accessallowed = checkUserAccessToObject($user, array('projet'), $tmpproject->id, 'projet&project', '', '', 'rowid', '');
2997  }
2998  }
2999  $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3000  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3001  } elseif ($modulepart == 'project_task' && !empty($conf->project->multidir_output[$entity])) {
3002  if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3003  $accessallowed = 1;
3004  // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3005  if ($refname && !preg_match('/^specimen/i', $original_file)) {
3006  include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
3007  $tmptask = new Task($db);
3008  $tmptask->fetch('', $refname);
3009  $accessallowed = checkUserAccessToObject($user, array('projet_task'), $tmptask->id, 'projet_task&project', '', '', 'rowid', '');
3010  }
3011  }
3012  $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3013  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3014  } elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) {
3015  // Wrapping pour les commandes fournisseurs
3016  if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) {
3017  $accessallowed = 1;
3018  }
3019  $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
3020  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3021  } elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) {
3022  // Wrapping pour les factures fournisseurs
3023  if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) {
3024  $accessallowed = 1;
3025  }
3026  $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
3027  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3028  } elseif ($modulepart == 'supplier_payment') {
3029  // Wrapping pour les rapport de paiements
3030  if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) {
3031  $accessallowed = 1;
3032  }
3033  $original_file = $conf->fournisseur->payment->dir_output.'/'.$original_file;
3034  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3035  } elseif ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) {
3036  // Wrapping pour les rapport de paiements
3037  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3038  $accessallowed = 1;
3039  }
3040  if ($fuser->socid > 0) {
3041  $original_file = $conf->facture->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file;
3042  } else {
3043  $original_file = $conf->facture->dir_output.'/payments/'.$original_file;
3044  }
3045  } elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) {
3046  // Wrapping for accounting exports
3047  if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i', $original_file)) {
3048  $accessallowed = 1;
3049  }
3050  $original_file = $conf->accounting->dir_output.'/'.$original_file;
3051  } elseif (($modulepart == 'expedition' || $modulepart == 'shipment') && !empty($conf->expedition->dir_output)) {
3052  // Wrapping pour les expedition
3053  if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
3054  $accessallowed = 1;
3055  }
3056  $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'sending/') === 0 ? '' : 'sending/').$original_file;
3057  //$original_file = $conf->expedition->dir_output."/".$original_file;
3058  } elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output)) {
3059  // Delivery Note Wrapping
3060  if ($fuser->hasRight('expedition', 'delivery', $lire) || preg_match('/^specimen/i', $original_file)) {
3061  $accessallowed = 1;
3062  }
3063  $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'receipt/') === 0 ? '' : 'receipt/').$original_file;
3064  } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
3065  // Wrapping pour les actions
3066  if ($fuser->hasRight('agenda', 'myactions', $read) || preg_match('/^specimen/i', $original_file)) {
3067  $accessallowed = 1;
3068  }
3069  $original_file = $conf->agenda->dir_output.'/'.$original_file;
3070  } elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) {
3071  // Wrapping pour les actions
3072  if ($fuser->hasRight('agenda', 'allactions', $read) || preg_match('/^specimen/i', $original_file)) {
3073  $accessallowed = 1;
3074  }
3075  $original_file = $conf->agenda->dir_temp."/".$original_file;
3076  } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
3077  // Wrapping pour les produits et services
3078  if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) {
3079  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3080  }
3081  if (($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) || preg_match('/^specimen/i', $original_file)) {
3082  $accessallowed = 1;
3083  }
3084  if (isModEnabled("product")) {
3085  $original_file = $conf->product->multidir_output[$entity].'/'.$original_file;
3086  } elseif (isModEnabled("service")) {
3087  $original_file = $conf->service->multidir_output[$entity].'/'.$original_file;
3088  }
3089  } elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') {
3090  // Wrapping pour les lots produits
3091  if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) {
3092  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3093  }
3094  if (($fuser->hasRight('produit', $lire)) || preg_match('/^specimen/i', $original_file)) {
3095  $accessallowed = 1;
3096  }
3097  if (isModEnabled('productbatch')) {
3098  $original_file = $conf->productbatch->multidir_output[$entity].'/'.$original_file;
3099  }
3100  } elseif ($modulepart == 'movement' || $modulepart == 'mouvement') {
3101  // Wrapping for stock movements
3102  if (empty($entity) || empty($conf->stock->multidir_output[$entity])) {
3103  return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3104  }
3105  if (($fuser->hasRight('stock', $lire) || $fuser->hasRight('stock', 'movement', $lire) || $fuser->hasRight('stock', 'mouvement', $lire)) || preg_match('/^specimen/i', $original_file)) {
3106  $accessallowed = 1;
3107  }
3108  if (isModEnabled('stock')) {
3109  $original_file = $conf->stock->multidir_output[$entity].'/movement/'.$original_file;
3110  }
3111  } elseif ($modulepart == 'contract' && !empty($conf->contrat->multidir_output[$entity])) {
3112  // Wrapping pour les contrats
3113  if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) {
3114  $accessallowed = 1;
3115  }
3116  $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
3117  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract').")";
3118  } elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) {
3119  // Wrapping pour les dons
3120  if ($fuser->hasRight('don', $lire) || preg_match('/^specimen/i', $original_file)) {
3121  $accessallowed = 1;
3122  }
3123  $original_file = $conf->don->dir_output.'/'.$original_file;
3124  } elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) {
3125  // Wrapping pour les dons
3126  if ($fuser->hasRight('resource', $read) || preg_match('/^specimen/i', $original_file)) {
3127  $accessallowed = 1;
3128  }
3129  $original_file = $conf->resource->dir_output.'/'.$original_file;
3130  } elseif (($modulepart == 'remisecheque' || $modulepart == 'chequereceipt') && !empty($conf->bank->dir_output)) {
3131  // Wrapping pour les remises de cheques
3132  if ($fuser->hasRight('banque', $lire) || preg_match('/^specimen/i', $original_file)) {
3133  $accessallowed = 1;
3134  }
3135 
3136  $original_file = $conf->bank->dir_output.'/checkdeposits/'.$original_file; // original_file should contains relative path so include the get_exdir result
3137  } elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) {
3138  // Wrapping for bank
3139  if ($fuser->hasRight('banque', $lire)) {
3140  $accessallowed = 1;
3141  }
3142  $original_file = $conf->bank->dir_output.'/'.$original_file;
3143  } elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) {
3144  // Wrapping for export module
3145  // Note that a test may not be required because we force the dir of download on the directory of the user that export
3146  $accessallowed = $user->rights->export->lire;
3147  $original_file = $conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file;
3148  } elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) {
3149  // Wrapping for import module
3150  $accessallowed = $user->rights->import->run;
3151  $original_file = $conf->import->dir_temp.'/'.$original_file;
3152  } elseif ($modulepart == 'recruitment' && !empty($conf->recruitment->dir_output)) {
3153  // Wrapping for recruitment module
3154  $accessallowed = $user->hasRight('recruitment', 'recruitmentjobposition', 'read');
3155  $original_file = $conf->recruitment->dir_output.'/'.$original_file;
3156  } elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) {
3157  // Wrapping for wysiwyg editor
3158  $accessallowed = 1;
3159  $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
3160  } elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) {
3161  // Wrapping for backups
3162  if ($fuser->admin) {
3163  $accessallowed = 1;
3164  }
3165  $original_file = $conf->admin->dir_output.'/'.$original_file;
3166  } elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) {
3167  // Wrapping for upload file test
3168  if ($fuser->admin) {
3169  $accessallowed = 1;
3170  }
3171  $original_file = $conf->admin->dir_temp.'/'.$original_file;
3172  } elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) {
3173  // Wrapping pour BitTorrent
3174  $accessallowed = 1;
3175  $dir = 'files';
3176  if (dol_mimetype($original_file) == 'application/x-bittorrent') {
3177  $dir = 'torrents';
3178  }
3179  $original_file = $conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
3180  } elseif ($modulepart == 'member' && !empty($conf->adherent->dir_output)) {
3181  // Wrapping pour Foundation module
3182  if ($fuser->hasRight('adherent', $lire) || preg_match('/^specimen/i', $original_file)) {
3183  $accessallowed = 1;
3184  }
3185  $original_file = $conf->adherent->dir_output.'/'.$original_file;
3186  } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
3187  // Wrapping for Scanner
3188  $accessallowed = 1;
3189  $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
3190  // If modulepart=module_user_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser
3191  // If modulepart=module_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp
3192  // If modulepart=module_user Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser
3193  // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3194  // If modulepart=module-abc Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3195  } else {
3196  // GENERIC Wrapping
3197  //var_dump($modulepart);
3198  //var_dump($original_file);
3199  if (preg_match('/^specimen/i', $original_file)) {
3200  $accessallowed = 1; // If link to a file called specimen. Test must be done before changing $original_file int full path.
3201  }
3202  if ($fuser->admin) {
3203  $accessallowed = 1; // If user is admin
3204  }
3205 
3206  $tmpmodulepart = explode('-', $modulepart);
3207  if (!empty($tmpmodulepart[1])) {
3208  $modulepart = $tmpmodulepart[0];
3209  $original_file = $tmpmodulepart[1].'/'.$original_file;
3210  }
3211 
3212  // Define $accessallowed
3213  $reg = array();
3214  if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) {
3215  $tmpmodule = $reg[1];
3216  if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3217  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3218  exit;
3219  }
3220  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3221  $accessallowed = 1;
3222  }
3223  $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
3224  } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) {
3225  $tmpmodule = $reg[1];
3226  if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3227  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3228  exit;
3229  }
3230  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3231  $accessallowed = 1;
3232  }
3233  $original_file = $conf->$tmpmodule->dir_temp.'/'.$original_file;
3234  } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) {
3235  $tmpmodule = $reg[1];
3236  if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3237  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3238  exit;
3239  }
3240  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3241  $accessallowed = 1;
3242  }
3243  $original_file = $conf->$tmpmodule->dir_output.'/'.$fuser->id.'/'.$original_file;
3244  } elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) {
3245  $tmpmodule = $reg[1];
3246  if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3247  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3248  exit;
3249  }
3250  if ($fuser->hasRight($tmpmodule, $lire) || preg_match('/^specimen/i', $original_file)) {
3251  $accessallowed = 1;
3252  }
3253  $original_file = $conf->$tmpmodule->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3254  } else {
3255  if (empty($conf->$modulepart->dir_output)) { // modulepart not supported
3256  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.');
3257  exit;
3258  }
3259 
3260  // Check fuser->rights->modulepart->myobject->read and fuser->rights->modulepart->read
3261  $partsofdirinoriginalfile = explode('/', $original_file);
3262  if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use)
3263  $partofdirinoriginalfile = $partsofdirinoriginalfile[0];
3264  if ($partofdirinoriginalfile && ($fuser->hasRight($modulepart, $partofdirinoriginalfile, 'lire') || $fuser->hasRight($modulepart, $partofdirinoriginalfile, 'read'))) {
3265  $accessallowed = 1;
3266  }
3267  }
3268  if ($fuser->hasRight($modulepart, $lire) || $fuser->hasRight($modulepart, $read)) {
3269  $accessallowed = 1;
3270  }
3271 
3272  if (is_array($conf->$modulepart->multidir_output) && !empty($conf->$modulepart->multidir_output[$entity])) {
3273  $original_file = $conf->$modulepart->multidir_output[$entity].'/'.$original_file;
3274  } else {
3275  $original_file = $conf->$modulepart->dir_output.'/'.$original_file;
3276  }
3277  }
3278 
3279  $parameters = array(
3280  'modulepart' => $modulepart,
3281  'original_file' => $original_file,
3282  'entity' => $entity,
3283  'fuser' => $fuser,
3284  'refname' => '',
3285  'mode' => $mode
3286  );
3287  $reshook = $hookmanager->executeHooks('checkSecureAccess', $parameters, $object);
3288  if ($reshook > 0) {
3289  if (!empty($hookmanager->resArray['original_file'])) {
3290  $original_file = $hookmanager->resArray['original_file'];
3291  }
3292  if (!empty($hookmanager->resArray['accessallowed'])) {
3293  $accessallowed = $hookmanager->resArray['accessallowed'];
3294  }
3295  if (!empty($hookmanager->resArray['sqlprotectagainstexternals'])) {
3296  $sqlprotectagainstexternals = $hookmanager->resArray['sqlprotectagainstexternals'];
3297  }
3298  }
3299  }
3300 
3301  $ret = array(
3302  'accessallowed' => ($accessallowed ? 1 : 0),
3303  'sqlprotectagainstexternals' => $sqlprotectagainstexternals,
3304  'original_file' => $original_file
3305  );
3306 
3307  return $ret;
3308 }
3309 
3318 function dol_filecache($directory, $filename, $object)
3319 {
3320  if (!dol_is_dir($directory)) {
3321  dol_mkdir($directory);
3322  }
3323  $cachefile = $directory.$filename;
3324  file_put_contents($cachefile, serialize($object), LOCK_EX);
3325  dolChmod($cachefile, '0644');
3326 }
3327 
3336 function dol_cache_refresh($directory, $filename, $cachetime)
3337 {
3338  $now = dol_now();
3339  $cachefile = $directory.$filename;
3340  $refresh = !file_exists($cachefile) || ($now - $cachetime) > dol_filemtime($cachefile);
3341  return $refresh;
3342 }
3343 
3351 function dol_readcachefile($directory, $filename)
3352 {
3353  $cachefile = $directory.$filename;
3354  $object = unserialize(file_get_contents($cachefile));
3355  return $object;
3356 }
3357 
3364 function dirbasename($pathfile)
3365 {
3366  return preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'\//', '', $pathfile);
3367 }
3368 
3369 
3381 function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
3382 {
3383  global $conffile;
3384 
3385  $exclude = 'install';
3386 
3387  foreach ($dir->md5file as $file) { // $file is a simpleXMLElement
3388  $filename = $path.$file['name'];
3389  $file_list['insignature'][] = $filename;
3390  $expectedsize = (empty($file['size']) ? '' : $file['size']);
3391  $expectedmd5 = (string) $file;
3392 
3393  //if (preg_match('#'.$exclude.'#', $filename)) continue;
3394 
3395  if (!file_exists($pathref.'/'.$filename)) {
3396  $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize);
3397  } else {
3398  $md5_local = md5_file($pathref.'/'.$filename);
3399 
3400  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
3401  $checksumconcat[] = $expectedmd5;
3402  } else {
3403  if ($md5_local != $expectedmd5) {
3404  $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize, 'md5'=>(string) $md5_local);
3405  }
3406  $checksumconcat[] = $md5_local;
3407  }
3408  }
3409  }
3410 
3411  foreach ($dir->dir as $subdir) { // $subdir['name'] is '' or '/accountancy/admin' for example
3412  getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat);
3413  }
3414 
3415  return $file_list;
3416 }
3417 
3425 function dragAndDropFileUpload($htmlname)
3426 {
3427  global $object, $langs;
3428 
3429  $out = "";
3430  $out .= '<div id="'.$htmlname.'Message" class="dragDropAreaMessage hidden"><span>'.img_picto("", 'download').'<br>'.$langs->trans("DropFileToAddItToObject").'</span></div>';
3431  $out .= "\n<!-- JS CODE TO ENABLE DRAG AND DROP OF FILE -->\n";
3432  $out .= "<script>";
3433  $out .= '
3434  jQuery(document).ready(function() {
3435  var enterTargetDragDrop = null;
3436 
3437  $("#'.$htmlname.'").addClass("cssDragDropArea");
3438 
3439  $(".cssDragDropArea").on("dragenter", function(ev, ui) {
3440  var dataTransfer = ev.originalEvent.dataTransfer;
3441  var dataTypes = dataTransfer.types;
3442  //console.log(dataTransfer);
3443  //console.log(dataTypes);
3444 
3445  if (!dataTypes || ($.inArray(\'Files\', dataTypes) === -1)) {
3446  // The element dragged is not a file, so we avoid the "dragenter"
3447  ev.preventDefault();
3448  return false;
3449  }
3450 
3451  // Entering drop area. Highlight area
3452  console.log("dragAndDropFileUpload: We add class highlightDragDropArea")
3453  enterTargetDragDrop = ev.target;
3454  $(this).addClass("highlightDragDropArea");
3455  $("#'.$htmlname.'Message").removeClass("hidden");
3456  ev.preventDefault();
3457  });
3458 
3459  $(".cssDragDropArea").on("dragleave", function(ev) {
3460  // Going out of drop area. Remove Highlight
3461  if (enterTargetDragDrop == ev.target){
3462  console.log("dragAndDropFileUpload: We remove class highlightDragDropArea")
3463  $("#'.$htmlname.'Message").addClass("hidden");
3464  $(this).removeClass("highlightDragDropArea");
3465  }
3466  });
3467 
3468  $(".cssDragDropArea").on("dragover", function(ev) {
3469  ev.preventDefault();
3470  return false;
3471  });
3472 
3473  $(".cssDragDropArea").on("drop", function(e) {
3474  console.log("Trigger event file dropped. fk_element='.dol_escape_js($object->id).' element='.dol_escape_js($object->element).'");
3475  e.preventDefault();
3476  fd = new FormData();
3477  fd.append("fk_element", "'.dol_escape_js($object->id).'");
3478  fd.append("element", "'.dol_escape_js($object->element).'");
3479  fd.append("token", "'.currentToken().'");
3480  fd.append("action", "linkit");
3481 
3482  var dataTransfer = e.originalEvent.dataTransfer;
3483 
3484  if (dataTransfer.files && dataTransfer.files.length){
3485  var droppedFiles = e.originalEvent.dataTransfer.files;
3486  $.each(droppedFiles, function(index,file){
3487  fd.append("files[]", file,file.name)
3488  });
3489  }
3490  $(".cssDragDropArea").removeClass("highlightDragDropArea");
3491  counterdragdrop = 0;
3492  $.ajax({
3493  url: "'.DOL_URL_ROOT.'/core/ajax/fileupload.php",
3494  type: "POST",
3495  processData: false,
3496  contentType: false,
3497  data: fd,
3498  success:function() {
3499  console.log("Uploaded.", arguments);
3500  /* arguments[0] is the json string of files */
3501  /* arguments[1] is the value for variable "success", can be 0 or 1 */
3502  let listoffiles = JSON.parse(arguments[0]);
3503  console.log(listoffiles);
3504  let nboferror = 0;
3505  for (let i = 0; i < listoffiles.length; i++) {
3506  console.log(listoffiles[i].error);
3507  if (listoffiles[i].error) {
3508  nboferror++;
3509  }
3510  }
3511  console.log(nboferror);
3512  if (nboferror > 0) {
3513  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorOnAtLeastOneFileUpload:warnings";
3514  } else {
3515  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=UploadFileDragDropSuccess:mesgs";
3516  }
3517  },
3518  error:function() {
3519  console.log("Error Uploading.", arguments)
3520  if (arguments[0].status == 403) {
3521  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadPermissionDenied:errors";
3522  }
3523  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadFileDragDropPermissionDenied:errors";
3524  },
3525  })
3526  });
3527  });
3528  ';
3529  $out .= "</script>\n";
3530  return $out;
3531 }
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:3364
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:1614
dolCheckVirus($src_file)
Check virus into a file.
Definition: files.lib.php:1157
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition: files.lib.php:37
getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path='', $pathref='', &$checksumconcat=array())
Function to get list of updated or modified files.
Definition: files.lib.php:3381
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:1485
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:1334
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:1196
dol_move_dir($srcdir, $destdir, $overwriteifexists=1, $indexdatabase=1, $renamedircontent=1)
Move a directory into another name.
Definition: files.lib.php:1083
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:1460
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:2543
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
Definition: files.lib.php:2278
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:1699
addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded', $setsharekey=0, $object=null)
Add a file into database index.
Definition: files.lib.php:1972
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
Definition: files.lib.php:2092
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:2524
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:3318
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:3425
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:1142
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:1914
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:2033
dol_readcachefile($directory, $filename)
Read object from cachefile.
Definition: files.lib.php:3351
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:1737
dol_cache_refresh($directory, $filename, $cachetime)
Test if Refresh needed.
Definition: files.lib.php:3336
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1537
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:947
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.