dolibarr  20.0.0-beta
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-2024 Frédéric France <frederic.france@free.fr>
8  * Copyright (C) 2023 Lenin Rivas <lenin.rivas777@gmail.com>
9  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <https://www.gnu.org/licenses/>.
23  * or see https://www.gnu.org/
24  */
25 
38 function dol_basename($pathfile)
39 {
40  return preg_replace('/^.*\/([^\/]+)$/', '$1', rtrim($pathfile, '/'));
41 }
42 
63 function dol_dir_list($utf8_path, $types = "all", $recursive = 0, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0, $nohook = 0, $relativename = "", $donotfollowsymlinks = 0, $nbsecondsold = 0)
64 {
65  global $db, $hookmanager;
66  global $object;
67 
68  if ($recursive <= 1) { // Avoid too verbose log
69  // Verify filters (only on first call to function)
70  $filters_ok = true;
71  $error_info = "";
72  // Ensure we have an array for the exclusions
73  $exclude_array = ($excludefilter === null || $excludefilter === '') ? array() : (is_array($excludefilter) ? $excludefilter : array($excludefilter));
74  foreach ((array($filter) + $exclude_array) as $f) {
75  // Check that all '/' are escaped.
76  if ((int) preg_match('/(?:^|[^\\\\])\//', $f) > 0) {
77  $filters_ok = false;
78  $error_info .= " error='$f unescaped_slash'";
79  dol_syslog("'$f' has unescaped '/'", LOG_ERR);
80  }
81  }
82  dol_syslog("files.lib.php::dol_dir_list path=".$utf8_path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter).$error_info);
83  // print 'xxx'."files.lib.php::dol_dir_list path=".$utf8_path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($exclude_array);
84  if (!$filters_ok) {
85  // Return empty array when filters are invalid
86  return array();
87  }
88  } else {
89  // Already computed before
90  $exclude_array = ($excludefilter === null || $excludefilter === '') ? array() : (is_array($excludefilter) ? $excludefilter : array($excludefilter));
91  }
92 
93  // Define excludefilterarray (before while, for speed)
94  $excludefilterarray = array_merge(array('^\.'), $exclude_array);
95 
96  $loaddate = ($mode == 1 || $mode == 2 || $nbsecondsold != 0 || $sortcriteria == 'date');
97  $loadsize = ($mode == 1 || $mode == 3 || $sortcriteria == 'size');
98  $loadperm = ($mode == 1 || $mode == 4 || $sortcriteria == 'perm');
99 
100  // Clean parameters
101  $utf8_path = preg_replace('/([\\/]+)$/', '', $utf8_path);
102  $os_path = dol_osencode($utf8_path);
103  $now = dol_now();
104 
105  $reshook = 0;
106  $file_list = array();
107 
108  if (!$nohook && $hookmanager instanceof HookManager) {
109  $hookmanager->resArray = array();
110 
111  $hookmanager->initHooks(array('fileslib'));
112 
113  $parameters = array(
114  'path' => $os_path,
115  'types' => $types,
116  'recursive' => $recursive,
117  'filter' => $filter,
118  'excludefilter' => $exclude_array, // Already converted to array.
119  'sortcriteria' => $sortcriteria,
120  'sortorder' => $sortorder,
121  'loaddate' => $loaddate,
122  'loadsize' => $loadsize,
123  'mode' => $mode
124  );
125  $reshook = $hookmanager->executeHooks('getDirList', $parameters, $object);
126  }
127 
128  // $hookmanager->resArray may contain array stacked by other modules
129  if (empty($reshook)) {
130  if (!is_dir($os_path)) {
131  return array();
132  }
133 
134  if (($dir = opendir($os_path)) === false) {
135  return array();
136  } else {
137  $filedate = '';
138  $filesize = '';
139  $fileperm = '';
140 
141  while (false !== ($os_file = readdir($dir))) { // $utf8_file is always a basename (in directory $os_path)
142  $os_fullpathfile = ($os_path ? $os_path.'/' : '').$os_file;
143 
144  if (!utf8_check($os_file)) {
145  $utf8_file = mb_convert_encoding($os_file, 'UTF-8', 'ISO-8859-1'); // Make sure data is stored in utf8 in memory
146  } else {
147  $utf8_file = $os_file;
148  }
149 
150  $qualified = 1;
151 
152  $utf8_fullpathfile = "$utf8_path/$utf8_file"; // Temp variable for speed
153 
154  // Check if file is qualified
155  foreach ($excludefilterarray as $filt) {
156  if (preg_match('/'.$filt.'/i', $utf8_file) || preg_match('/'.$filt.'/i', $utf8_fullpathfile)) {
157  $qualified = 0;
158  break;
159  }
160  }
161  //print $utf8_fullpathfile.' '.$utf8_file.' '.$qualified.'<br>';
162 
163  if ($qualified) {
164  $isdir = is_dir($os_fullpathfile);
165  // Check whether this is a file or directory and whether we're interested in that type
166  if ($isdir) {
167  // Add entry into file_list array
168  if (($types == "directories") || ($types == "all")) {
169  if ($loaddate || $sortcriteria == 'date') {
170  $filedate = dol_filemtime($utf8_fullpathfile);
171  }
172  if ($loadsize || $sortcriteria == 'size') {
173  $filesize = dol_filesize($utf8_fullpathfile);
174  }
175  if ($loadperm || $sortcriteria == 'perm') {
176  $fileperm = dol_fileperm($utf8_fullpathfile);
177  }
178 
179  if (!$filter || preg_match('/'.$filter.'/i', $utf8_file)) { // We do not search key $filter into all $path, only into $file part
180  $reg = array();
181  preg_match('/([^\/]+)\/[^\/]+$/', $utf8_fullpathfile, $reg);
182  $level1name = (isset($reg[1]) ? $reg[1] : '');
183  $file_list[] = array(
184  "name" => $utf8_file,
185  "path" => $utf8_path,
186  "level1name" => $level1name,
187  "relativename" => ($relativename ? $relativename.'/' : '').$utf8_file,
188  "fullname" => $utf8_fullpathfile,
189  "date" => $filedate,
190  "size" => $filesize,
191  "perm" => $fileperm,
192  "type" => 'dir'
193  );
194  }
195  }
196 
197  // if we're in a directory and we want recursive behavior, call this function again
198  if ($recursive > 0) {
199  if (empty($donotfollowsymlinks) || !is_link($os_fullpathfile)) {
200  //var_dump('eee '. $utf8_fullpathfile. ' '.is_dir($utf8_fullpathfile).' '.is_link($utf8_fullpathfile));
201  $file_list = array_merge($file_list, dol_dir_list($utf8_fullpathfile, $types, $recursive + 1, $filter, $exclude_array, $sortcriteria, $sortorder, $mode, $nohook, ($relativename != '' ? $relativename.'/' : '').$utf8_file, $donotfollowsymlinks, $nbsecondsold));
202  }
203  }
204  } elseif (in_array($types, array("files", "all"))) {
205  // Add file into file_list array
206  if ($loaddate || $sortcriteria == 'date') {
207  $filedate = dol_filemtime($utf8_fullpathfile);
208  }
209  if ($loadsize || $sortcriteria == 'size') {
210  $filesize = dol_filesize($utf8_fullpathfile);
211  }
212 
213  if (!$filter || preg_match('/'.$filter.'/i', $utf8_file)) { // We do not search key $filter into $utf8_path, only into $utf8_file
214  if (empty($nbsecondsold) || $filedate <= ($now - $nbsecondsold)) {
215  preg_match('/([^\/]+)\/[^\/]+$/', $utf8_fullpathfile, $reg);
216  $level1name = (isset($reg[1]) ? $reg[1] : '');
217  $file_list[] = array(
218  "name" => $utf8_file,
219  "path" => $utf8_path,
220  "level1name" => $level1name,
221  "relativename" => ($relativename ? $relativename.'/' : '').$utf8_file,
222  "fullname" => $utf8_fullpathfile,
223  "date" => $filedate,
224  "size" => $filesize,
225  "type" => 'file'
226  );
227  }
228  }
229  }
230  }
231  }
232  closedir($dir);
233 
234  // Obtain a list of columns
235  if (!empty($sortcriteria) && $sortorder) {
236  $file_list = dol_sort_array($file_list, $sortcriteria, ($sortorder == SORT_ASC ? 'asc' : 'desc'));
237  }
238  }
239  }
240 
241  if ($hookmanager instanceof HookManager && is_array($hookmanager->resArray)) {
242  $file_list = array_merge($file_list, $hookmanager->resArray);
243  }
244 
245  return $file_list;
246 }
247 
248 
262 function dol_dir_list_in_database($path, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0)
263 {
264  global $conf, $db;
265 
266 
267  $sql = " SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams,";
268  $sql .= " date_c, tms as date_m, fk_user_c, fk_user_m, acl, position, share";
269  if ($mode) {
270  $sql .= ", description";
271  }
272  $sql .= " FROM ".MAIN_DB_PREFIX."ecm_files";
273  $sql .= " WHERE entity = ".$conf->entity;
274  if (preg_match('/%$/', $path)) {
275  $sql .= " AND filepath LIKE '".$db->escape($path)."'";
276  } else {
277  $sql .= " AND filepath = '".$db->escape($path)."'";
278  }
279 
280  $resql = $db->query($sql);
281  if ($resql) {
282  $file_list = array();
283  $num = $db->num_rows($resql);
284  $i = 0;
285  while ($i < $num) {
286  $obj = $db->fetch_object($resql);
287  if ($obj) {
288  $reg = array();
289  preg_match('/([^\/]+)\/[^\/]+$/', DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename, $reg);
290  $level1name = (isset($reg[1]) ? $reg[1] : '');
291  $file_list[] = array(
292  "rowid" => $obj->rowid,
293  "label" => $obj->label, // md5
294  "name" => $obj->filename,
295  "path" => DOL_DATA_ROOT.'/'.$obj->filepath,
296  "level1name" => $level1name,
297  "fullname" => DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,
298  "fullpath_orig" => $obj->fullpath_orig,
299  "date_c" => $db->jdate($obj->date_c),
300  "date_m" => $db->jdate($obj->date_m),
301  "type" => 'file',
302  "keywords" => $obj->keywords,
303  "cover" => $obj->cover,
304  "position" => (int) $obj->position,
305  "acl" => $obj->acl,
306  "share" => $obj->share,
307  "description" => ($mode ? $obj->description : '')
308  );
309  }
310  $i++;
311  }
312 
313  // Obtain a list of columns
314  if (!empty($sortcriteria)) {
315  $myarray = array();
316  foreach ($file_list as $key => $row) {
317  $myarray[$key] = (isset($row[$sortcriteria]) ? $row[$sortcriteria] : '');
318  }
319  // Sort the data
320  if ($sortorder) {
321  array_multisort($myarray, $sortorder, SORT_REGULAR, $file_list);
322  }
323  }
324 
325  return $file_list;
326  } else {
327  dol_print_error($db);
328  return array();
329  }
330 }
331 
332 
341 function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
342 {
343  global $conf, $db, $user;
344 
345  $filearrayindatabase = dol_dir_list_in_database($relativedir, '', null, 'name', SORT_ASC);
346 
347  // TODO Remove this when PRODUCT_USE_OLD_PATH_FOR_PHOTO will be removed
348  global $modulepart;
349  if ($modulepart == 'produit' && getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
350  global $object;
351  if (!empty($object->id)) {
352  if (isModEnabled("product")) {
353  $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";
354  } else {
355  $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";
356  }
357 
358  $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dirold);
359  $relativedirold = preg_replace('/^[\\/]/', '', $relativedirold);
360 
361  $filearrayindatabase = array_merge($filearrayindatabase, dol_dir_list_in_database($relativedirold, '', null, 'name', SORT_ASC));
362  }
363  } elseif ($modulepart == 'ticket') {
364  foreach ($filearray as $key => $val) {
365  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filearray[$key]['path']);
366  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
367  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
368  if ($rel_dir != $relativedir) {
369  $filearrayindatabase = array_merge($filearrayindatabase, dol_dir_list_in_database($rel_dir, '', null, 'name', SORT_ASC));
370  }
371  }
372  }
373 
374  //var_dump($relativedir);
375  //var_dump($filearray);
376  //var_dump($filearrayindatabase);
377 
378  // Complete filearray with properties found into $filearrayindatabase
379  foreach ($filearray as $key => $val) {
380  $tmpfilename = preg_replace('/\.noexe$/', '', $filearray[$key]['name']);
381  $found = 0;
382  // Search if it exists into $filearrayindatabase
383  foreach ($filearrayindatabase as $key2 => $val2) {
384  if (($filearrayindatabase[$key2]['path'] == $filearray[$key]['path']) && ($filearrayindatabase[$key2]['name'] == $tmpfilename)) {
385  $filearray[$key]['position_name'] = ($filearrayindatabase[$key2]['position'] ? $filearrayindatabase[$key2]['position'] : '0').'_'.$filearrayindatabase[$key2]['name'];
386  $filearray[$key]['position'] = $filearrayindatabase[$key2]['position'];
387  $filearray[$key]['cover'] = $filearrayindatabase[$key2]['cover'];
388  $filearray[$key]['keywords'] = $filearrayindatabase[$key2]['keywords'];
389  $filearray[$key]['acl'] = $filearrayindatabase[$key2]['acl'];
390  $filearray[$key]['rowid'] = $filearrayindatabase[$key2]['rowid'];
391  $filearray[$key]['label'] = $filearrayindatabase[$key2]['label'];
392  $filearray[$key]['share'] = $filearrayindatabase[$key2]['share'];
393  $found = 1;
394  break;
395  }
396  }
397 
398  if (!$found) { // This happen in transition toward version 6, or if files were added manually into os dir.
399  $filearray[$key]['position'] = '999999'; // File not indexed are at end. So if we add a file, it will not replace an existing position
400  $filearray[$key]['cover'] = 0;
401  $filearray[$key]['acl'] = '';
402  $filearray[$key]['share'] = 0;
403 
404  $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filearray[$key]['fullname']);
405 
406  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filename)) { // If not a tmp file
407  dol_syslog("list_of_documents We found a file called '".$filearray[$key]['name']."' not indexed into database. We add it");
408  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
409  $ecmfile = new EcmFiles($db);
410 
411  // Add entry into database
412  $filename = basename($rel_filename);
413  $rel_dir = dirname($rel_filename);
414  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
415  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
416 
417  $ecmfile->filepath = $rel_dir;
418  $ecmfile->filename = $filename;
419  $ecmfile->label = md5_file(dol_osencode($filearray[$key]['fullname'])); // $destfile is a full path to file
420  $ecmfile->fullpath_orig = $filearray[$key]['fullname'];
421  $ecmfile->gen_or_uploaded = 'unknown';
422  $ecmfile->description = ''; // indexed content
423  $ecmfile->keywords = ''; // keyword content
424  $result = $ecmfile->create($user);
425  if ($result < 0) {
426  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
427  } else {
428  $filearray[$key]['rowid'] = $result;
429  }
430  } else {
431  $filearray[$key]['rowid'] = 0; // Should not happened
432  }
433  }
434  }
435  //var_dump($filearray); var_dump($relativedir.' - tmpfilename='.$tmpfilename.' - found='.$found);
436 }
437 
438 
446 function dol_compare_file($a, $b)
447 {
448  global $sortorder, $sortfield;
449 
450  $sortorder = strtoupper($sortorder);
451 
452  if ($sortorder == 'ASC') {
453  $retup = -1;
454  $retdown = 1;
455  } else {
456  $retup = 1;
457  $retdown = -1;
458  }
459 
460  if ($sortfield == 'name') {
461  if ($a->name == $b->name) {
462  return 0;
463  }
464  return ($a->name < $b->name) ? $retup : $retdown;
465  }
466  if ($sortfield == 'date') {
467  if ($a->date == $b->date) {
468  return 0;
469  }
470  return ($a->date < $b->date) ? $retup : $retdown;
471  }
472  if ($sortfield == 'size') {
473  if ($a->size == $b->size) {
474  return 0;
475  }
476  return ($a->size < $b->size) ? $retup : $retdown;
477  }
478 
479  return 0;
480 }
481 
482 
489 function dol_is_dir($folder)
490 {
491  $newfolder = dol_osencode($folder);
492  if (is_dir($newfolder)) {
493  return true;
494  } else {
495  return false;
496  }
497 }
498 
505 function dol_is_dir_empty($dir)
506 {
507  if (!is_readable($dir)) {
508  return false;
509  }
510  return (count(scandir($dir)) == 2);
511 }
512 
519 function dol_is_file($pathoffile)
520 {
521  $newpathoffile = dol_osencode($pathoffile);
522  return is_file($newpathoffile);
523 }
524 
531 function dol_is_link($pathoffile)
532 {
533  $newpathoffile = dol_osencode($pathoffile);
534  return is_link($newpathoffile);
535 }
536 
543 function dol_is_writable($folderorfile)
544 {
545  $newfolderorfile = dol_osencode($folderorfile);
546  return is_writable($newfolderorfile);
547 }
548 
557 function dol_is_url($uri)
558 {
559  $prots = array('file', 'http', 'https', 'ftp', 'zlib', 'data', 'ssh', 'ssh2', 'ogg', 'expect');
560  return false !== preg_match('/^('.implode('|', $prots).'):/i', $uri);
561 }
562 
569 function dol_dir_is_emtpy($folder)
570 {
571  $newfolder = dol_osencode($folder);
572  if (is_dir($newfolder)) {
573  $handle = opendir($newfolder);
574  $folder_content = '';
575  $name_array = [];
576  while ((gettype($name = readdir($handle)) != "boolean")) {
577  $name_array[] = $name;
578  }
579  foreach ($name_array as $temp) {
580  $folder_content .= $temp;
581  }
582 
583  closedir($handle);
584 
585  if ($folder_content == "...") {
586  return true;
587  } else {
588  return false;
589  }
590  } else {
591  return true; // Dir does not exists
592  }
593 }
594 
602 function dol_count_nb_of_line($file)
603 {
604  $nb = 0;
605 
606  $newfile = dol_osencode($file);
607  //print 'x'.$file;
608  $fp = fopen($newfile, 'r');
609  if ($fp) {
610  while (!feof($fp)) {
611  $line = fgets($fp);
612  // Increase count only if read was success.
613  // Test needed because feof returns true only after fgets
614  // so we do n+1 fgets for a file with n lines.
615  if ($line !== false) {
616  $nb++;
617  }
618  }
619  fclose($fp);
620  } else {
621  $nb = -1;
622  }
623 
624  return $nb;
625 }
626 
627 
635 function dol_filesize($pathoffile)
636 {
637  $newpathoffile = dol_osencode($pathoffile);
638  return filesize($newpathoffile);
639 }
640 
647 function dol_filemtime($pathoffile)
648 {
649  $newpathoffile = dol_osencode($pathoffile);
650  return @filemtime($newpathoffile); // @Is to avoid errors if files does not exists
651 }
652 
659 function dol_fileperm($pathoffile)
660 {
661  $newpathoffile = dol_osencode($pathoffile);
662  return fileperms($newpathoffile);
663 }
664 
677 function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask = '0', $indexdatabase = 0, $arrayreplacementisregex = 0)
678 {
679  dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase." arrayreplacementisregex=".$arrayreplacementisregex);
680 
681  if (empty($srcfile)) {
682  return -1;
683  }
684  if (empty($destfile)) {
685  $destfile = $srcfile;
686  }
687 
688  // Clean the aa/bb/../cc into aa/cc
689  $srcfile = preg_replace('/\.\.\/?/', '', $srcfile);
690  $destfile = preg_replace('/\.\.\/?/', '', $destfile);
691 
692  $destexists = dol_is_file($destfile);
693  if (($destfile != $srcfile) && $destexists) {
694  return 0;
695  }
696 
697  $srcexists = dol_is_file($srcfile);
698  if (!$srcexists) {
699  dol_syslog("files.lib.php::dolReplaceInFile failed to read src file", LOG_WARNING);
700  return -3;
701  }
702 
703  $tmpdestfile = $destfile.'.tmp';
704 
705  $newpathofsrcfile = dol_osencode($srcfile);
706  $newpathoftmpdestfile = dol_osencode($tmpdestfile);
707  $newpathofdestfile = dol_osencode($destfile);
708  $newdirdestfile = dirname($newpathofdestfile);
709 
710  if ($destexists && !is_writable($newpathofdestfile)) {
711  dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to overwrite target file", LOG_WARNING);
712  return -1;
713  }
714  if (!is_writable($newdirdestfile)) {
715  dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
716  return -2;
717  }
718 
719  dol_delete_file($tmpdestfile);
720 
721  // Create $newpathoftmpdestfile from $newpathofsrcfile
722  $content = file_get_contents($newpathofsrcfile);
723 
724  if (empty($arrayreplacementisregex)) {
725  $content = make_substitutions($content, $arrayreplacement, null);
726  } else {
727  foreach ($arrayreplacement as $key => $value) {
728  $content = preg_replace($key, $value, $content);
729  }
730  }
731 
732  file_put_contents($newpathoftmpdestfile, $content);
733  dolChmod($newpathoftmpdestfile, $newmask);
734 
735  // Rename
736  $result = dol_move($newpathoftmpdestfile, $newpathofdestfile, $newmask, (($destfile == $srcfile) ? 1 : 0), 0, $indexdatabase);
737  if (!$result) {
738  dol_syslog("files.lib.php::dolReplaceInFile failed to move tmp file to final dest", LOG_WARNING);
739  return -3;
740  }
741  if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
742  $newmask = getDolGlobalString('MAIN_UMASK');
743  }
744  if (empty($newmask)) { // This should no happen
745  dol_syslog("Warning: dolReplaceInFile called with empty value for newmask and no default value defined", LOG_WARNING);
746  $newmask = '0664';
747  }
748 
749  dolChmod($newpathofdestfile, $newmask);
750 
751  return 1;
752 }
753 
754 
767 function dol_copy($srcfile, $destfile, $newmask = '0', $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 0)
768 {
769  global $db, $user;
770 
771  dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
772 
773  if (empty($srcfile) || empty($destfile)) {
774  return -1;
775  }
776 
777  $destexists = dol_is_file($destfile);
778  if (!$overwriteifexists && $destexists) {
779  return 0;
780  }
781 
782  $newpathofsrcfile = dol_osencode($srcfile);
783  $newpathofdestfile = dol_osencode($destfile);
784  $newdirdestfile = dirname($newpathofdestfile);
785 
786  if ($destexists && !is_writable($newpathofdestfile)) {
787  dol_syslog("files.lib.php::dol_copy failed Permission denied to overwrite target file", LOG_WARNING);
788  return -1;
789  }
790  if (!is_writable($newdirdestfile)) {
791  dol_syslog("files.lib.php::dol_copy failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
792  return -2;
793  }
794 
795  // Check virus
796  $testvirusarray = array();
797  if ($testvirus) {
798  $testvirusarray = dolCheckVirus($srcfile, $destfile);
799  if (count($testvirusarray)) {
800  dol_syslog("files.lib.php::dol_copy canceled because a virus was found into source file. we ignore the copy request.", LOG_WARNING);
801  return -3;
802  }
803  }
804 
805  // Copy with overwriting if exists
806  $result = @copy($newpathofsrcfile, $newpathofdestfile);
807  //$result=copy($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
808  if (!$result) {
809  dol_syslog("files.lib.php::dol_copy failed to copy", LOG_WARNING);
810  return -3;
811  }
812  if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
813  $newmask = getDolGlobalString('MAIN_UMASK');
814  }
815  if (empty($newmask)) { // This should no happen
816  dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
817  $newmask = '0664';
818  }
819 
820  dolChmod($newpathofdestfile, $newmask);
821 
822  if ($result && $indexdatabase) {
823  // Add entry into ecm database
824  $rel_filetocopyafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $newpathofdestfile);
825  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetocopyafter)) { // If not a tmp file
826  $rel_filetocopyafter = preg_replace('/^[\\/]/', '', $rel_filetocopyafter);
827  //var_dump($rel_filetorenamebefore.' - '.$rel_filetocopyafter);exit;
828 
829  dol_syslog("Try to copy also entries in database for: ".$rel_filetocopyafter, LOG_DEBUG);
830  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
831 
832  $ecmfiletarget = new EcmFiles($db);
833  $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetocopyafter);
834  if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created.
835  dol_syslog("ECM dest file found, remove it", LOG_DEBUG);
836  $ecmfiletarget->delete($user);
837  } else {
838  dol_syslog("ECM dest file not found, create it", LOG_DEBUG);
839  }
840 
841  $ecmSrcfile = new EcmFiles($db);
842  $resultecm = $ecmSrcfile->fetch(0, '', $srcfile);
843  if ($resultecm) {
844  dol_syslog("Fetch src file ok", LOG_DEBUG);
845  } else {
846  dol_syslog("Fetch src file error", LOG_DEBUG);
847  }
848 
849  $ecmfile = new EcmFiles($db);
850  $filename = basename($rel_filetocopyafter);
851  $rel_dir = dirname($rel_filetocopyafter);
852  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
853  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
854 
855  $ecmfile->filepath = $rel_dir;
856  $ecmfile->filename = $filename;
857  $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
858  $ecmfile->fullpath_orig = $srcfile;
859  $ecmfile->gen_or_uploaded = 'copy';
860  $ecmfile->description = $ecmSrcfile->description;
861  $ecmfile->keywords = $ecmSrcfile->keywords;
862  $resultecm = $ecmfile->create($user);
863  if ($resultecm < 0) {
864  dol_syslog("Create ECM file ok", LOG_DEBUG);
865  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
866  } else {
867  dol_syslog("Create ECM file error", LOG_DEBUG);
868  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
869  }
870 
871  if ($resultecm > 0) {
872  $result = 1;
873  } else {
874  $result = -1;
875  }
876  }
877  }
878 
879  return (int) $result;
880 }
881 
896 function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null, $excludesubdir = 0, $excludefileext = null, $excludearchivefiles = 0)
897 {
898  $result = 0;
899 
900  dol_syslog("files.lib.php::dolCopyDir srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
901 
902  if (empty($srcfile) || empty($destfile)) {
903  return -1;
904  }
905 
906  $destexists = dol_is_dir($destfile);
907 
908  //if (! $overwriteifexists && $destexists) return 0; // The overwriteifexists is for files only, so propagated to dol_copy only.
909 
910  if (!$destexists) {
911  // We must set mask just before creating dir, because it can be set differently by dol_copy
912  umask(0);
913  $dirmaskdec = octdec($newmask);
914  if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
915  $dirmaskdec = octdec(getDolGlobalString('MAIN_UMASK'));
916  }
917  $dirmaskdec |= octdec('0200'); // Set w bit required to be able to create content for recursive subdirs files
918 
919  $result = dol_mkdir($destfile, '', decoct($dirmaskdec));
920 
921  if (!dol_is_dir($destfile)) {
922  // The output directory does not exists and we failed to create it. So we stop here.
923  return -1;
924  }
925  }
926 
927  $ossrcfile = dol_osencode($srcfile);
928  $osdestfile = dol_osencode($destfile);
929 
930  // Recursive function to copy all subdirectories and contents:
931  if (is_dir($ossrcfile)) {
932  $dir_handle = opendir($ossrcfile);
933  while ($file = readdir($dir_handle)) {
934  if ($file != "." && $file != ".." && !is_link($ossrcfile."/".$file)) {
935  if (is_dir($ossrcfile."/".$file)) {
936  if (empty($excludesubdir) || ($excludesubdir == 2 && strlen($file) == 2)) {
937  $newfile = $file;
938  // Replace destination filename with a new one
939  if (is_array($arrayreplacement)) {
940  foreach ($arrayreplacement as $key => $val) {
941  $newfile = str_replace($key, $val, $newfile);
942  }
943  }
944  //var_dump("xxx dolCopyDir $srcfile/$file, $destfile/$file, $newmask, $overwriteifexists");
945  $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists, $arrayreplacement, $excludesubdir, $excludefileext, $excludearchivefiles);
946  }
947  } else {
948  $newfile = $file;
949 
950  if (is_array($excludefileext)) {
951  $extension = pathinfo($file, PATHINFO_EXTENSION);
952  if (in_array($extension, $excludefileext)) {
953  //print "We exclude the file ".$file." because its extension is inside list ".join(', ', $excludefileext); exit;
954  continue;
955  }
956  }
957 
958  if ($excludearchivefiles == 1) {
959  $extension = pathinfo($file, PATHINFO_EXTENSION);
960  if (preg_match('/^[v|d]\d+$/', $extension)) {
961  continue;
962  }
963  }
964 
965  // Replace destination filename with a new one
966  if (is_array($arrayreplacement)) {
967  foreach ($arrayreplacement as $key => $val) {
968  $newfile = str_replace($key, $val, $newfile);
969  }
970  }
971  $tmpresult = dol_copy($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists);
972  }
973  // Set result
974  if ($result > 0 && $tmpresult >= 0) {
975  // Do nothing, so we don't set result to 0 if tmpresult is 0 and result was success in a previous pass
976  } else {
977  $result = $tmpresult;
978  }
979  if ($result < 0) {
980  break;
981  }
982  }
983  }
984  closedir($dir_handle);
985  } else {
986  // Source directory does not exists
987  $result = -2;
988  }
989 
990  return (int) $result;
991 }
992 
993 
1011 function dol_move($srcfile, $destfile, $newmask = '0', $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1, $moreinfo = array())
1012 {
1013  global $user, $db, $conf;
1014  $result = false;
1015 
1016  dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
1017  $srcexists = dol_is_file($srcfile);
1018  $destexists = dol_is_file($destfile);
1019 
1020  if (!$srcexists) {
1021  dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request.");
1022  return false;
1023  }
1024 
1025  if ($overwriteifexists || !$destexists) {
1026  $newpathofsrcfile = dol_osencode($srcfile);
1027  $newpathofdestfile = dol_osencode($destfile);
1028 
1029  // Check on virus
1030  $testvirusarray = array();
1031  if ($testvirus) {
1032  // Check using filename + antivirus
1033  $testvirusarray = dolCheckVirus($newpathofsrcfile, $newpathofdestfile);
1034  if (count($testvirusarray)) {
1035  dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. We ignore the move request.", LOG_WARNING);
1036  return false;
1037  }
1038  } else {
1039  // Check using filename only
1040  $testvirusarray = dolCheckOnFileName($newpathofsrcfile, $newpathofdestfile);
1041  if (count($testvirusarray)) {
1042  dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. We ignore the move request.", LOG_WARNING);
1043  return false;
1044  }
1045  }
1046 
1047  global $dolibarr_main_restrict_os_commands;
1048  if (!empty($dolibarr_main_restrict_os_commands)) {
1049  $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
1050  $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
1051  if (in_array(basename($destfile), $arrayofallowedcommand)) {
1052  //$langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1053  //setEventMessages($langs->trans("ErrorFilenameReserved", basename($destfile)), null, 'errors');
1054  dol_syslog("files.lib.php::dol_move canceled because target filename ".basename($destfile)." is using a reserved command name. we ignore the move request.", LOG_WARNING);
1055  return false;
1056  }
1057  }
1058 
1059  $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
1060  if (!$result) {
1061  if ($destexists) {
1062  dol_syslog("files.lib.php::dol_move Failed. We try to delete target first and move after.", LOG_WARNING);
1063  // We force delete and try again. Rename function sometimes fails to replace dest file with some windows NTFS partitions.
1064  dol_delete_file($destfile);
1065  $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
1066  } else {
1067  dol_syslog("files.lib.php::dol_move Failed.", LOG_WARNING);
1068  }
1069  }
1070 
1071  // Move ok
1072  if ($result && $indexdatabase) {
1073  // Rename entry into ecm database
1074  $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile);
1075  $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile);
1076  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) { // If not a tmp file
1077  $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore);
1078  $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter);
1079  //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);exit;
1080 
1081  dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG);
1082  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1083 
1084  $ecmfiletarget = new EcmFiles($db);
1085  $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetorenameafter);
1086  if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created.
1087  $ecmfiletarget->delete($user);
1088  }
1089 
1090  $ecmfile = new EcmFiles($db);
1091  $resultecm = $ecmfile->fetch(0, '', $rel_filetorenamebefore);
1092  if ($resultecm > 0) { // If an entry was found for src file, we use it to move entry
1093  $filename = basename($rel_filetorenameafter);
1094  $rel_dir = dirname($rel_filetorenameafter);
1095  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1096  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1097 
1098  $ecmfile->filepath = $rel_dir;
1099  $ecmfile->filename = $filename;
1100 
1101  $resultecm = $ecmfile->update($user);
1102  } elseif ($resultecm == 0) { // If no entry were found for src files, create/update target file
1103  $filename = basename($rel_filetorenameafter);
1104  $rel_dir = dirname($rel_filetorenameafter);
1105  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1106  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1107 
1108  $ecmfile->filepath = $rel_dir;
1109  $ecmfile->filename = $filename;
1110  $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
1111  $ecmfile->fullpath_orig = basename($srcfile);
1112  $ecmfile->gen_or_uploaded = 'uploaded';
1113  if (!empty($moreinfo) && !empty($moreinfo['description'])) {
1114  $ecmfile->description = $moreinfo['description']; // indexed content
1115  } else {
1116  $ecmfile->description = ''; // indexed content
1117  }
1118  if (!empty($moreinfo) && !empty($moreinfo['keywords'])) {
1119  $ecmfile->keywords = $moreinfo['keywords']; // indexed content
1120  } else {
1121  $ecmfile->keywords = ''; // keyword content
1122  }
1123  if (!empty($moreinfo) && !empty($moreinfo['note_private'])) {
1124  $ecmfile->note_private = $moreinfo['note_private'];
1125  }
1126  if (!empty($moreinfo) && !empty($moreinfo['note_public'])) {
1127  $ecmfile->note_public = $moreinfo['note_public'];
1128  }
1129  if (!empty($moreinfo) && !empty($moreinfo['src_object_type'])) {
1130  $ecmfile->src_object_type = $moreinfo['src_object_type'];
1131  }
1132  if (!empty($moreinfo) && !empty($moreinfo['src_object_id'])) {
1133  $ecmfile->src_object_id = $moreinfo['src_object_id'];
1134  }
1135 
1136  $resultecm = $ecmfile->create($user);
1137  if ($resultecm < 0) {
1138  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1139  }
1140  } elseif ($resultecm < 0) {
1141  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1142  }
1143 
1144  if ($resultecm > 0) {
1145  $result = true;
1146  } else {
1147  $result = false;
1148  }
1149  }
1150  }
1151 
1152  if (empty($newmask)) {
1153  $newmask = getDolGlobalString('MAIN_UMASK', '0755');
1154  }
1155 
1156  // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too)
1157  // to allow mask usage for dir, we should introduce a new param "isdir" to 1 to complete newmask like this
1158  // if ($isdir) $newmaskdec |= octdec('0111'); // Set x bit required for directories
1159  dolChmod($newpathofdestfile, $newmask);
1160  }
1161 
1162  return $result;
1163 }
1164 
1175 function dol_move_dir($srcdir, $destdir, $overwriteifexists = 1, $indexdatabase = 1, $renamedircontent = 1)
1176 {
1177  $result = false;
1178 
1179  dol_syslog("files.lib.php::dol_move_dir srcdir=".$srcdir." destdir=".$destdir." overwritifexists=".$overwriteifexists." indexdatabase=".$indexdatabase." renamedircontent=".$renamedircontent);
1180  $srcexists = dol_is_dir($srcdir);
1181  $srcbasename = basename($srcdir);
1182  $destexists = dol_is_dir($destdir);
1183 
1184  if (!$srcexists) {
1185  dol_syslog("files.lib.php::dol_move_dir srcdir does not exists. we ignore the move request.");
1186  return false;
1187  }
1188 
1189  if ($overwriteifexists || !$destexists) {
1190  $newpathofsrcdir = dol_osencode($srcdir);
1191  $newpathofdestdir = dol_osencode($destdir);
1192 
1193  $result = @rename($newpathofsrcdir, $newpathofdestdir);
1194 
1195  // Now we rename also contents inside dir after the move to match new destination name
1196  if ($result && $renamedircontent) {
1197  if (file_exists($newpathofdestdir)) {
1198  $destbasename = basename($newpathofdestdir);
1199  $files = dol_dir_list($newpathofdestdir);
1200  if (!empty($files) && is_array($files)) {
1201  foreach ($files as $key => $file) {
1202  if (!file_exists($file["fullname"])) {
1203  continue;
1204  }
1205  $filepath = $file["path"];
1206  $oldname = $file["name"];
1207 
1208  $newname = str_replace($srcbasename, $destbasename, $oldname);
1209  if (!empty($newname) && $newname !== $oldname) {
1210  if ($file["type"] == "dir") {
1211  $res = dol_move_dir($filepath.'/'.$oldname, $filepath.'/'.$newname, $overwriteifexists, $indexdatabase, $renamedircontent);
1212  } else {
1213  $res = dol_move($filepath.'/'.$oldname, $filepath.'/'.$newname, 0, $overwriteifexists, 0, $indexdatabase);
1214  }
1215  if (!$res) {
1216  return $result;
1217  }
1218  }
1219  }
1220  $result = true;
1221  }
1222  }
1223  }
1224  }
1225  return $result;
1226 }
1227 
1235 function dol_unescapefile($filename)
1236 {
1237  // Remove path information and dots around the filename, to prevent uploading
1238  // into different directories or replacing hidden system files.
1239  // Also remove control characters and spaces (\x00..\x20) around the filename:
1240  return trim(basename($filename), ".\x00..\x20");
1241 }
1242 
1243 
1251 function dolCheckVirus($src_file, $dest_file = '')
1252 {
1253  global $db;
1254 
1255  $reterrors = dolCheckOnFileName($src_file, $dest_file);
1256  if (!empty($reterrors)) {
1257  return $reterrors;
1258  }
1259 
1260  if (getDolGlobalString('MAIN_ANTIVIRUS_COMMAND')) {
1261  if (!class_exists('AntiVir')) {
1262  require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
1263  }
1264  $antivir = new AntiVir($db);
1265  $result = $antivir->dol_avscan_file($src_file);
1266  if ($result < 0) { // If virus or error, we stop here
1267  $reterrors = $antivir->errors;
1268  return $reterrors;
1269  }
1270  }
1271  return array();
1272 }
1273 
1281 function dolCheckOnFileName($src_file, $dest_file = '')
1282 {
1283  if (preg_match('/\.pdf$/i', $dest_file)) {
1284  if (!getDolGlobalString('MAIN_ANTIVIRUS_ALLOW_JS_IN_PDF')) {
1285  dol_syslog("dolCheckOnFileName Check that pdf does not contains js code");
1286 
1287  $tmp = file_get_contents(trim($src_file));
1288  if (preg_match('/[\n\s]+\/JavaScript[\n\s]+/m', $tmp)) {
1289  return array('File is a PDF with javascript inside');
1290  }
1291  } else {
1292  dol_syslog("dolCheckOnFileName Check js into pdf disabled");
1293  }
1294  }
1295 
1296  return array();
1297 }
1298 
1299 
1320 function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile', $upload_dir = '')
1321 {
1322  global $conf;
1323  global $object, $hookmanager;
1324 
1325  $reshook = 0;
1326  $file_name = $dest_file;
1327  $successcode = 1;
1328 
1329  if (empty($nohook)) {
1330  $reshook = $hookmanager->initHooks(array('fileslib'));
1331 
1332  $parameters = array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
1333  $reshook = $hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
1334  }
1335 
1336  if (empty($reshook)) {
1337  // If an upload error has been reported
1338  if ($uploaderrorcode) {
1339  switch ($uploaderrorcode) {
1340  case UPLOAD_ERR_INI_SIZE: // 1
1341  return 'ErrorFileSizeTooLarge';
1342  case UPLOAD_ERR_FORM_SIZE: // 2
1343  return 'ErrorFileSizeTooLarge';
1344  case UPLOAD_ERR_PARTIAL: // 3
1345  return 'ErrorPartialFile';
1346  case UPLOAD_ERR_NO_TMP_DIR: //
1347  return 'ErrorNoTmpDir';
1348  case UPLOAD_ERR_CANT_WRITE:
1349  return 'ErrorFailedToWriteInDir';
1350  case UPLOAD_ERR_EXTENSION:
1351  return 'ErrorUploadBlockedByAddon';
1352  default:
1353  break;
1354  }
1355  }
1356 
1357  // Security:
1358  // If we need to make a virus scan
1359  if (empty($disablevirusscan) && file_exists($src_file)) {
1360  $checkvirusarray = dolCheckVirus($src_file, $dest_file);
1361  if (count($checkvirusarray)) {
1362  dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.implode(',', $checkvirusarray), LOG_WARNING);
1363  return 'ErrorFileIsInfectedWithAVirus: '.implode(',', $checkvirusarray);
1364  }
1365  }
1366 
1367  // Security:
1368  // Disallow file with some extensions. We rename them.
1369  // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
1370  if (isAFileWithExecutableContent($dest_file) && !getDolGlobalString('MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED')) {
1371  // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
1372  $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
1373  if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
1374  $publicmediasdirwithslash .= '/';
1375  }
1376 
1377  if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
1378  $file_name .= '.noexe';
1379  $successcode = 2;
1380  }
1381  }
1382 
1383  // Security:
1384  // We refuse cache files/dirs, upload using .. and pipes into filenames.
1385  if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
1386  dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
1387  return -1;
1388  }
1389 
1390  // Security:
1391  // We refuse cache files/dirs, upload using .. and pipes into filenames.
1392  if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
1393  dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
1394  return -2;
1395  }
1396  }
1397 
1398  if ($reshook < 0) { // At least one blocking error returned by one hook
1399  $errmsg = implode(',', $hookmanager->errors);
1400  if (empty($errmsg)) {
1401  $errmsg = 'ErrorReturnedBySomeHooks'; // Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
1402  }
1403  return $errmsg;
1404  } elseif (empty($reshook)) {
1405  // The file functions must be in OS filesystem encoding.
1406  $src_file_osencoded = dol_osencode($src_file);
1407  $file_name_osencoded = dol_osencode($file_name);
1408 
1409  // Check if destination dir is writable
1410  if (!is_writable(dirname($file_name_osencoded))) {
1411  dol_syslog("Files.lib::dol_move_uploaded_file Dir ".dirname($file_name_osencoded)." is not writable. Return 'ErrorDirNotWritable'", LOG_WARNING);
1412  return 'ErrorDirNotWritable';
1413  }
1414 
1415  // Check if destination file already exists
1416  if (!$allowoverwrite) {
1417  if (file_exists($file_name_osencoded)) {
1418  dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
1419  return 'ErrorFileAlreadyExists';
1420  }
1421  } else { // We are allowed to erase
1422  if (is_dir($file_name_osencoded)) { // If there is a directory with name of file to create
1423  dol_syslog("Files.lib::dol_move_uploaded_file A directory with name ".$file_name." already exists. Return 'ErrorDirWithFileNameAlreadyExists'", LOG_WARNING);
1424  return 'ErrorDirWithFileNameAlreadyExists';
1425  }
1426  }
1427 
1428  // Move file
1429  $return = move_uploaded_file($src_file_osencoded, $file_name_osencoded);
1430  if ($return) {
1431  dolChmod($file_name_osencoded);
1432  dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=" . getDolGlobalString('MAIN_UMASK'), LOG_DEBUG);
1433  return $successcode; // Success
1434  } else {
1435  dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
1436  return -3; // Unknown error
1437  }
1438  }
1439 
1440  return $successcode; // Success
1441 }
1442 
1458 function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1, $nolog = 0)
1459 {
1460  global $db, $user, $langs;
1461  global $hookmanager;
1462 
1463  // Load translation files required by the page
1464  $langs->loadLangs(array('other', 'errors'));
1465 
1466  if (empty($nolog)) {
1467  dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook);
1468  }
1469 
1470  // Security:
1471  // We refuse transversal using .. and pipes into filenames.
1472  if ((!$allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file)) {
1473  dol_syslog("Refused to delete file ".$file, LOG_WARNING);
1474  return false;
1475  }
1476 
1477  $reshook = 0;
1478  if (empty($nohook) && !empty($hookmanager)) {
1479  $hookmanager->initHooks(array('fileslib'));
1480 
1481  $parameters = array(
1482  'file' => $file,
1483  'disableglob' => $disableglob,
1484  'nophperrors' => $nophperrors
1485  );
1486  $reshook = $hookmanager->executeHooks('deleteFile', $parameters, $object);
1487  }
1488 
1489  if (empty($nohook) && $reshook != 0) { // reshook = 0 to do standard actions, 1 = ok and replace, -1 = ko
1490  dol_syslog("reshook=".$reshook);
1491  if ($reshook < 0) {
1492  return false;
1493  }
1494  return true;
1495  } else {
1496  $file_osencoded = dol_osencode($file); // New filename encoded in OS filesystem encoding charset
1497  if (empty($disableglob) && !empty($file_osencoded)) {
1498  $ok = true;
1499  $globencoded = str_replace('[', '\[', $file_osencoded);
1500  $globencoded = str_replace(']', '\]', $globencoded);
1501  $listofdir = glob($globencoded);
1502  if (!empty($listofdir) && is_array($listofdir)) {
1503  foreach ($listofdir as $filename) {
1504  if ($nophperrors) {
1505  $ok = @unlink($filename);
1506  } else {
1507  $ok = unlink($filename);
1508  }
1509 
1510  // If it fails and it is because of the missing write permission on parent dir
1511  if (!$ok && file_exists(dirname($filename)) && !(fileperms(dirname($filename)) & 0200)) {
1512  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);
1513  dolChmod(dirname($filename), decoct(fileperms(dirname($filename)) | 0200));
1514  // Now we retry deletion
1515  if ($nophperrors) {
1516  $ok = @unlink($filename);
1517  } else {
1518  $ok = unlink($filename);
1519  }
1520  }
1521 
1522  if ($ok) {
1523  if (empty($nolog)) {
1524  dol_syslog("Removed file ".$filename, LOG_DEBUG);
1525  }
1526 
1527  // Delete entry into ecm database
1528  $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename);
1529  if (!preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) { // If not a tmp file
1530  if (is_object($db) && $indexdatabase) { // $db may not be defined when lib is in a context with define('NOREQUIREDB',1)
1531  $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete);
1532  $rel_filetodelete = preg_replace('/\.noexe$/', '', $rel_filetodelete);
1533 
1534  dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG);
1535  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1536  $ecmfile = new EcmFiles($db);
1537  $result = $ecmfile->fetch(0, '', $rel_filetodelete);
1538  if ($result >= 0 && $ecmfile->id > 0) {
1539  $result = $ecmfile->delete($user);
1540  }
1541  if ($result < 0) {
1542  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1543  }
1544  }
1545  }
1546  } else {
1547  dol_syslog("Failed to remove file ".$filename, LOG_WARNING);
1548  // TODO Failure to remove can be because file was already removed or because of permission
1549  // If error because it does not exists, we should return true, and we should return false if this is a permission problem
1550  }
1551  }
1552  } else {
1553  dol_syslog("No files to delete found", LOG_DEBUG);
1554  }
1555  } else {
1556  $ok = false;
1557  if ($nophperrors) {
1558  $ok = @unlink($file_osencoded);
1559  } else {
1560  $ok = unlink($file_osencoded);
1561  }
1562  if ($ok) {
1563  if (empty($nolog)) {
1564  dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
1565  }
1566  } else {
1567  dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
1568  }
1569  }
1570 
1571  return $ok;
1572  }
1573 }
1574 
1584 function dol_delete_dir($dir, $nophperrors = 0)
1585 {
1586  // Security:
1587  // We refuse transversal using .. and pipes into filenames.
1588  if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) {
1589  dol_syslog("Refused to delete dir ".$dir.' (contains invalid char sequence)', LOG_WARNING);
1590  return false;
1591  }
1592 
1593  $dir_osencoded = dol_osencode($dir);
1594  return ($nophperrors ? @rmdir($dir_osencoded) : rmdir($dir_osencoded));
1595 }
1596 
1609 function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0, $indexdatabase = 1, $nolog = 0)
1610 {
1611  if (empty($nolog)) {
1612  dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG);
1613  }
1614  if (dol_is_dir($dir)) {
1615  $dir_osencoded = dol_osencode($dir);
1616  if ($handle = opendir("$dir_osencoded")) {
1617  while (false !== ($item = readdir($handle))) {
1618  if (!utf8_check($item)) {
1619  $item = mb_convert_encoding($item, 'UTF-8', 'ISO-8859-1'); // should be useless
1620  }
1621 
1622  if ($item != "." && $item != "..") {
1623  if (is_dir(dol_osencode("$dir/$item")) && !is_link(dol_osencode("$dir/$item"))) {
1624  $count = dol_delete_dir_recursive("$dir/$item", $count, $nophperrors, 0, $countdeleted, $indexdatabase, $nolog);
1625  } else {
1626  $result = dol_delete_file("$dir/$item", 1, $nophperrors, 0, null, false, $indexdatabase, $nolog);
1627  $count++;
1628  if ($result) {
1629  $countdeleted++;
1630  }
1631  //else print 'Error on '.$item."\n";
1632  }
1633  }
1634  }
1635  closedir($handle);
1636 
1637  // Delete also the main directory
1638  if (empty($onlysub)) {
1639  $result = dol_delete_dir($dir, $nophperrors);
1640  $count++;
1641  if ($result) {
1642  $countdeleted++;
1643  }
1644  //else print 'Error on '.$dir."\n";
1645  }
1646  }
1647  }
1648 
1649  return $count;
1650 }
1651 
1652 
1662 {
1663  global $langs, $conf;
1664 
1665  // Define parent dir of elements
1666  $element = $object->element;
1667 
1668  if ($object->element == 'order_supplier') {
1669  $dir = $conf->fournisseur->commande->dir_output;
1670  } elseif ($object->element == 'invoice_supplier') {
1671  $dir = $conf->fournisseur->facture->dir_output;
1672  } elseif ($object->element == 'project') {
1673  $dir = $conf->project->dir_output;
1674  } elseif ($object->element == 'shipping') {
1675  $dir = $conf->expedition->dir_output.'/sending';
1676  } elseif ($object->element == 'delivery') {
1677  $dir = $conf->expedition->dir_output.'/receipt';
1678  } elseif ($object->element == 'fichinter') {
1679  $dir = $conf->ficheinter->dir_output;
1680  } else {
1681  $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1682  }
1683 
1684  if (empty($dir)) {
1685  $object->error = $langs->trans('ErrorObjectNoSupportedByFunction');
1686  return 0;
1687  }
1688 
1689  $refsan = dol_sanitizeFileName($object->ref);
1690  $dir = $dir."/".$refsan;
1691  $filepreviewnew = $dir."/".$refsan.".pdf_preview.png";
1692  $filepreviewnewbis = $dir."/".$refsan.".pdf_preview-0.png";
1693  $filepreviewold = $dir."/".$refsan.".pdf.png";
1694 
1695  // For new preview files
1696  if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) {
1697  if (!dol_delete_file($filepreviewnew, 1)) {
1698  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnew);
1699  return 0;
1700  }
1701  }
1702  if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) {
1703  if (!dol_delete_file($filepreviewnewbis, 1)) {
1704  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis);
1705  return 0;
1706  }
1707  }
1708  // For old preview files
1709  if (file_exists($filepreviewold) && is_writable($filepreviewold)) {
1710  if (!dol_delete_file($filepreviewold, 1)) {
1711  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewold);
1712  return 0;
1713  }
1714  } else {
1715  $multiple = $filepreviewold.".";
1716  for ($i = 0; $i < 20; $i++) {
1717  $preview = $multiple.$i;
1718 
1719  if (file_exists($preview) && is_writable($preview)) {
1720  if (!dol_delete_file($preview, 1)) {
1721  $object->error = $langs->trans("ErrorFailedToOpenFile", $preview);
1722  return 0;
1723  }
1724  }
1725  }
1726  }
1727 
1728  return 1;
1729 }
1730 
1740 {
1741  global $conf;
1742 
1743  // Create meta file
1744  if (!getDolGlobalString('MAIN_DOC_CREATE_METAFILE')) {
1745  return 0; // By default, no metafile.
1746  }
1747 
1748  // Define parent dir of elements
1749  $element = $object->element;
1750 
1751  if ($object->element == 'order_supplier') {
1752  $dir = $conf->fournisseur->dir_output.'/commande';
1753  } elseif ($object->element == 'invoice_supplier') {
1754  $dir = $conf->fournisseur->dir_output.'/facture';
1755  } elseif ($object->element == 'project') {
1756  $dir = $conf->project->dir_output;
1757  } elseif ($object->element == 'shipping') {
1758  $dir = $conf->expedition->dir_output.'/sending';
1759  } elseif ($object->element == 'delivery') {
1760  $dir = $conf->expedition->dir_output.'/receipt';
1761  } elseif ($object->element == 'fichinter') {
1762  $dir = $conf->ficheinter->dir_output;
1763  } else {
1764  $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1765  }
1766 
1767  if ($dir) {
1768  $object->fetch_thirdparty();
1769 
1770  $objectref = dol_sanitizeFileName($object->ref);
1771  $dir = $dir."/".$objectref;
1772  $file = $dir."/".$objectref.".meta";
1773 
1774  if (!is_dir($dir)) {
1775  dol_mkdir($dir);
1776  }
1777 
1778  if (is_dir($dir)) {
1779  if (is_countable($object->lines) && count($object->lines) > 0) {
1780  $nblines = count($object->lines);
1781  }
1782  $client = $object->thirdparty->name." ".$object->thirdparty->address." ".$object->thirdparty->zip." ".$object->thirdparty->town;
1783  $meta = "REFERENCE=\"".$object->ref."\"
1784  DATE=\"" . dol_print_date($object->date, '')."\"
1785  NB_ITEMS=\"" . $nblines."\"
1786  CLIENT=\"" . $client."\"
1787  AMOUNT_EXCL_TAX=\"" . $object->total_ht."\"
1788  AMOUNT=\"" . $object->total_ttc."\"\n";
1789 
1790  for ($i = 0; $i < $nblines; $i++) {
1791  //Pour les articles
1792  $meta .= "ITEM_".$i."_QUANTITY=\"".$object->lines[$i]->qty."\"
1793  ITEM_" . $i."_AMOUNT_WO_TAX=\"".$object->lines[$i]->total_ht."\"
1794  ITEM_" . $i."_VAT=\"".$object->lines[$i]->tva_tx."\"
1795  ITEM_" . $i."_DESCRIPTION=\"".str_replace("\r\n", "", nl2br($object->lines[$i]->desc))."\"
1796  ";
1797  }
1798  }
1799 
1800  $fp = fopen($file, "w");
1801  fwrite($fp, $meta);
1802  fclose($fp);
1803 
1804  dolChmod($file);
1805 
1806  return 1;
1807  } else {
1808  dol_syslog('FailedToDetectDirInDolMetaCreateFor'.$object->element, LOG_WARNING);
1809  }
1810 
1811  return 0;
1812 }
1813 
1814 
1815 
1824 function dol_init_file_process($pathtoscan = '', $trackid = '')
1825 {
1826  $listofpaths = array();
1827  $listofnames = array();
1828  $listofmimes = array();
1829 
1830  if ($pathtoscan) {
1831  $listoffiles = dol_dir_list($pathtoscan, 'files');
1832  foreach ($listoffiles as $key => $val) {
1833  $listofpaths[] = $val['fullname'];
1834  $listofnames[] = $val['name'];
1835  $listofmimes[] = dol_mimetype($val['name']);
1836  }
1837  }
1838  $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1839  $_SESSION["listofpaths".$keytoavoidconflict] = implode(';', $listofpaths);
1840  $_SESSION["listofnames".$keytoavoidconflict] = implode(';', $listofnames);
1841  $_SESSION["listofmimes".$keytoavoidconflict] = implode(';', $listofmimes);
1842 }
1843 
1844 
1862 function dol_add_file_process($upload_dir, $allowoverwrite = 0, $updatesessionordb = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null)
1863 {
1864  global $db, $user, $conf, $langs;
1865 
1866  $res = 0;
1867 
1868  if (!empty($_FILES[$varfiles])) { // For view $_FILES[$varfiles]['error']
1869  dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$updatesessionordb.' savingdocmask='.$savingdocmask, LOG_DEBUG);
1870  $maxfilesinform = getDolGlobalInt("MAIN_SECURITY_MAX_ATTACHMENT_ON_FORMS", 10);
1871  if (is_array($_FILES[$varfiles]["name"]) && count($_FILES[$varfiles]["name"]) > $maxfilesinform) {
1872  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1873  setEventMessages($langs->trans("ErrorTooMuchFileInForm", $maxfilesinform), null, "errors");
1874  return -1;
1875  }
1876  $result = dol_mkdir($upload_dir);
1877  // var_dump($result);exit;
1878  if ($result >= 0) {
1879  $TFile = $_FILES[$varfiles];
1880  // Convert value of $TFile
1881  if (!is_array($TFile['name'])) {
1882  foreach ($TFile as $key => &$val) {
1883  $val = array($val);
1884  }
1885  }
1886 
1887  $nbfile = count($TFile['name']);
1888  $nbok = 0;
1889  for ($i = 0; $i < $nbfile; $i++) {
1890  if (empty($TFile['name'][$i])) {
1891  continue; // For example, when submitting a form with no file name
1892  }
1893 
1894  // Define $destfull (path to file including filename) and $destfile (only filename)
1895  $destfile = trim($TFile['name'][$i]);
1896  $destfull = $upload_dir."/".$destfile;
1897  $destfilewithoutext = preg_replace('/\.[^\.]+$/', '', $destfile);
1898 
1899  if ($savingdocmask && strpos($savingdocmask, $destfilewithoutext) !== 0) {
1900  $destfile = trim(preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask));
1901  $destfull = $upload_dir."/".$destfile;
1902  }
1903 
1904  $filenameto = basename($destfile);
1905  if (preg_match('/^\./', $filenameto)) {
1906  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1907  setEventMessages($langs->trans("ErrorFilenameCantStartWithDot", $filenameto), null, 'errors');
1908  break;
1909  }
1910  // dol_sanitizeFileName the file name and lowercase extension
1911  $info = pathinfo($destfull);
1912  $destfull = $info['dirname'].'/'.dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1913  $info = pathinfo($destfile);
1914  $destfile = dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1915 
1916  // We apply dol_string_nohtmltag also to clean file names (this remove duplicate spaces) because
1917  // this function is also applied when we rename and when we make try to download file (by the GETPOST(filename, 'alphanohtml') call).
1918  $destfile = dol_string_nohtmltag($destfile);
1919  $destfull = dol_string_nohtmltag($destfull);
1920 
1921  // Check that filename is not the one of a reserved allowed CLI command
1922  global $dolibarr_main_restrict_os_commands;
1923  if (!empty($dolibarr_main_restrict_os_commands)) {
1924  $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
1925  $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
1926  if (in_array($destfile, $arrayofallowedcommand)) {
1927  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1928  setEventMessages($langs->trans("ErrorFilenameReserved", $destfile), null, 'errors');
1929  return -1;
1930  }
1931  }
1932 
1933  // Move file from temp directory to final directory. A .noexe may also be appended on file name.
1934  $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir);
1935 
1936  if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists'
1937  include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
1938 
1939  $tmparraysize = getDefaultImageSizes();
1940  $maxwidthsmall = $tmparraysize['maxwidthsmall'];
1941  $maxheightsmall = $tmparraysize['maxheightsmall'];
1942  $maxwidthmini = $tmparraysize['maxwidthmini'];
1943  $maxheightmini = $tmparraysize['maxheightmini'];
1944  //$quality = $tmparraysize['quality'];
1945  $quality = 50; // For thumbs, we force quality to 50
1946 
1947  // Generate thumbs.
1948  if ($generatethumbs) {
1949  if (image_format_supported($destfull) == 1) {
1950  // Create thumbs
1951  // We can't use $object->addThumbs here because there is no $object known
1952 
1953  // Used on logon for example
1954  $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', $quality, "thumbs");
1955  // Create mini thumbs for image (Ratio is near 16/9)
1956  // Used on menu or for setup page for example
1957  $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', $quality, "thumbs");
1958  }
1959  }
1960 
1961  // Update session
1962  if (empty($updatesessionordb)) {
1963  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1964  $formmail = new FormMail($db);
1965  $formmail->trackid = $trackid;
1966  $formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
1967  }
1968 
1969  // Update index table of files (llx_ecm_files)
1970  if ($updatesessionordb == 1) {
1971  $sharefile = 0;
1972  if ($TFile['type'][$i] == 'application/pdf' && strpos($_SERVER["REQUEST_URI"], 'product') !== false && getDolGlobalString('PRODUCT_ALLOW_EXTERNAL_DOWNLOAD')) {
1973  $sharefile = 1;
1974  }
1975  $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', $sharefile, $object);
1976  if ($result < 0) {
1977  if ($allowoverwrite) {
1978  // Do not show error message. We can have an error due to DB_ERROR_RECORD_ALREADY_EXISTS
1979  } else {
1980  setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', null, 'warnings');
1981  }
1982  }
1983  }
1984 
1985  $nbok++;
1986  } else {
1987  $langs->load("errors");
1988  if (is_numeric($resupload) && $resupload < 0) { // Unknown error
1989  setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
1990  } elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) { // Files infected by a virus
1991  if (preg_match('/File is a PDF with javascript inside/', $resupload)) {
1992  setEventMessages($langs->trans("ErrorFileIsAnInfectedPDFWithJSInside"), null, 'errors');
1993  } else {
1994  setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors');
1995  }
1996  } else { // Known error
1997  setEventMessages($langs->trans($resupload), null, 'errors');
1998  }
1999  }
2000  }
2001  if ($nbok > 0) {
2002  $res = 1;
2003  setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs');
2004  }
2005  } else {
2006  setEventMessages($langs->trans("ErrorFailedToCreateDir", $upload_dir), null, 'errors');
2007  }
2008  } elseif ($link) {
2009  require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
2010  $linkObject = new Link($db);
2011  $linkObject->entity = $conf->entity;
2012  $linkObject->url = $link;
2013  $linkObject->objecttype = GETPOST('objecttype', 'alpha');
2014  $linkObject->objectid = GETPOSTINT('objectid');
2015  $linkObject->label = GETPOST('label', 'alpha');
2016  $res = $linkObject->create($user);
2017 
2018  if ($res > 0) {
2019  setEventMessages($langs->trans("LinkComplete"), null, 'mesgs');
2020  } else {
2021  setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors');
2022  }
2023  } else {
2024  $langs->load("errors");
2025  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
2026  }
2027 
2028  return $res;
2029 }
2030 
2031 
2043 function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '')
2044 {
2045  global $db, $user, $conf, $langs, $_FILES;
2046 
2047  $keytodelete = $filenb;
2048  $keytodelete--;
2049 
2050  $listofpaths = array();
2051  $listofnames = array();
2052  $listofmimes = array();
2053  $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
2054  if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
2055  $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
2056  }
2057  if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
2058  $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
2059  }
2060  if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
2061  $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
2062  }
2063 
2064  if ($keytodelete >= 0) {
2065  $pathtodelete = $listofpaths[$keytodelete];
2066  $filetodelete = $listofnames[$keytodelete];
2067  if (empty($donotdeletefile)) {
2068  $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file
2069  } else {
2070  $result = 0;
2071  }
2072  if ($result >= 0) {
2073  if (empty($donotdeletefile)) {
2074  $langs->load("other");
2075  setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs');
2076  }
2077  if (empty($donotupdatesession)) {
2078  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2079  $formmail = new FormMail($db);
2080  $formmail->trackid = $trackid;
2081  $formmail->remove_attached_files($keytodelete);
2082  }
2083  }
2084  }
2085 }
2086 
2087 
2101 function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null)
2102 {
2103  global $db, $user, $conf;
2104 
2105  $result = 0;
2106 
2107  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2108 
2109  if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir
2110  $filename = basename(preg_replace('/\.noexe$/', '', $file));
2111  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2112  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2113 
2114  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
2115  $ecmfile = new EcmFiles($db);
2116  $ecmfile->filepath = $rel_dir;
2117  $ecmfile->filename = $filename;
2118  $ecmfile->label = md5_file(dol_osencode($dir.'/'.$file)); // MD5 of file content
2119  $ecmfile->fullpath_orig = $fullpathorig;
2120  $ecmfile->gen_or_uploaded = $mode;
2121  $ecmfile->description = ''; // indexed content
2122  $ecmfile->keywords = ''; // keyword content
2123 
2124  if (is_object($object) && $object->id > 0) {
2125  $ecmfile->src_object_id = $object->id;
2126  if (isset($object->table_element)) {
2127  $ecmfile->src_object_type = $object->table_element;
2128  } else {
2129  dol_syslog('Error: object ' . get_class($object) . ' has no table_element attribute.');
2130  return -1;
2131  }
2132  if (isset($object->src_object_description)) {
2133  $ecmfile->description = $object->src_object_description;
2134  }
2135  if (isset($object->src_object_keywords)) {
2136  $ecmfile->keywords = $object->src_object_keywords;
2137  }
2138  }
2139 
2140  if (getDolGlobalString('MAIN_FORCE_SHARING_ON_ANY_UPLOADED_FILE')) {
2141  $setsharekey = 1;
2142  }
2143 
2144  if ($setsharekey) {
2145  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
2146  $ecmfile->share = getRandomPassword(true);
2147  }
2148 
2149  // Use a convertisser Doc to Text
2150  $useFullTextIndexation = getDolGlobalString('MAIN_USE_FULL_TEXT_INDEXATION');
2151  //$useFullTextIndexation = 1;
2152  if ($useFullTextIndexation) {
2153  $ecmfile->filepath = $rel_dir;
2154  $ecmfile->filename = $filename;
2155 
2156  $filetoprocess = $dir.'/'.$ecmfile->filename;
2157 
2158  $textforfulltextindex = '';
2159  $keywords = '';
2160  if (preg_match('/\.pdf/i', $filename)) {
2161  // TODO Move this into external submodule files
2162 
2163  // TODO Develop a native PHP parser using sample code in https://github.com/adeel/php-pdf-parser
2164 
2165  include_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
2166  $utils = new Utils($db);
2167  $outputfile = $conf->admin->dir_temp.'/tmppdttotext.'.$user->id.'.out'; // File used with popen method
2168 
2169  // We also exclude '/temp/' dir and 'documents/admin/documents'
2170  // We make escapement here and call executeCLI without escapement because we don't want to have the '*.log' escaped.
2171  $cmd = getDolGlobalString('MAIN_USE_FULL_TEXT_INDEXATION_PDFTOTEXT', 'pdftotext')." -htmlmeta '".escapeshellcmd($filetoprocess)."' - ";
2172  $result = $utils->executeCLI($cmd, $outputfile, 0, null, 1);
2173 
2174  if (!$result['error']) {
2175  $txt = $result['output'];
2176  $matches = array();
2177  if (preg_match('/<meta name="Keywords" content="([^\/]+)"\s*\/>/i', $txt, $matches)) {
2178  $keywords = $matches[1];
2179  }
2180  if (preg_match('/<pre>(.*)<\/pre>/si', $txt, $matches)) {
2181  $textforfulltextindex = dol_string_nospecial($matches[1]);
2182  }
2183  }
2184  }
2185 
2186  $ecmfile->description = $textforfulltextindex;
2187  $ecmfile->keywords = $keywords;
2188  }
2189 
2190  $result = $ecmfile->create($user);
2191  if ($result < 0) {
2192  dol_syslog($ecmfile->error);
2193  }
2194  }
2195 
2196  return $result;
2197 }
2198 
2207 function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded')
2208 {
2209  global $conf, $db, $user;
2210 
2211  $error = 0;
2212 
2213  if (empty($dir)) {
2214  dol_syslog("deleteFilesIntoDatabaseIndex: dir parameter can't be empty", LOG_ERR);
2215  return -1;
2216  }
2217 
2218  $db->begin();
2219 
2220  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2221 
2222  $filename = basename($file);
2223  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2224  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2225 
2226  if (!$error) {
2227  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'ecm_files';
2228  $sql .= ' WHERE entity = '.$conf->entity;
2229  $sql .= " AND filepath = '".$db->escape($rel_dir)."'";
2230  if ($file) {
2231  $sql .= " AND filename = '".$db->escape($file)."'";
2232  }
2233  if ($mode) {
2234  $sql .= " AND gen_or_uploaded = '".$db->escape($mode)."'";
2235  }
2236 
2237  $resql = $db->query($sql);
2238  if (!$resql) {
2239  $error++;
2240  dol_syslog(__FUNCTION__.' '.$db->lasterror(), LOG_ERR);
2241  }
2242  }
2243 
2244  // Commit or rollback
2245  if ($error) {
2246  $db->rollback();
2247  return -1 * $error;
2248  } else {
2249  $db->commit();
2250  return 1;
2251  }
2252 }
2253 
2254 
2266 function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '')
2267 {
2268  if (class_exists('Imagick')) {
2269  $image = new Imagick();
2270  try {
2271  $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : '');
2272  //var_dump($filetoconvert);
2273  $ret = $image->readImage($filetoconvert);
2274  } catch (Exception $e) {
2275  $ext = pathinfo($fileinput, PATHINFO_EXTENSION);
2276  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." conversion in /etc/ImageMagick*/policy.xml): ".$e->getMessage(), LOG_WARNING);
2277  return 0;
2278  }
2279  if ($ret) {
2280  $ret = $image->setImageFormat($ext);
2281  if ($ret) {
2282  if (empty($fileoutput)) {
2283  $fileoutput = $fileinput.".".$ext;
2284  }
2285 
2286  $count = $image->getNumberImages();
2287 
2288  if (!dol_is_file($fileoutput) || is_writable($fileoutput)) {
2289  try {
2290  $ret = $image->writeImages($fileoutput, true);
2291  } catch (Exception $e) {
2292  dol_syslog($e->getMessage(), LOG_WARNING);
2293  }
2294  } else {
2295  dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR);
2296  }
2297  if ($ret) {
2298  return $count;
2299  } else {
2300  return -3;
2301  }
2302  } else {
2303  return -2;
2304  }
2305  } else {
2306  return -1;
2307  }
2308  } else {
2309  return 0;
2310  }
2311 }
2312 
2313 
2325 function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring = null)
2326 {
2327  $foundhandler = 0;
2328  //var_dump(basename($inputfile)); exit;
2329 
2330  try {
2331  dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile);
2332 
2333  $data = implode("", file(dol_osencode($inputfile)));
2334  if ($mode == 'gz' && function_exists('gzencode')) {
2335  $foundhandler = 1;
2336  $compressdata = gzencode($data, 9);
2337  } elseif ($mode == 'bz' && function_exists('bzcompress')) {
2338  $foundhandler = 1;
2339  $compressdata = bzcompress($data, 9);
2340  } elseif ($mode == 'zstd' && function_exists('zstd_compress')) {
2341  $foundhandler = 1;
2342  $compressdata = zstd_compress($data, 9);
2343  } elseif ($mode == 'zip') {
2344  if (class_exists('ZipArchive') && getDolGlobalString('MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS')) {
2345  $foundhandler = 1;
2346 
2347  $rootPath = realpath($inputfile);
2348 
2349  dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath);
2350  $zip = new ZipArchive();
2351 
2352  if ($zip->open($outputfile, ZipArchive::CREATE) !== true) {
2353  $errorstring = "dol_compress_file failure - Failed to open file ".$outputfile."\n";
2354  dol_syslog($errorstring, LOG_ERR);
2355 
2356  global $errormsg;
2357  $errormsg = $errorstring;
2358 
2359  return -6;
2360  }
2361 
2362  // Create recursive directory iterator
2364  $files = new RecursiveIteratorIterator(
2365  new RecursiveDirectoryIterator($rootPath, FilesystemIterator::UNIX_PATHS),
2366  RecursiveIteratorIterator::LEAVES_ONLY
2367  );
2368 
2369  foreach ($files as $name => $file) {
2370  // Skip directories (they would be added automatically)
2371  if (!$file->isDir()) {
2372  // Get real and relative path for current file
2373  $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2374  $fileName = $file->getFilename();
2375  $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2376 
2377  //$relativePath = substr($fileFullRealPath, strlen($rootPath) + 1);
2378  $relativePath = substr(($filePath ? $filePath.'/' : '').$fileName, strlen($rootPath) + 1);
2379 
2380  // Add current file to archive
2381  $zip->addFile($fileFullRealPath, $relativePath);
2382  }
2383  }
2384 
2385  // Zip archive will be created only after closing object
2386  $zip->close();
2387 
2388  dol_syslog("dol_compress_file success - ".$zip->numFiles." files");
2389  return 1;
2390  }
2391 
2392  if (defined('ODTPHP_PATHTOPCLZIP')) {
2393  $foundhandler = 1;
2394 
2395  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2396  $archive = new PclZip($outputfile);
2397 
2398  $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2399 
2400  if ($result === 0) {
2401  global $errormsg;
2402  $errormsg = $archive->errorInfo(true);
2403 
2404  if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) {
2405  $errorstring = "PCLZIP_ERR_WRITE_OPEN_FAIL";
2406  dol_syslog("dol_compress_file error - archive->errorCode() = PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR);
2407  return -4;
2408  }
2409 
2410  $errorstring = "dol_compress_file error archive->errorCode = ".$archive->errorCode()." errormsg=".$errormsg;
2411  dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR);
2412  return -3;
2413  } else {
2414  dol_syslog("dol_compress_file success - ".count($result)." files");
2415  return 1;
2416  }
2417  }
2418  }
2419 
2420  if ($foundhandler) {
2421  $fp = fopen($outputfile, "w");
2422  fwrite($fp, $compressdata);
2423  fclose($fp);
2424  return 1;
2425  } else {
2426  $errorstring = "Try to zip with format ".$mode." with no handler for this format";
2427  dol_syslog($errorstring, LOG_ERR);
2428 
2429  global $errormsg;
2430  $errormsg = $errorstring;
2431  return -2;
2432  }
2433  } catch (Exception $e) {
2434  global $langs, $errormsg;
2435  $langs->load("errors");
2436  $errormsg = $langs->trans("ErrorFailedToWriteInDir");
2437 
2438  $errorstring = "Failed to open file ".$outputfile;
2439  dol_syslog($errorstring, LOG_ERR);
2440  return -1;
2441  }
2442 }
2443 
2452 function dol_uncompress($inputfile, $outputdir)
2453 {
2454  global $langs, $db;
2455 
2456  $fileinfo = pathinfo($inputfile);
2457  $fileinfo["extension"] = strtolower($fileinfo["extension"]);
2458 
2459  if ($fileinfo["extension"] == "zip") {
2460  if (defined('ODTPHP_PATHTOPCLZIP') && !getDolGlobalString('MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS')) {
2461  dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
2462  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2463  $archive = new PclZip($inputfile);
2464 
2465  // We create output dir manually, so it uses the correct permission (When created by the archive->extract, dir is rwx for everybody).
2466  dol_mkdir(dol_sanitizePathName($outputdir));
2467 
2468  try {
2469  // Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
2470  $result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
2471  } catch (Exception $e) {
2472  return array('error' => $e->getMessage());
2473  }
2474 
2475  if (!is_array($result) && $result <= 0) {
2476  return array('error' => $archive->errorInfo(true));
2477  } else {
2478  $ok = 1;
2479  $errmsg = '';
2480  // Loop on each file to check result for unzipping file
2481  foreach ($result as $key => $val) {
2482  if ($val['status'] == 'path_creation_fail') {
2483  $langs->load("errors");
2484  $ok = 0;
2485  $errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
2486  break;
2487  }
2488  if ($val['status'] == 'write_protected') {
2489  $langs->load("errors");
2490  $ok = 0;
2491  $errmsg = $langs->trans("ErrorFailToCreateFile", $val['filename']);
2492  break;
2493  }
2494  }
2495 
2496  if ($ok) {
2497  return array();
2498  } else {
2499  return array('error' => $errmsg);
2500  }
2501  }
2502  }
2503 
2504  if (class_exists('ZipArchive')) { // Must install php-zip to have it
2505  dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
2506  $zip = new ZipArchive();
2507  $res = $zip->open($inputfile);
2508  if ($res === true) {
2509  //$zip->extractTo($outputdir.'/');
2510  // We must extract one file at time so we can check that file name does not contain '..' to avoid transversal path of zip built for example using
2511  // python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
2512  // with -l is the range of dot to go back in path.
2513  // and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
2514  for ($i = 0; $i < $zip->numFiles; $i++) {
2515  if (preg_match('/\.\./', $zip->getNameIndex($i))) {
2516  dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
2517  continue; // Discard the file
2518  }
2519  $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
2520  }
2521 
2522  $zip->close();
2523  return array();
2524  } else {
2525  return array('error' => 'ErrUnzipFails');
2526  }
2527  }
2528 
2529  return array('error' => 'ErrNoZipEngine');
2530  } elseif (in_array($fileinfo["extension"], array('gz', 'bz2', 'zst'))) {
2531  include_once DOL_DOCUMENT_ROOT."/core/class/utils.class.php";
2532  $utils = new Utils($db);
2533 
2534  dol_mkdir(dol_sanitizePathName($outputdir));
2535  $outputfilename = escapeshellcmd(dol_sanitizePathName($outputdir).'/'.dol_sanitizeFileName($fileinfo["filename"]));
2536  dol_delete_file($outputfilename.'.tmp');
2537  dol_delete_file($outputfilename.'.err');
2538 
2539  $extension = strtolower(pathinfo($fileinfo["filename"], PATHINFO_EXTENSION));
2540  if ($extension == "tar") {
2541  $cmd = 'tar -C '.escapeshellcmd(dol_sanitizePathName($outputdir)).' -xvf '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2542 
2543  $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, $outputfilename.'.err', 0);
2544  if ($resarray["result"] != 0) {
2545  $resarray["error"] .= file_get_contents($outputfilename.'.err');
2546  }
2547  } else {
2548  $program = "";
2549  if ($fileinfo["extension"] == "gz") {
2550  $program = 'gzip';
2551  } elseif ($fileinfo["extension"] == "bz2") {
2552  $program = 'bzip2';
2553  } elseif ($fileinfo["extension"] == "zst") {
2554  $program = 'zstd';
2555  } else {
2556  return array('error' => 'ErrorBadFileExtension');
2557  }
2558  $cmd = $program.' -dc '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2559  $cmd .= ' > '.$outputfilename;
2560 
2561  $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, null, 1, $outputfilename.'.err');
2562  if ($resarray["result"] != 0) {
2563  $errfilecontent = @file_get_contents($outputfilename.'.err');
2564  if ($errfilecontent) {
2565  $resarray["error"] .= " - ".$errfilecontent;
2566  }
2567  }
2568  }
2569  return $resarray["result"] != 0 ? array('error' => $resarray["error"]) : array();
2570  }
2571 
2572  return array('error' => 'ErrorBadFileExtension');
2573 }
2574 
2575 
2588 function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '', $rootdirinzip = '', $newmask = '0')
2589 {
2590  $foundhandler = 0;
2591 
2592  dol_syslog("Try to zip dir ".$inputdir." into ".$outputfile." mode=".$mode);
2593 
2594  if (!dol_is_dir(dirname($outputfile)) || !is_writable(dirname($outputfile))) {
2595  global $langs, $errormsg;
2596  $langs->load("errors");
2597  $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile);
2598  return -3;
2599  }
2600 
2601  try {
2602  if ($mode == 'gz') {
2603  $foundhandler = 0;
2604  } elseif ($mode == 'bz') {
2605  $foundhandler = 0;
2606  } elseif ($mode == 'zip') {
2607  /*if (defined('ODTPHP_PATHTOPCLZIP'))
2608  {
2609  $foundhandler=0; // TODO implement this
2610 
2611  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2612  $archive = new PclZip($outputfile);
2613  $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2614  //$archive->add($inputfile);
2615  return 1;
2616  }
2617  else*/
2618  //if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS))
2619 
2620  if (class_exists('ZipArchive')) {
2621  $foundhandler = 1;
2622 
2623  // Initialize archive object
2624  $zip = new ZipArchive();
2625  $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
2626  if ($result !== true) {
2627  global $langs, $errormsg;
2628  $langs->load("errors");
2629  $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile);
2630  return -4;
2631  }
2632 
2633  // Create recursive directory iterator
2634  // This does not return symbolic links
2636  $files = new RecursiveIteratorIterator(
2637  new RecursiveDirectoryIterator($inputdir, FilesystemIterator::UNIX_PATHS),
2638  RecursiveIteratorIterator::LEAVES_ONLY
2639  );
2640 
2641  //var_dump($inputdir);
2642  foreach ($files as $name => $file) {
2643  // Skip directories (they would be added automatically)
2644  if (!$file->isDir()) {
2645  // Get real and relative path for current file
2646  $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2647  $fileName = $file->getFilename();
2648  $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2649 
2650  //$relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($fileFullRealPath, strlen($inputdir) + 1);
2651  $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr(($filePath ? $filePath.'/' : '').$fileName, strlen($inputdir) + 1);
2652 
2653  //var_dump($filePath);var_dump($fileFullRealPath);var_dump($relativePath);
2654  if (empty($excludefiles) || !preg_match($excludefiles, $fileFullRealPath)) {
2655  // Add current file to archive
2656  $zip->addFile($fileFullRealPath, $relativePath);
2657  }
2658  }
2659  }
2660 
2661  // Zip archive will be created only after closing object
2662  $zip->close();
2663 
2664  if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
2665  $newmask = getDolGlobalString('MAIN_UMASK');
2666  }
2667  if (empty($newmask)) { // This should no happen
2668  dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
2669  $newmask = '0664';
2670  }
2671 
2672  dolChmod($outputfile, $newmask);
2673 
2674  return 1;
2675  }
2676  }
2677 
2678  if (!$foundhandler) {
2679  dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR);
2680  return -2;
2681  } else {
2682  return 0;
2683  }
2684  } catch (Exception $e) {
2685  global $langs, $errormsg;
2686  $langs->load("errors");
2687  dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
2688  dol_syslog($e->getMessage(), LOG_ERR);
2689  $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile).' - '.$e->getMessage();
2690  return -1;
2691  }
2692 }
2693 
2694 
2695 
2706 function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$', '^\.'), $nohook = 0, $mode = 0)
2707 {
2708  $tmparray = dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook);
2709  return isset($tmparray[0]) ? $tmparray[0] : null;
2710 }
2711 
2725 function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = null, $refname = '', $mode = 'read')
2726 {
2727  global $conf, $db, $user, $hookmanager;
2728  global $dolibarr_main_data_root, $dolibarr_main_document_root_alt;
2729  global $object;
2730 
2731  if (!is_object($fuser)) {
2732  $fuser = $user;
2733  }
2734 
2735  if (empty($modulepart)) {
2736  return 'ErrorBadParameter';
2737  }
2738  if (empty($entity)) {
2739  if (!isModEnabled('multicompany')) {
2740  $entity = 1;
2741  } else {
2742  $entity = 0;
2743  }
2744  }
2745  // Fix modulepart for backward compatibility
2746  if ($modulepart == 'facture') {
2747  $modulepart = 'invoice';
2748  } elseif ($modulepart == 'users') {
2749  $modulepart = 'user';
2750  } elseif ($modulepart == 'tva') {
2751  $modulepart = 'tax-vat';
2752  } elseif ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) {
2753  // Fix modulepart delivery
2754  $modulepart = 'delivery';
2755  }
2756 
2757  //print 'dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity;
2758  dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
2759 
2760  // We define $accessallowed and $sqlprotectagainstexternals
2761  $accessallowed = 0;
2762  $sqlprotectagainstexternals = '';
2763  $ret = array();
2764 
2765  // Find the subdirectory name as the reference. For example original_file='10/myfile.pdf' -> refname='10'
2766  if (empty($refname)) {
2767  $refname = basename(dirname($original_file)."/");
2768  if ($refname == 'thumbs' || $refname == 'temp') {
2769  // If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10'
2770  $refname = basename(dirname(dirname($original_file))."/");
2771  }
2772  }
2773 
2774  // Define possible keys to use for permission check
2775  $lire = 'lire';
2776  $read = 'read';
2777  $download = 'download';
2778  if ($mode == 'write') {
2779  $lire = 'creer';
2780  $read = 'write';
2781  $download = 'upload';
2782  }
2783 
2784  // Wrapping for miscellaneous medias files
2785  if ($modulepart == 'common') {
2786  // Wrapping for some images
2787  $accessallowed = 1;
2788  $original_file = DOL_DOCUMENT_ROOT.'/public/theme/common/'.$original_file;
2789  } elseif ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) {
2790  if (empty($entity) || empty($conf->medias->multidir_output[$entity])) {
2791  return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
2792  }
2793  $accessallowed = 1;
2794  $original_file = $conf->medias->multidir_output[$entity].'/'.$original_file;
2795  } elseif ($modulepart == 'logs' && !empty($dolibarr_main_data_root)) {
2796  // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
2797  $accessallowed = ($user->admin && basename($original_file) == $original_file && preg_match('/^dolibarr.*\.(log|json)$/', basename($original_file)));
2798  $original_file = $dolibarr_main_data_root.'/'.$original_file;
2799  } elseif ($modulepart == 'doctemplates' && !empty($dolibarr_main_data_root)) {
2800  // Wrapping for doctemplates
2801  $accessallowed = $user->admin;
2802  $original_file = $dolibarr_main_data_root.'/doctemplates/'.$original_file;
2803  } elseif ($modulepart == 'doctemplateswebsite' && !empty($dolibarr_main_data_root)) {
2804  // Wrapping for doctemplates of websites
2805  $accessallowed = ($fuser->hasRight('website', 'write') && preg_match('/\.jpg$/i', basename($original_file)));
2806  $original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file;
2807  } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) { // To download zip of modules
2808  // Wrapping for *.zip package files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
2809  // Dir for custom dirs
2810  $tmp = explode(',', $dolibarr_main_document_root_alt);
2811  $dirins = $tmp[0];
2812 
2813  $accessallowed = ($user->admin && preg_match('/^module_.*\.zip$/', basename($original_file)));
2814  $original_file = $dirins.'/'.$original_file;
2815  } elseif ($modulepart == 'mycompany' && !empty($conf->mycompany->dir_output)) {
2816  // Wrapping for some images
2817  $accessallowed = 1;
2818  $original_file = $conf->mycompany->dir_output.'/'.$original_file;
2819  } elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output)) {
2820  // Wrapping for users photos (user photos are allowed to any connected users)
2821  $accessallowed = 0;
2822  if (preg_match('/^\d+\/photos\//', $original_file)) {
2823  $accessallowed = 1;
2824  }
2825  $original_file = $conf->user->dir_output.'/'.$original_file;
2826  } elseif ($modulepart == 'userphotopublic' && !empty($conf->user->dir_output)) {
2827  // Wrapping for users photos that were set to public (for virtual credit card) by their owner (public user photos can be read
2828  // with the public link and securekey)
2829  $accessok = false;
2830  $reg = array();
2831  if (preg_match('/^(\d+)\/photos\//', $original_file, $reg)) {
2832  if ($reg[1]) {
2833  $tmpobject = new User($db);
2834  $tmpobject->fetch($reg[1], '', '', 1);
2835  if (getDolUserInt('USER_ENABLE_PUBLIC', 0, $tmpobject)) {
2836  $securekey = GETPOST('securekey', 'alpha', 1);
2837  // Security check
2838  global $dolibarr_main_cookie_cryptkey, $dolibarr_main_instance_unique_id;
2839  $valuetouse = $dolibarr_main_instance_unique_id ? $dolibarr_main_instance_unique_id : $dolibarr_main_cookie_cryptkey; // Use $dolibarr_main_instance_unique_id first then $dolibarr_main_cookie_cryptkey
2840  $encodedsecurekey = dol_hash($valuetouse.'uservirtualcard'.$tmpobject->id.'-'.$tmpobject->login, 'md5');
2841  if ($encodedsecurekey == $securekey) {
2842  $accessok = true;
2843  }
2844  }
2845  }
2846  }
2847  if ($accessok) {
2848  $accessallowed = 1;
2849  }
2850  $original_file = $conf->user->dir_output.'/'.$original_file;
2851  } elseif (($modulepart == 'companylogo') && !empty($conf->mycompany->dir_output)) {
2852  // Wrapping for company logos (company logos are allowed to anyboby, they are public)
2853  $accessallowed = 1;
2854  $original_file = $conf->mycompany->dir_output.'/logos/'.$original_file;
2855  } elseif ($modulepart == 'memberphoto' && !empty($conf->member->dir_output)) {
2856  // Wrapping for members photos
2857  $accessallowed = 0;
2858  if (preg_match('/^\d+\/photos\//', $original_file)) {
2859  $accessallowed = 1;
2860  }
2861  $original_file = $conf->member->dir_output.'/'.$original_file;
2862  } elseif ($modulepart == 'apercufacture' && !empty($conf->invoice->multidir_output[$entity])) {
2863  // Wrapping for invoices (user need permission to read invoices)
2864  if ($fuser->hasRight('facture', $lire)) {
2865  $accessallowed = 1;
2866  }
2867  $original_file = $conf->invoice->multidir_output[$entity].'/'.$original_file;
2868  } elseif ($modulepart == 'apercupropal' && !empty($conf->propal->multidir_output[$entity])) {
2869  // Wrapping pour les apercu propal
2870  if ($fuser->hasRight('propal', $lire)) {
2871  $accessallowed = 1;
2872  }
2873  $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
2874  } elseif ($modulepart == 'apercucommande' && !empty($conf->order->multidir_output[$entity])) {
2875  // Wrapping pour les apercu commande
2876  if ($fuser->hasRight('commande', $lire)) {
2877  $accessallowed = 1;
2878  }
2879  $original_file = $conf->order->multidir_output[$entity].'/'.$original_file;
2880  } elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output)) {
2881  // Wrapping pour les apercu intervention
2882  if ($fuser->hasRight('ficheinter', $lire)) {
2883  $accessallowed = 1;
2884  }
2885  $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2886  } elseif (($modulepart == 'apercucontract') && !empty($conf->contract->multidir_output[$entity])) {
2887  // Wrapping pour les apercu contrat
2888  if ($fuser->hasRight('contrat', $lire)) {
2889  $accessallowed = 1;
2890  }
2891  $original_file = $conf->contract->multidir_output[$entity].'/'.$original_file;
2892  } elseif (($modulepart == 'apercusupplier_proposal' || $modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output)) {
2893  // Wrapping pour les apercu supplier proposal
2894  if ($fuser->hasRight('supplier_proposal', $lire)) {
2895  $accessallowed = 1;
2896  }
2897  $original_file = $conf->supplier_proposal->dir_output.'/'.$original_file;
2898  } elseif (($modulepart == 'apercusupplier_order' || $modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output)) {
2899  // Wrapping pour les apercu supplier order
2900  if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2901  $accessallowed = 1;
2902  }
2903  $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
2904  } elseif (($modulepart == 'apercusupplier_invoice' || $modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output)) {
2905  // Wrapping pour les apercu supplier invoice
2906  if ($fuser->hasRight('fournisseur', $lire)) {
2907  $accessallowed = 1;
2908  }
2909  $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
2910  } elseif (($modulepart == 'holiday') && !empty($conf->holiday->dir_output)) {
2911  if ($fuser->hasRight('holiday', $read) || $fuser->hasRight('holiday', 'readall') || preg_match('/^specimen/i', $original_file)) {
2912  $accessallowed = 1;
2913  // If we known $id of holiday, call checkUserAccessToObject to check permission on properties and hierarchy of leave request
2914  if ($refname && !$fuser->hasRight('holiday', 'readall') && !preg_match('/^specimen/i', $original_file)) {
2915  include_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
2916  $tmpholiday = new Holiday($db);
2917  $tmpholiday->fetch('', $refname);
2918  $accessallowed = checkUserAccessToObject($user, array('holiday'), $tmpholiday, 'holiday', '', '', 'rowid', '');
2919  }
2920  }
2921  $original_file = $conf->holiday->dir_output.'/'.$original_file;
2922  } elseif (($modulepart == 'expensereport') && !empty($conf->expensereport->dir_output)) {
2923  if ($fuser->hasRight('expensereport', $lire) || $fuser->hasRight('expensereport', 'readall') || preg_match('/^specimen/i', $original_file)) {
2924  $accessallowed = 1;
2925  // If we known $id of expensereport, call checkUserAccessToObject to check permission on properties and hierarchy of expense report
2926  if ($refname && !$fuser->hasRight('expensereport', 'readall') && !preg_match('/^specimen/i', $original_file)) {
2927  include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
2928  $tmpexpensereport = new ExpenseReport($db);
2929  $tmpexpensereport->fetch('', $refname);
2930  $accessallowed = checkUserAccessToObject($user, array('expensereport'), $tmpexpensereport, 'expensereport', '', '', 'rowid', '');
2931  }
2932  }
2933  $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2934  } elseif (($modulepart == 'apercuexpensereport') && !empty($conf->expensereport->dir_output)) {
2935  // Wrapping pour les apercu expense report
2936  if ($fuser->hasRight('expensereport', $lire)) {
2937  $accessallowed = 1;
2938  }
2939  $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2940  } elseif ($modulepart == 'propalstats' && !empty($conf->propal->multidir_temp[$entity])) {
2941  // Wrapping pour les images des stats propales
2942  if ($fuser->hasRight('propal', $lire)) {
2943  $accessallowed = 1;
2944  }
2945  $original_file = $conf->propal->multidir_temp[$entity].'/'.$original_file;
2946  } elseif ($modulepart == 'orderstats' && !empty($conf->order->dir_temp)) {
2947  // Wrapping pour les images des stats commandes
2948  if ($fuser->hasRight('commande', $lire)) {
2949  $accessallowed = 1;
2950  }
2951  $original_file = $conf->order->dir_temp.'/'.$original_file;
2952  } elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2953  if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2954  $accessallowed = 1;
2955  }
2956  $original_file = $conf->fournisseur->commande->dir_temp.'/'.$original_file;
2957  } elseif ($modulepart == 'billstats' && !empty($conf->invoice->dir_temp)) {
2958  // Wrapping pour les images des stats factures
2959  if ($fuser->hasRight('facture', $lire)) {
2960  $accessallowed = 1;
2961  }
2962  $original_file = $conf->invoice->dir_temp.'/'.$original_file;
2963  } elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2964  if ($fuser->hasRight('fournisseur', 'facture', $lire)) {
2965  $accessallowed = 1;
2966  }
2967  $original_file = $conf->fournisseur->facture->dir_temp.'/'.$original_file;
2968  } elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp)) {
2969  // Wrapping pour les images des stats expeditions
2970  if ($fuser->hasRight('expedition', $lire)) {
2971  $accessallowed = 1;
2972  }
2973  $original_file = $conf->expedition->dir_temp.'/'.$original_file;
2974  } elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp)) {
2975  // Wrapping pour les images des stats expeditions
2976  if ($fuser->hasRight('deplacement', $lire)) {
2977  $accessallowed = 1;
2978  }
2979  $original_file = $conf->deplacement->dir_temp.'/'.$original_file;
2980  } elseif ($modulepart == 'memberstats' && !empty($conf->member->dir_temp)) {
2981  // Wrapping pour les images des stats expeditions
2982  if ($fuser->hasRight('adherent', $lire)) {
2983  $accessallowed = 1;
2984  }
2985  $original_file = $conf->member->dir_temp.'/'.$original_file;
2986  } elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) {
2987  // Wrapping pour les images des stats produits
2988  if ($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) {
2989  $accessallowed = 1;
2990  }
2991  $original_file = (!empty($conf->product->multidir_temp[$entity]) ? $conf->product->multidir_temp[$entity] : $conf->service->multidir_temp[$entity]).'/'.$original_file;
2992  } elseif (in_array($modulepart, array('tax', 'tax-vat', 'tva')) && !empty($conf->tax->dir_output)) {
2993  // Wrapping for taxes
2994  if ($fuser->hasRight('tax', 'charges', $lire)) {
2995  $accessallowed = 1;
2996  }
2997  $modulepartsuffix = str_replace('tax-', '', $modulepart);
2998  $original_file = $conf->tax->dir_output.'/'.($modulepartsuffix != 'tax' ? $modulepartsuffix.'/' : '').$original_file;
2999  } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
3000  // Wrapping for events
3001  if ($fuser->hasRight('agenda', 'myactions', $read)) {
3002  $accessallowed = 1;
3003  // If we known $id of project, call checkUserAccessToObject to check permission on the given agenda event on properties and assigned users
3004  if ($refname && !preg_match('/^specimen/i', $original_file)) {
3005  include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
3006  $tmpobject = new ActionComm($db);
3007  $tmpobject->fetch((int) $refname);
3008  $accessallowed = checkUserAccessToObject($user, array('agenda'), $tmpobject->id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id', '');
3009  if ($user->socid && $tmpobject->socid) {
3010  $accessallowed = checkUserAccessToObject($user, array('societe'), $tmpobject->socid);
3011  }
3012  }
3013  }
3014  $original_file = $conf->agenda->dir_output.'/'.$original_file;
3015  } elseif ($modulepart == 'category' && !empty($conf->categorie->multidir_output[$entity])) {
3016  // Wrapping for categories (categories are allowed if user has permission to read categories or to work on TakePos)
3017  if (empty($entity) || empty($conf->categorie->multidir_output[$entity])) {
3018  return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3019  }
3020  if ($fuser->hasRight("categorie", $lire) || $fuser->hasRight("takepos", "run")) {
3021  $accessallowed = 1;
3022  }
3023  $original_file = $conf->categorie->multidir_output[$entity].'/'.$original_file;
3024  } elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) {
3025  // Wrapping pour les prelevements
3026  if ($fuser->hasRight('prelevement', 'bons', $lire) || preg_match('/^specimen/i', $original_file)) {
3027  $accessallowed = 1;
3028  }
3029  $original_file = $conf->prelevement->dir_output.'/'.$original_file;
3030  } elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp)) {
3031  // Wrapping pour les graph energie
3032  $accessallowed = 1;
3033  $original_file = $conf->stock->dir_temp.'/'.$original_file;
3034  } elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp)) {
3035  // Wrapping pour les graph fournisseurs
3036  $accessallowed = 1;
3037  $original_file = $conf->fournisseur->dir_temp.'/'.$original_file;
3038  } elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp)) {
3039  // Wrapping pour les graph des produits
3040  $accessallowed = 1;
3041  $original_file = $conf->product->multidir_temp[$entity].'/'.$original_file;
3042  } elseif ($modulepart == 'barcode') {
3043  // Wrapping pour les code barre
3044  $accessallowed = 1;
3045  // If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
3046  //$original_file=$conf->barcode->dir_temp.'/'.$original_file;
3047  $original_file = '';
3048  } elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp)) {
3049  // Wrapping for icon of background of mailings
3050  $accessallowed = 1;
3051  $original_file = $conf->mailing->dir_temp.'/'.$original_file;
3052  } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
3053  // Wrapping pour le scanner
3054  $accessallowed = 1;
3055  $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
3056  } elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output)) {
3057  // Wrapping pour les images fckeditor
3058  $accessallowed = 1;
3059  $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
3060  } elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) {
3061  // Wrapping for users
3062  $canreaduser = (!empty($fuser->admin) || $fuser->rights->user->user->{$lire});
3063  if ($fuser->id == (int) $refname) {
3064  $canreaduser = 1;
3065  } // A user can always read its own card
3066  if ($canreaduser || preg_match('/^specimen/i', $original_file)) {
3067  $accessallowed = 1;
3068  }
3069  $original_file = $conf->user->dir_output.'/'.$original_file;
3070  } elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->multidir_output[$entity])) {
3071  // Wrapping for third parties
3072  if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
3073  return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3074  }
3075  if ($fuser->hasRight('societe', $lire) || preg_match('/^specimen/i', $original_file)) {
3076  $accessallowed = 1;
3077  }
3078  $original_file = $conf->societe->multidir_output[$entity].'/'.$original_file;
3079  $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe').")";
3080  } elseif ($modulepart == 'contact' && !empty($conf->societe->multidir_output[$entity])) {
3081  // Wrapping for contact
3082  if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
3083  return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3084  }
3085  if ($fuser->hasRight('societe', $lire)) {
3086  $accessallowed = 1;
3087  }
3088  $original_file = $conf->societe->multidir_output[$entity].'/contact/'.$original_file;
3089  } elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->invoice->multidir_output[$entity])) {
3090  // Wrapping for invoices
3091  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3092  $accessallowed = 1;
3093  }
3094  $original_file = $conf->invoice->multidir_output[$entity].'/'.$original_file;
3095  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('invoice').")";
3096  } elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) {
3097  // Wrapping for mass actions
3098  if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
3099  $accessallowed = 1;
3100  }
3101  $original_file = $conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
3102  } elseif ($modulepart == 'massfilesarea_orders') {
3103  if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3104  $accessallowed = 1;
3105  }
3106  $original_file = $conf->order->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
3107  } elseif ($modulepart == 'massfilesarea_sendings') {
3108  if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
3109  $accessallowed = 1;
3110  }
3111  $original_file = $conf->expedition->dir_output.'/sending/temp/massgeneration/'.$user->id.'/'.$original_file;
3112  } elseif ($modulepart == 'massfilesarea_receipts') {
3113  if ($fuser->hasRight('reception', $lire) || preg_match('/^specimen/i', $original_file)) {
3114  $accessallowed = 1;
3115  }
3116  $original_file = $conf->reception->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3117  } elseif ($modulepart == 'massfilesarea_invoices') {
3118  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3119  $accessallowed = 1;
3120  }
3121  $original_file = $conf->invoice->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
3122  } elseif ($modulepart == 'massfilesarea_expensereport') {
3123  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3124  $accessallowed = 1;
3125  }
3126  $original_file = $conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3127  } elseif ($modulepart == 'massfilesarea_interventions') {
3128  if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
3129  $accessallowed = 1;
3130  }
3131  $original_file = $conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3132  } elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) {
3133  if ($fuser->hasRight('supplier_proposal', $lire) || preg_match('/^specimen/i', $original_file)) {
3134  $accessallowed = 1;
3135  }
3136  $original_file = $conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3137  } elseif ($modulepart == 'massfilesarea_supplier_order') {
3138  if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3139  $accessallowed = 1;
3140  }
3141  $original_file = $conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3142  } elseif ($modulepart == 'massfilesarea_supplier_invoice') {
3143  if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3144  $accessallowed = 1;
3145  }
3146  $original_file = $conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3147  } elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contract->dir_output)) {
3148  if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
3149  $accessallowed = 1;
3150  }
3151  $original_file = $conf->contract->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3152  } elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) {
3153  // Wrapping for interventions
3154  if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
3155  $accessallowed = 1;
3156  }
3157  $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
3158  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3159  } elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) {
3160  // Wrapping pour les deplacements et notes de frais
3161  if ($fuser->hasRight('deplacement', $lire) || preg_match('/^specimen/i', $original_file)) {
3162  $accessallowed = 1;
3163  }
3164  $original_file = $conf->deplacement->dir_output.'/'.$original_file;
3165  //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3166  } elseif (($modulepart == 'propal' || $modulepart == 'propale') && isset($conf->propal->multidir_output[$entity])) {
3167  // Wrapping pour les propales
3168  if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
3169  $accessallowed = 1;
3170  }
3171  $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
3172  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('propal').")";
3173  } elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->order->multidir_output[$entity])) {
3174  // Wrapping pour les commandes
3175  if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3176  $accessallowed = 1;
3177  }
3178  $original_file = $conf->order->multidir_output[$entity].'/'.$original_file;
3179  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")";
3180  } elseif ($modulepart == 'project' && !empty($conf->project->multidir_output[$entity])) {
3181  // Wrapping pour les projects
3182  if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3183  $accessallowed = 1;
3184  // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3185  if ($refname && !preg_match('/^specimen/i', $original_file)) {
3186  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
3187  $tmpproject = new Project($db);
3188  $tmpproject->fetch('', $refname);
3189  $accessallowed = checkUserAccessToObject($user, array('projet'), $tmpproject->id, 'projet&project', '', '', 'rowid', '');
3190  }
3191  }
3192  $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3193  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3194  } elseif ($modulepart == 'project_task' && !empty($conf->project->multidir_output[$entity])) {
3195  if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3196  $accessallowed = 1;
3197  // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3198  if ($refname && !preg_match('/^specimen/i', $original_file)) {
3199  include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
3200  $tmptask = new Task($db);
3201  $tmptask->fetch('', $refname);
3202  $accessallowed = checkUserAccessToObject($user, array('projet_task'), $tmptask->id, 'projet_task&project', '', '', 'rowid', '');
3203  }
3204  }
3205  $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3206  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3207  } elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) {
3208  // Wrapping pour les commandes fournisseurs
3209  if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3210  $accessallowed = 1;
3211  }
3212  $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
3213  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3214  } elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) {
3215  // Wrapping pour les factures fournisseurs
3216  if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3217  $accessallowed = 1;
3218  }
3219  $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
3220  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3221  } elseif ($modulepart == 'supplier_payment') {
3222  // Wrapping pour les rapport de paiements
3223  if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3224  $accessallowed = 1;
3225  }
3226  $original_file = $conf->fournisseur->payment->dir_output.'/'.$original_file;
3227  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3228  } elseif ($modulepart == 'payment') {
3229  // Wrapping pour les rapport de paiements
3230  if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) {
3231  $accessallowed = 1;
3232  }
3233  $original_file = $conf->compta->payment->dir_output.'/'.$original_file;
3234  } elseif ($modulepart == 'facture_paiement' && !empty($conf->invoice->dir_output)) {
3235  // Wrapping pour les rapport de paiements
3236  if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3237  $accessallowed = 1;
3238  }
3239  if ($fuser->socid > 0) {
3240  $original_file = $conf->invoice->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file;
3241  } else {
3242  $original_file = $conf->invoice->dir_output.'/payments/'.$original_file;
3243  }
3244  } elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) {
3245  // Wrapping for accounting exports
3246  if ($fuser->hasRight('accounting', 'bind', 'write') || preg_match('/^specimen/i', $original_file)) {
3247  $accessallowed = 1;
3248  }
3249  $original_file = $conf->accounting->dir_output.'/'.$original_file;
3250  } elseif (($modulepart == 'expedition' || $modulepart == 'shipment') && !empty($conf->expedition->dir_output)) {
3251  // Wrapping pour les expedition
3252  if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
3253  $accessallowed = 1;
3254  }
3255  $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'sending/') === 0 ? '' : 'sending/').$original_file;
3256  //$original_file = $conf->expedition->dir_output."/".$original_file;
3257  } elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output)) {
3258  // Delivery Note Wrapping
3259  if ($fuser->hasRight('expedition', 'delivery', $lire) || preg_match('/^specimen/i', $original_file)) {
3260  $accessallowed = 1;
3261  }
3262  $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'receipt/') === 0 ? '' : 'receipt/').$original_file;
3263  } elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) {
3264  // Wrapping pour les actions
3265  if ($fuser->hasRight('agenda', 'allactions', $read) || preg_match('/^specimen/i', $original_file)) {
3266  $accessallowed = 1;
3267  }
3268  $original_file = $conf->agenda->dir_temp."/".$original_file;
3269  } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
3270  // Wrapping pour les produits et services
3271  if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) {
3272  return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3273  }
3274  if (($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) || preg_match('/^specimen/i', $original_file)) {
3275  $accessallowed = 1;
3276  }
3277  if (isModEnabled("product")) {
3278  $original_file = $conf->product->multidir_output[$entity].'/'.$original_file;
3279  } elseif (isModEnabled("service")) {
3280  $original_file = $conf->service->multidir_output[$entity].'/'.$original_file;
3281  }
3282  } elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') {
3283  // Wrapping pour les lots produits
3284  if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) {
3285  return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3286  }
3287  if (($fuser->hasRight('produit', $lire)) || preg_match('/^specimen/i', $original_file)) {
3288  $accessallowed = 1;
3289  }
3290  if (isModEnabled('productbatch')) {
3291  $original_file = $conf->productbatch->multidir_output[$entity].'/'.$original_file;
3292  }
3293  } elseif ($modulepart == 'movement' || $modulepart == 'mouvement') {
3294  // Wrapping for stock movements
3295  if (empty($entity) || empty($conf->stock->multidir_output[$entity])) {
3296  return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3297  }
3298  if (($fuser->hasRight('stock', $lire) || $fuser->hasRight('stock', 'movement', $lire) || $fuser->hasRight('stock', 'mouvement', $lire)) || preg_match('/^specimen/i', $original_file)) {
3299  $accessallowed = 1;
3300  }
3301  if (isModEnabled('stock')) {
3302  $original_file = $conf->stock->multidir_output[$entity].'/movement/'.$original_file;
3303  }
3304  } elseif ($modulepart == 'contract' && !empty($conf->contract->multidir_output[$entity])) {
3305  // Wrapping pour les contrats
3306  if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
3307  $accessallowed = 1;
3308  }
3309  $original_file = $conf->contract->multidir_output[$entity].'/'.$original_file;
3310  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract').")";
3311  } elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) {
3312  // Wrapping pour les dons
3313  if ($fuser->hasRight('don', $lire) || preg_match('/^specimen/i', $original_file)) {
3314  $accessallowed = 1;
3315  }
3316  $original_file = $conf->don->dir_output.'/'.$original_file;
3317  } elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) {
3318  // Wrapping pour les dons
3319  if ($fuser->hasRight('resource', $read) || preg_match('/^specimen/i', $original_file)) {
3320  $accessallowed = 1;
3321  }
3322  $original_file = $conf->resource->dir_output.'/'.$original_file;
3323  } elseif (($modulepart == 'remisecheque' || $modulepart == 'chequereceipt') && !empty($conf->bank->dir_output)) {
3324  // Wrapping pour les remises de cheques
3325  if ($fuser->hasRight('banque', $lire) || preg_match('/^specimen/i', $original_file)) {
3326  $accessallowed = 1;
3327  }
3328  $original_file = $conf->bank->dir_output.'/checkdeposits/'.$original_file; // original_file should contains relative path so include the get_exdir result
3329  } elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) {
3330  // Wrapping for bank
3331  if ($fuser->hasRight('banque', $lire)) {
3332  $accessallowed = 1;
3333  }
3334  $original_file = $conf->bank->dir_output.'/'.$original_file;
3335  } elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) {
3336  // Wrapping for export module
3337  // Note that a test may not be required because we force the dir of download on the directory of the user that export
3338  $accessallowed = $user->hasRight('export', 'lire');
3339  $original_file = $conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file;
3340  } elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) {
3341  // Wrapping for import module
3342  $accessallowed = $user->hasRight('import', 'run');
3343  $original_file = $conf->import->dir_temp.'/'.$original_file;
3344  } elseif ($modulepart == 'recruitment' && !empty($conf->recruitment->dir_output)) {
3345  // Wrapping for recruitment module
3346  $accessallowed = $user->hasRight('recruitment', 'recruitmentjobposition', 'read');
3347  $original_file = $conf->recruitment->dir_output.'/'.$original_file;
3348  } elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) {
3349  // Wrapping for wysiwyg editor
3350  $accessallowed = 1;
3351  $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
3352  } elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) {
3353  // Wrapping for backups
3354  if ($fuser->admin) {
3355  $accessallowed = 1;
3356  }
3357  $original_file = $conf->admin->dir_output.'/'.$original_file;
3358  } elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) {
3359  // Wrapping for upload file test
3360  if ($fuser->admin) {
3361  $accessallowed = 1;
3362  }
3363  $original_file = $conf->admin->dir_temp.'/'.$original_file;
3364  } elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) {
3365  // Wrapping pour BitTorrent
3366  $accessallowed = 1;
3367  $dir = 'files';
3368  if (dol_mimetype($original_file) == 'application/x-bittorrent') {
3369  $dir = 'torrents';
3370  }
3371  $original_file = $conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
3372  } elseif ($modulepart == 'member' && !empty($conf->member->dir_output)) {
3373  // Wrapping pour Foundation module
3374  if ($fuser->hasRight('adherent', $lire) || preg_match('/^specimen/i', $original_file)) {
3375  $accessallowed = 1;
3376  }
3377  $original_file = $conf->member->dir_output.'/'.$original_file;
3378  // If modulepart=module_user_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser
3379  // If modulepart=module_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp
3380  // If modulepart=module_user Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser
3381  // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3382  // If modulepart=module-abc Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3383  } else {
3384  // GENERIC Wrapping
3385  //var_dump($modulepart);
3386  //var_dump($original_file);
3387  if (preg_match('/^specimen/i', $original_file)) {
3388  $accessallowed = 1; // If link to a file called specimen. Test must be done before changing $original_file int full path.
3389  }
3390  if ($fuser->admin) {
3391  $accessallowed = 1; // If user is admin
3392  }
3393 
3394  $tmpmodulepart = explode('-', $modulepart);
3395  if (!empty($tmpmodulepart[1])) {
3396  $modulepart = $tmpmodulepart[0];
3397  $original_file = $tmpmodulepart[1].'/'.$original_file;
3398  }
3399 
3400  // Define $accessallowed
3401  $reg = array();
3402  if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) {
3403  $tmpmodule = $reg[1];
3404  if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3405  dol_print_error(null, 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3406  exit;
3407  }
3408  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3409  $accessallowed = 1;
3410  }
3411  $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
3412  } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) {
3413  $tmpmodule = $reg[1];
3414  if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3415  dol_print_error(null, 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3416  exit;
3417  }
3418  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3419  $accessallowed = 1;
3420  }
3421  $original_file = $conf->$tmpmodule->dir_temp.'/'.$original_file;
3422  } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) {
3423  $tmpmodule = $reg[1];
3424  if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3425  dol_print_error(null, 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3426  exit;
3427  }
3428  if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3429  $accessallowed = 1;
3430  }
3431  $original_file = $conf->$tmpmodule->dir_output.'/'.$fuser->id.'/'.$original_file;
3432  } elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) {
3433  $tmpmodule = $reg[1];
3434  if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3435  dol_print_error(null, 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3436  exit;
3437  }
3438  if ($fuser->hasRight($tmpmodule, $lire) || preg_match('/^specimen/i', $original_file)) {
3439  $accessallowed = 1;
3440  }
3441  $original_file = $conf->$tmpmodule->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3442  } else {
3443  if (empty($conf->$modulepart->dir_output)) { // modulepart not supported
3444  dol_print_error(null, '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.');
3445  exit;
3446  }
3447 
3448  // Check fuser->rights->modulepart->myobject->read and fuser->rights->modulepart->read
3449  $partsofdirinoriginalfile = explode('/', $original_file);
3450  if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use)
3451  $partofdirinoriginalfile = $partsofdirinoriginalfile[0];
3452  if ($partofdirinoriginalfile && ($fuser->hasRight($modulepart, $partofdirinoriginalfile, 'lire') || $fuser->hasRight($modulepart, $partofdirinoriginalfile, 'read'))) {
3453  $accessallowed = 1;
3454  }
3455  }
3456  if ($fuser->hasRight($modulepart, $lire) || $fuser->hasRight($modulepart, $read)) {
3457  $accessallowed = 1;
3458  }
3459 
3460  if (is_array($conf->$modulepart->multidir_output) && !empty($conf->$modulepart->multidir_output[$entity])) {
3461  $original_file = $conf->$modulepart->multidir_output[$entity].'/'.$original_file;
3462  } else {
3463  $original_file = $conf->$modulepart->dir_output.'/'.$original_file;
3464  }
3465  }
3466 
3467  $parameters = array(
3468  'modulepart' => $modulepart,
3469  'original_file' => $original_file,
3470  'entity' => $entity,
3471  'fuser' => $fuser,
3472  'refname' => '',
3473  'mode' => $mode
3474  );
3475  $reshook = $hookmanager->executeHooks('checkSecureAccess', $parameters, $object);
3476  if ($reshook > 0) {
3477  if (!empty($hookmanager->resArray['original_file'])) {
3478  $original_file = $hookmanager->resArray['original_file'];
3479  }
3480  if (!empty($hookmanager->resArray['accessallowed'])) {
3481  $accessallowed = $hookmanager->resArray['accessallowed'];
3482  }
3483  if (!empty($hookmanager->resArray['sqlprotectagainstexternals'])) {
3484  $sqlprotectagainstexternals = $hookmanager->resArray['sqlprotectagainstexternals'];
3485  }
3486  }
3487  }
3488 
3489  $ret = array(
3490  'accessallowed' => ($accessallowed ? 1 : 0),
3491  'sqlprotectagainstexternals' => $sqlprotectagainstexternals,
3492  'original_file' => $original_file
3493  );
3494 
3495  return $ret;
3496 }
3497 
3506 function dol_filecache($directory, $filename, $object)
3507 {
3508  if (!dol_is_dir($directory)) {
3509  $result = dol_mkdir($directory);
3510  if ($result < -1) {
3511  dol_syslog("Failed to create the cache directory ".$directory, LOG_WARNING);
3512  }
3513  }
3514  $cachefile = $directory.$filename;
3515 
3516  file_put_contents($cachefile, serialize($object), LOCK_EX);
3517 
3518  dolChmod($cachefile, '0644');
3519 }
3520 
3529 function dol_cache_refresh($directory, $filename, $cachetime)
3530 {
3531  $now = dol_now();
3532  $cachefile = $directory.$filename;
3533  $refresh = !file_exists($cachefile) || ($now - $cachetime) > dol_filemtime($cachefile);
3534  return $refresh;
3535 }
3536 
3544 function dol_readcachefile($directory, $filename)
3545 {
3546  $cachefile = $directory.$filename;
3547  $object = unserialize(file_get_contents($cachefile));
3548  return $object;
3549 }
3550 
3557 function dirbasename($pathfile)
3558 {
3559  return preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'\//', '', $pathfile);
3560 }
3561 
3562 
3574 function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
3575 {
3576  global $conffile;
3577 
3578  $exclude = 'install';
3579 
3580  foreach ($dir->md5file as $file) { // $file is a simpleXMLElement
3581  $filename = $path.$file['name'];
3582  $file_list['insignature'][] = $filename;
3583  $expectedsize = (empty($file['size']) ? '' : $file['size']);
3584  $expectedmd5 = (string) $file;
3585 
3586  if (!file_exists($pathref.'/'.$filename)) {
3587  $file_list['missing'][] = array('filename' => $filename, 'expectedmd5' => $expectedmd5, 'expectedsize' => $expectedsize);
3588  } else {
3589  $md5_local = md5_file($pathref.'/'.$filename);
3590 
3591  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
3592  $checksumconcat[] = $expectedmd5;
3593  } else {
3594  if ($md5_local != $expectedmd5) {
3595  $file_list['updated'][] = array('filename' => $filename, 'expectedmd5' => $expectedmd5, 'expectedsize' => $expectedsize, 'md5' => (string) $md5_local);
3596  }
3597  $checksumconcat[] = $md5_local;
3598  }
3599  }
3600  }
3601 
3602  foreach ($dir->dir as $subdir) { // $subdir['name'] is '' or '/accountancy/admin' for example
3603  getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat);
3604  }
3605 
3606  return $file_list;
3607 }
3608 
3616 function dragAndDropFileUpload($htmlname)
3617 {
3618  global $object, $langs;
3619 
3620  $out = "";
3621  $out .= '<div id="'.$htmlname.'Message" class="dragDropAreaMessage hidden"><span>'.img_picto("", 'download').'<br>'.$langs->trans("DropFileToAddItToObject").'</span></div>';
3622  $out .= "\n<!-- JS CODE TO ENABLE DRAG AND DROP OF FILE -->\n";
3623  $out .= "<script>";
3624  $out .= '
3625  jQuery(document).ready(function() {
3626  var enterTargetDragDrop = null;
3627 
3628  $("#'.$htmlname.'").addClass("cssDragDropArea");
3629 
3630  $(".cssDragDropArea").on("dragenter", function(ev, ui) {
3631  var dataTransfer = ev.originalEvent.dataTransfer;
3632  var dataTypes = dataTransfer.types;
3633  //console.log(dataTransfer);
3634  //console.log(dataTypes);
3635 
3636  if (!dataTypes || ($.inArray(\'Files\', dataTypes) === -1)) {
3637  // The element dragged is not a file, so we avoid the "dragenter"
3638  ev.preventDefault();
3639  return false;
3640  }
3641 
3642  // Entering drop area. Highlight area
3643  console.log("dragAndDropFileUpload: We add class highlightDragDropArea")
3644  enterTargetDragDrop = ev.target;
3645  $(this).addClass("highlightDragDropArea");
3646  $("#'.$htmlname.'Message").removeClass("hidden");
3647  ev.preventDefault();
3648  });
3649 
3650  $(".cssDragDropArea").on("dragleave", function(ev) {
3651  // Going out of drop area. Remove Highlight
3652  if (enterTargetDragDrop == ev.target){
3653  console.log("dragAndDropFileUpload: We remove class highlightDragDropArea")
3654  $("#'.$htmlname.'Message").addClass("hidden");
3655  $(this).removeClass("highlightDragDropArea");
3656  }
3657  });
3658 
3659  $(".cssDragDropArea").on("dragover", function(ev) {
3660  ev.preventDefault();
3661  return false;
3662  });
3663 
3664  $(".cssDragDropArea").on("drop", function(e) {
3665  console.log("Trigger event file dropped. fk_element='.dol_escape_js($object->id).' element='.dol_escape_js($object->element).'");
3666  e.preventDefault();
3667  fd = new FormData();
3668  fd.append("fk_element", "'.dol_escape_js($object->id).'");
3669  fd.append("element", "'.dol_escape_js($object->element).'");
3670  fd.append("token", "'.currentToken().'");
3671  fd.append("action", "linkit");
3672 
3673  var dataTransfer = e.originalEvent.dataTransfer;
3674 
3675  if (dataTransfer.files && dataTransfer.files.length){
3676  var droppedFiles = e.originalEvent.dataTransfer.files;
3677  $.each(droppedFiles, function(index,file){
3678  fd.append("files[]", file,file.name)
3679  });
3680  }
3681  $(".cssDragDropArea").removeClass("highlightDragDropArea");
3682  counterdragdrop = 0;
3683  $.ajax({
3684  url: "'.DOL_URL_ROOT.'/core/ajax/fileupload.php",
3685  type: "POST",
3686  processData: false,
3687  contentType: false,
3688  data: fd,
3689  success:function() {
3690  console.log("Uploaded.", arguments);
3691  /* arguments[0] is the json string of files */
3692  /* arguments[1] is the value for variable "success", can be 0 or 1 */
3693  let listoffiles = JSON.parse(arguments[0]);
3694  console.log(listoffiles);
3695  let nboferror = 0;
3696  for (let i = 0; i < listoffiles.length; i++) {
3697  console.log(listoffiles[i].error);
3698  if (listoffiles[i].error) {
3699  nboferror++;
3700  }
3701  }
3702  console.log(nboferror);
3703  if (nboferror > 0) {
3704  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorOnAtLeastOneFileUpload:warnings";
3705  } else {
3706  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=UploadFileDragDropSuccess:mesgs";
3707  }
3708  },
3709  error:function() {
3710  console.log("Error Uploading.", arguments)
3711  if (arguments[0].status == 403) {
3712  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadPermissionDenied:errors";
3713  }
3714  window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadFileDragDropPermissionDenied:errors";
3715  },
3716  })
3717  });
3718  });
3719  ';
3720  $out .= "</script>\n";
3721  return $out;
3722 }
3723 
3734 function archiveOrBackupFile($filetpl, $max_versions = 5, $archivedir = '', $suffix = "v", $moveorcopy = 'move')
3735 {
3736  $base_file_pattern = ($archivedir ? $archivedir : dirname($filetpl)).'/'.basename($filetpl).".".$suffix;
3737  $files_in_directory = glob($base_file_pattern . "*");
3738 
3739  // Extract the modification timestamps for each file
3740  $files_with_timestamps = [];
3741  foreach ($files_in_directory as $file) {
3742  $files_with_timestamps[] = [
3743  'file' => $file,
3744  'timestamp' => filemtime($file)
3745  ];
3746  }
3747 
3748  // Sort the files by modification date
3749  $sorted_files = [];
3750  while (count($files_with_timestamps) > 0) {
3751  $latest_file = null;
3752  $latest_index = null;
3753 
3754  // Find the latest file by timestamp
3755  foreach ($files_with_timestamps as $index => $file_info) {
3756  if ($latest_file === null || (is_array($latest_file) && $file_info['timestamp'] > $latest_file['timestamp'])) {
3757  $latest_file = $file_info;
3758  $latest_index = $index;
3759  }
3760  }
3761 
3762  // Add the latest file to the sorted list and remove it from the original list
3763  if ($latest_file !== null) {
3764  $sorted_files[] = $latest_file['file'];
3765  unset($files_with_timestamps[$latest_index]);
3766  }
3767  }
3768 
3769  // Delete the oldest files to keep only the allowed number of versions
3770  if (count($sorted_files) >= $max_versions) {
3771  $oldest_files = array_slice($sorted_files, $max_versions - 1);
3772  foreach ($oldest_files as $oldest_file) {
3773  dol_delete_file($oldest_file);
3774  }
3775  }
3776 
3777  $timestamp = dol_now('gmt');
3778  $new_backup = $filetpl . ".v" . $timestamp;
3779 
3780  // Move or copy the original file to the new backup with the timestamp
3781  if ($moveorcopy == 'move') {
3782  $result = dol_move($filetpl, $new_backup, '0', 1, 0, 0);
3783  } else {
3784  $result = dol_copy($filetpl, $new_backup, '0', 1, 0, 0);
3785  }
3786 
3787  if (!$result) {
3788  return false;
3789  }
3790 
3791  return true;
3792 }
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
Class to manage agenda events (actions)
Class to scan for virus.
Class to manage ECM files.
Class to manage Trips and Expenses.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class of the module paid holiday.
Class to manage hooks.
Class to manage projects.
Class to manage tasks.
Definition: task.class.php:41
Class to manage Dolibarr users.
Definition: user.class.php:50
Class to manage utility methods.
Definition: utils.class.php:34
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
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:3557
dol_is_link($pathoffile)
Return if path is a symbolic link.
Definition: files.lib.php:531
dol_compare_file($a, $b)
Fast compare of 2 files identified by their properties ->name, ->date and ->size.
Definition: files.lib.php:446
dol_meta_create($object)
Create a meta file with document file into same directory.
Definition: files.lib.php:1739
dol_is_url($uri)
Return if path is an URI (the name of the method is misleading).
Definition: files.lib.php:557
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition: files.lib.php:38
getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path='', $pathref='', &$checksumconcat=array())
Function to get list of updated or modified files.
Definition: files.lib.php:3574
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:647
dol_filesize($pathoffile)
Return size of a file.
Definition: files.lib.php:635
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:1609
dol_copy($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
Definition: files.lib.php:767
archiveOrBackupFile($filetpl, $max_versions=5, $archivedir='', $suffix="v", $moveorcopy='move')
Manage backup versions for a given file, ensuring only a maximum number of versions are kept.
Definition: files.lib.php:3734
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:1458
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Check validity of a file upload from an GUI page, and move it to its final destination.
Definition: files.lib.php:1320
dol_move_dir($srcdir, $destdir, $overwriteifexists=1, $indexdatabase=1, $renamedircontent=1)
Move a directory into another name.
Definition: files.lib.php:1175
dol_fileperm($pathoffile)
Return permissions of a file.
Definition: files.lib.php:659
dol_is_writable($folderorfile)
Test if directory or filename is writable.
Definition: files.lib.php:543
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
Definition: files.lib.php:1584
dol_add_file_process($upload_dir, $allowoverwrite=0, $updatesessionordb=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:1862
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
Definition: files.lib.php:2452
dol_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
Definition: files.lib.php:1011
dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser=null, $refname='', $mode='read')
Security check when accessing to a document (used by document.php, viewimage.php and webservices to g...
Definition: files.lib.php:2725
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:1824
addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded', $setsharekey=0, $object=null)
Add a file into database index.
Definition: files.lib.php:2101
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
Definition: files.lib.php:2266
dol_filecache($directory, $filename, $object)
Store object in file.
Definition: files.lib.php:3506
dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null, $excludesubdir=0, $excludefileext=null, $excludearchivefiles=0)
Copy a dir to another dir.
Definition: files.lib.php:896
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:262
dragAndDropFileUpload($htmlname)
Function to manage the drag and drop of a file.
Definition: files.lib.php:3616
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:519
dol_count_nb_of_line($file)
Count number of lines in a file.
Definition: files.lib.php:602
dol_most_recent_file($dir, $regexfilter='', $excludefilter=array('(\.meta|_preview.*\.png)$', '^\.'), $nohook=0, $mode=0)
Return file(s) into a directory (by default most recent)
Definition: files.lib.php:2706
dolCheckVirus($src_file, $dest_file='')
Check virus into a file.
Definition: files.lib.php:1251
dol_unescapefile($filename)
Unescape a file submitted by upload.
Definition: files.lib.php:1235
dol_dir_is_emtpy($folder)
Test if a folder is empty.
Definition: files.lib.php:569
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:2043
dolCheckOnFileName($src_file, $dest_file='')
Check virus into a file.
Definition: files.lib.php:1281
dol_dir_list($utf8_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:63
deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded')
Delete files into database index using search criteria.
Definition: files.lib.php:2207
dol_readcachefile($directory, $filename)
Read object from cachefile.
Definition: files.lib.php:3544
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:489
completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
Complete $filearray with data from database.
Definition: files.lib.php:341
dol_cache_refresh($directory, $filename, $cachetime)
Test if Refresh needed.
Definition: files.lib.php:3529
dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask='0', $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
Definition: files.lib.php:677
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1661
dol_is_dir_empty($dir)
Return if path is empty.
Definition: files.lib.php:505
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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:513
if(!defined('IMAGETYPE_WEBP')) getDefaultImageSizes()
Return default values for image sizes.
Definition: images.lib.php:44
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Definition: images.lib.php:84
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
checkUserAccessToObject($user, array $featuresarray, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='', $dbt_select='rowid', $parenttableforentity='')
Check that access by a given user to an object is ok.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.