dolibarr  18.0.0
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 }
dol_move_dir
dol_move_dir($srcdir, $destdir, $overwriteifexists=1, $indexdatabase=1, $renamedircontent=1)
Move a directory into another name.
Definition: files.lib.php:1083
make_substitutions
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
Definition: functions.lib.php:8366
dol_fileperm
dol_fileperm($pathoffile)
Return permissions of a file.
Definition: files.lib.php:611
dol_is_url
dol_is_url($url)
Return if path is an URL.
Definition: files.lib.php:507
dol_sanitizePathName
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
Definition: functions.lib.php:1349
dol_basename
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition: files.lib.php:37
getDefaultImageSizes
getDefaultImageSizes()
Return default values for image sizes.
Definition: images.lib.php:38
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1323
Project
Class to manage projects.
Definition: project.class.php:36
ActionComm
Class to manage agenda events (actions)
Definition: actioncomm.class.php:38
dol_delete_dir_recursive
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_count_nb_of_line
dol_count_nb_of_line($file)
Count number of lines in a file.
Definition: files.lib.php:556
dol_osencode
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
Definition: functions.lib.php:9055
dol_filemtime
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:599
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:609
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5107
dol_uncompress
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
Definition: files.lib.php:2278
dolReplaceInFile
dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
Definition: files.lib.php:629
dol_sort_array
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...
Definition: functions.lib.php:8922
Utils
Class to manage utility methods.
Definition: utils.class.php:30
dol_add_file_process
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_dir_list
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
Task
Class to manage tasks.
Definition: task.class.php:39
dol_mimetype
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
Definition: functions.lib.php:10370
image_format_supported
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Definition: images.lib.php:80
dol_most_recent_file
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_link
dol_is_link($pathoffile)
Return if path is a symbolic link.
Definition: files.lib.php:495
dol_copy
dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
Definition: files.lib.php:717
dol_is_file
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:483
getRandomPassword
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
Definition: security2.lib.php:487
dol_readcachefile
dol_readcachefile($directory, $filename)
Read object from cachefile.
Definition: files.lib.php:3351
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2675
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4135
dolChmod
dolChmod($filepath, $newmask='')
Change mod of a file.
Definition: functions.lib.php:7007
dol_compare_file
dol_compare_file($a, $b)
Fast compare of 2 files identified by their properties ->name, ->date and ->size.
Definition: files.lib.php:410
getDolUserInt
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
Definition: functions.lib.php:190
dol_unescapefile
dol_unescapefile($filename)
Unescape a file submitted by upload.
Definition: files.lib.php:1142
utf8_check
utf8_check($str)
Check if a string is in UTF8.
Definition: functions.lib.php:8978
dol_init_file_process
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
dol_delete_file
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
deleteFilesIntoDatabaseIndex
deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded')
Delete files into database index using search criterias.
Definition: files.lib.php:2033
dol_hash
dol_hash($chain, $type='0')
Returns a hash (non reversible encryption) of a string.
Definition: security.lib.php:221
Exception
getFilesUpdated
getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path='', $pathref='', &$checksumconcat=array())
Function to get list of updated or modified files.
Definition: files.lib.php:3381
dol_move_uploaded_file
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_is_dir_empty
dol_is_dir_empty($dir)
Return if path is empty.
Definition: files.lib.php:469
dol_escape_js
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
Definition: functions.lib.php:1546
addFileIntoDatabaseIndex
addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded', $setsharekey=0, $object=null)
Add a file into database index.
Definition: files.lib.php:1972
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:266
dol_convert_file
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
Definition: files.lib.php:2092
Holiday
Class of the module paid holiday.
Definition: holiday.class.php:34
dol_filecache
dol_filecache($directory, $filename, $object)
Store object in file.
Definition: files.lib.php:3318
dol_meta_create
dol_meta_create($object)
Create a meta file with document file into same directory.
Definition: files.lib.php:1614
AntiVir
Class to scan for virus.
Definition: antivir.class.php:30
dol_delete_dir
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
Definition: files.lib.php:1460
dol_dir_is_emtpy
dol_dir_is_emtpy($folder)
Test if a folder is empty.
Definition: files.lib.php:524
completeFileArrayWithDatabaseInfo
completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
Complete $filearray with data from database.
Definition: files.lib.php:315
dol_string_nohtmltag
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
Definition: functions.lib.php:7046
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
dolCopyDir
dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null, $excludesubdir=0, $excludefileext=null)
Copy a dir to another dir.
Definition: files.lib.php:845
dol_cache_refresh
dol_cache_refresh($directory, $filename, $cachetime)
Test if Refresh needed.
Definition: files.lib.php:3336
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
Definition: functions.lib.php:8673
EcmFiles
Class to manage ECM files.
Definition: ecmfiles.class.php:35
isAFileWithExecutableContent
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
Definition: functions.lib.php:11638
$sql
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
dol_check_secure_access_document
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_dir_list_in_database
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
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
dol_remove_file_process
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
User
Class to manage Dolibarr users.
Definition: user.class.php:47
dol_filesize
dol_filesize($pathoffile)
Return size of a file.
Definition: files.lib.php:587
dolCheckVirus
dolCheckVirus($src_file)
Check virus into a file.
Definition: files.lib.php:1157
dol_delete_preview
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1537
ExpenseReport
Class to manage Trips and Expenses.
Definition: expensereport.class.php:36
dragAndDropFileUpload
dragAndDropFileUpload($htmlname)
Function to manage the drag and drop of a file.
Definition: files.lib.php:3425
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3056
checkUserAccessToObject
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.
Definition: security.lib.php:823
dol_is_dir
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:453
dirbasename
dirbasename($pathfile)
Return the relative dirname (relative to DOL_DATA_ROOT) of a full path string.
Definition: files.lib.php:3364
FormMail
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Definition: html.formmail.class.php:40
dol_mkdir
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Definition: functions.lib.php:6936
vignette
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
currentToken
currentToken()
Return the value of token currently saved into session with name 'token'.
Definition: functions.lib.php:11666
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
dol_move
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:947