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