dolibarr  13.0.2
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-2015 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2012-2016 Juanjo Menent <jmenent@2byte.es>
5  * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
6  * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
7  * Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  * or see https://www.gnu.org/
22  */
23 
36 function dol_basename($pathfile)
37 {
38  return preg_replace('/^.*\/([^\/]+)$/', '$1', rtrim($pathfile, '/'));
39 }
40 
60 function dol_dir_list($path, $types = "all", $recursive = 0, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0, $nohook = 0, $relativename = "", $donotfollowsymlinks = 0)
61 {
62  global $db, $hookmanager;
63  global $object;
64 
65  dol_syslog("files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter));
66  //print 'xxx'."files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter);
67 
68  $loaddate = ($mode == 1 || $mode == 2) ?true:false;
69  $loadsize = ($mode == 1 || $mode == 3) ?true:false;
70 
71  // Clean parameters
72  $path = preg_replace('/([\\/]+)$/i', '', $path);
73  $newpath = dol_osencode($path);
74 
75  $reshook = 0;
76  $file_list = array();
77 
78  if (is_object($hookmanager) && !$nohook)
79  {
80  $hookmanager->resArray = array();
81 
82  $hookmanager->initHooks(array('fileslib'));
83 
84  $parameters = array(
85  'path' => $newpath,
86  'types'=> $types,
87  'recursive' => $recursive,
88  'filter' => $filter,
89  'excludefilter' => $excludefilter,
90  'sortcriteria' => $sortcriteria,
91  'sortorder' => $sortorder,
92  'loaddate' => $loaddate,
93  'loadsize' => $loadsize,
94  'mode' => $mode
95  );
96  $reshook = $hookmanager->executeHooks('getDirList', $parameters, $object);
97  }
98 
99  // $hookmanager->resArray may contain array stacked by other modules
100  if (empty($reshook))
101  {
102  if (!is_dir($newpath)) return array();
103 
104  if ($dir = opendir($newpath))
105  {
106  $filedate = '';
107  $filesize = '';
108 
109  while (false !== ($file = readdir($dir))) // $file is always a basename (into directory $newpath)
110  {
111  if (!utf8_check($file)) $file = utf8_encode($file); // To be sure data is stored in utf8 in memory
112  $fullpathfile = ($newpath ? $newpath.'/' : '').$file;
113 
114  $qualified = 1;
115 
116  // Define excludefilterarray
117  $excludefilterarray = array('^\.');
118  if (is_array($excludefilter))
119  {
120  $excludefilterarray = array_merge($excludefilterarray, $excludefilter);
121  } elseif ($excludefilter) $excludefilterarray[] = $excludefilter;
122  // Check if file is qualified
123  foreach ($excludefilterarray as $filt)
124  {
125  if (preg_match('/'.$filt.'/i', $file) || preg_match('/'.$filt.'/i', $fullpathfile)) {
126  $qualified = 0; break;
127  }
128  }
129  //print $fullpathfile.' '.$file.' '.$qualified.'<br>';
130 
131  if ($qualified)
132  {
133  $isdir = is_dir(dol_osencode($path."/".$file));
134  // Check whether this is a file or directory and whether we're interested in that type
135  if ($isdir && (($types == "directories") || ($types == "all") || $recursive))
136  {
137  // Add entry into file_list array
138  if (($types == "directories") || ($types == "all"))
139  {
140  if ($loaddate || $sortcriteria == 'date') $filedate = dol_filemtime($path."/".$file);
141  if ($loadsize || $sortcriteria == 'size') $filesize = dol_filesize($path."/".$file);
142 
143  if (!$filter || preg_match('/'.$filter.'/i', $file)) // We do not search key $filter into all $path, only into $file part
144  {
145  $reg = array();
146  preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg);
147  $level1name = (isset($reg[1]) ? $reg[1] : '');
148  $file_list[] = array(
149  "name" => $file,
150  "path" => $path,
151  "level1name" => $level1name,
152  "relativename" => ($relativename ? $relativename.'/' : '').$file,
153  "fullname" => $path.'/'.$file,
154  "date" => $filedate,
155  "size" => $filesize,
156  "type" => 'dir'
157  );
158  }
159  }
160 
161  // if we're in a directory and we want recursive behavior, call this function again
162  if ($recursive)
163  {
164  if (empty($donotfollowsymlinks) || !is_link($path."/".$file))
165  {
166  //var_dump('eee '. $path."/".$file. ' '.is_dir($path."/".$file).' '.is_link($path."/".$file));
167  $file_list = array_merge($file_list, dol_dir_list($path."/".$file, $types, $recursive, $filter, $excludefilter, $sortcriteria, $sortorder, $mode, $nohook, ($relativename != '' ? $relativename.'/' : '').$file, $donotfollowsymlinks));
168  }
169  }
170  } elseif (!$isdir && (($types == "files") || ($types == "all")))
171  {
172  // Add file into file_list array
173  if ($loaddate || $sortcriteria == 'date') $filedate = dol_filemtime($path."/".$file);
174  if ($loadsize || $sortcriteria == 'size') $filesize = dol_filesize($path."/".$file);
175 
176  if (!$filter || preg_match('/'.$filter.'/i', $file)) // We do not search key $filter into $path, only into $file
177  {
178  preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg);
179  $level1name = (isset($reg[1]) ? $reg[1] : '');
180  $file_list[] = array(
181  "name" => $file,
182  "path" => $path,
183  "level1name" => $level1name,
184  "relativename" => ($relativename ? $relativename.'/' : '').$file,
185  "fullname" => $path.'/'.$file,
186  "date" => $filedate,
187  "size" => $filesize,
188  "type" => 'file'
189  );
190  }
191  }
192  }
193  }
194  closedir($dir);
195 
196  // Obtain a list of columns
197  if (!empty($sortcriteria) && $sortorder)
198  {
199  $file_list = dol_sort_array($file_list, $sortcriteria, ($sortorder == SORT_ASC ? 'asc' : 'desc'));
200  }
201  }
202  }
203 
204  if (is_object($hookmanager) && is_array($hookmanager->resArray)) $file_list = array_merge($file_list, $hookmanager->resArray);
205 
206  return $file_list;
207 }
208 
209 
223 function dol_dir_list_in_database($path, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0)
224 {
225  global $conf, $db;
226 
227  $sql = " SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams,";
228  $sql .= " date_c, tms as date_m, fk_user_c, fk_user_m, acl, position, share";
229  if ($mode) $sql .= ", description";
230  $sql .= " FROM ".MAIN_DB_PREFIX."ecm_files";
231  $sql .= " WHERE entity = ".$conf->entity;
232  if (preg_match('/%$/', $path)) {
233  $sql .= " AND filepath LIKE '".$db->escape($path)."'";
234  } else {
235  $sql .= " AND filepath = '".$db->escape($path)."'";
236  }
237 
238  $resql = $db->query($sql);
239  if ($resql)
240  {
241  $file_list = array();
242  $num = $db->num_rows($resql);
243  $i = 0;
244  while ($i < $num)
245  {
246  $obj = $db->fetch_object($resql);
247  if ($obj)
248  {
249  $reg = array();
250  preg_match('/([^\/]+)\/[^\/]+$/', DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename, $reg);
251  $level1name = (isset($reg[1]) ? $reg[1] : '');
252  $file_list[] = array(
253  "rowid" => $obj->rowid,
254  "label" => $obj->label, // md5
255  "name" => $obj->filename,
256  "path" => DOL_DATA_ROOT.'/'.$obj->filepath,
257  "level1name" => $level1name,
258  "fullname" => DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,
259  "fullpath_orig" => $obj->fullpath_orig,
260  "date_c" => $db->jdate($obj->date_c),
261  "date_m" => $db->jdate($obj->date_m),
262  "type" => 'file',
263  "keywords" => $obj->keywords,
264  "cover" => $obj->cover,
265  "position" => (int) $obj->position,
266  "acl" => $obj->acl,
267  "share" => $obj->share
268  );
269  }
270  $i++;
271  }
272 
273  // Obtain a list of columns
274  if (!empty($sortcriteria))
275  {
276  $myarray = array();
277  foreach ($file_list as $key => $row)
278  {
279  $myarray[$key] = (isset($row[$sortcriteria]) ? $row[$sortcriteria] : '');
280  }
281  // Sort the data
282  if ($sortorder) array_multisort($myarray, $sortorder, $file_list);
283  }
284 
285  return $file_list;
286  } else {
287  dol_print_error($db);
288  return array();
289  }
290 }
291 
292 
301 function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
302 {
303  global $conf, $db, $user;
304 
305  $filearrayindatabase = dol_dir_list_in_database($relativedir, '', null, 'name', SORT_ASC);
306 
307  // TODO Remove this when PRODUCT_USE_OLD_PATH_FOR_PHOTO will be removed
308  global $modulepart;
309  if ($modulepart == 'produit' && !empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) {
310  global $object;
311  if (!empty($object->id))
312  {
313  if (!empty($conf->product->enabled)) $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";
314  else $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";
315 
316  $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dirold);
317  $relativedirold = preg_replace('/^[\\/]/', '', $relativedirold);
318 
319  $filearrayindatabase = array_merge($filearrayindatabase, dol_dir_list_in_database($relativedirold, '', null, 'name', SORT_ASC));
320  }
321  }
322 
323  /*var_dump($relativedir);
324  var_dump($filearray);
325  var_dump($filearrayindatabase);*/
326 
327  // Complete filearray with properties found into $filearrayindatabase
328  foreach ($filearray as $key => $val)
329  {
330  $tmpfilename = preg_replace('/\.noexe$/', '', $filearray[$key]['name']);
331  $found = 0;
332  // Search if it exists into $filearrayindatabase
333  foreach ($filearrayindatabase as $key2 => $val2)
334  {
335  if (($filearrayindatabase[$key2]['path'] == $filearray[$key]['path']) && ($filearrayindatabase[$key2]['name'] == $tmpfilename))
336  {
337  $filearray[$key]['position_name'] = ($filearrayindatabase[$key2]['position'] ? $filearrayindatabase[$key2]['position'] : '0').'_'.$filearrayindatabase[$key2]['name'];
338  $filearray[$key]['position'] = $filearrayindatabase[$key2]['position'];
339  $filearray[$key]['cover'] = $filearrayindatabase[$key2]['cover'];
340  $filearray[$key]['acl'] = $filearrayindatabase[$key2]['acl'];
341  $filearray[$key]['rowid'] = $filearrayindatabase[$key2]['rowid'];
342  $filearray[$key]['label'] = $filearrayindatabase[$key2]['label'];
343  $filearray[$key]['share'] = $filearrayindatabase[$key2]['share'];
344  $found = 1;
345  break;
346  }
347  }
348 
349  if (!$found) // This happen in transition toward version 6, or if files were added manually into os dir.
350  {
351  $filearray[$key]['position'] = '999999'; // File not indexed are at end. So if we add a file, it will not replace an existing position
352  $filearray[$key]['cover'] = 0;
353  $filearray[$key]['acl'] = '';
354 
355  $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filearray[$key]['fullname']);
356 
357  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filename)) // If not a tmp file
358  {
359  dol_syslog("list_of_documents We found a file called '".$filearray[$key]['name']."' not indexed into database. We add it");
360  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
361  $ecmfile = new EcmFiles($db);
362 
363  // Add entry into database
364  $filename = basename($rel_filename);
365  $rel_dir = dirname($rel_filename);
366  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
367  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
368 
369  $ecmfile->filepath = $rel_dir;
370  $ecmfile->filename = $filename;
371  $ecmfile->label = md5_file(dol_osencode($filearray[$key]['fullname'])); // $destfile is a full path to file
372  $ecmfile->fullpath_orig = $filearray[$key]['fullname'];
373  $ecmfile->gen_or_uploaded = 'unknown';
374  $ecmfile->description = ''; // indexed content
375  $ecmfile->keyword = ''; // keyword content
376  $result = $ecmfile->create($user);
377  if ($result < 0)
378  {
379  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
380  } else {
381  $filearray[$key]['rowid'] = $result;
382  }
383  } else {
384  $filearray[$key]['rowid'] = 0; // Should not happened
385  }
386  }
387  }
388  //var_dump($filearray); var_dump($relativedir.' - tmpfilename='.$tmpfilename.' - found='.$found);
389 }
390 
391 
399 function dol_compare_file($a, $b)
400 {
401  global $sortorder;
402  global $sortfield;
403 
404  $sortorder = strtoupper($sortorder);
405 
406  if ($sortorder == 'ASC') { $retup = -1; $retdown = 1; } else { $retup = 1; $retdown = -1; }
407 
408  if ($sortfield == 'name')
409  {
410  if ($a->name == $b->name) return 0;
411  return ($a->name < $b->name) ? $retup : $retdown;
412  }
413  if ($sortfield == 'date')
414  {
415  if ($a->date == $b->date) return 0;
416  return ($a->date < $b->date) ? $retup : $retdown;
417  }
418  if ($sortfield == 'size')
419  {
420  if ($a->size == $b->size) return 0;
421  return ($a->size < $b->size) ? $retup : $retdown;
422  }
423 }
424 
425 
432 function dol_is_dir($folder)
433 {
434  $newfolder = dol_osencode($folder);
435  if (is_dir($newfolder)) return true;
436  else return false;
437 }
438 
445 function dol_is_dir_empty($dir)
446 {
447  if (!is_readable($dir)) return false;
448  return (count(scandir($dir)) == 2);
449 }
450 
457 function dol_is_file($pathoffile)
458 {
459  $newpathoffile = dol_osencode($pathoffile);
460  return is_file($newpathoffile);
461 }
462 
469 function dol_is_link($pathoffile)
470 {
471  $newpathoffile = dol_osencode($pathoffile);
472  return is_link($newpathoffile);
473 }
474 
481 function dol_is_url($url)
482 {
483  $tmpprot = array('file', 'http', 'https', 'ftp', 'zlib', 'data', 'ssh', 'ssh2', 'ogg', 'expect');
484  foreach ($tmpprot as $prot)
485  {
486  if (preg_match('/^'.$prot.':/i', $url)) return true;
487  }
488  return false;
489 }
490 
497 function dol_dir_is_emtpy($folder)
498 {
499  $newfolder = dol_osencode($folder);
500  if (is_dir($newfolder))
501  {
502  $handle = opendir($newfolder);
503  $folder_content = '';
504  while ((gettype($name = readdir($handle)) != "boolean"))
505  {
506  $name_array[] = $name;
507  }
508  foreach ($name_array as $temp) $folder_content .= $temp;
509 
510  closedir($handle);
511 
512  if ($folder_content == "...") return true;
513  else return false;
514  } else return true; // Dir does not exists
515 }
516 
524 function dol_count_nb_of_line($file)
525 {
526  $nb = 0;
527 
528  $newfile = dol_osencode($file);
529  //print 'x'.$file;
530  $fp = fopen($newfile, 'r');
531  if ($fp)
532  {
533  while (!feof($fp))
534  {
535  $line = fgets($fp);
536  // We increase count only if read was success. We need test because feof return true only after fgets so we do n+1 fgets for a file with n lines.
537  if (!$line === false) $nb++;
538  }
539  fclose($fp);
540  } else {
541  $nb = -1;
542  }
543 
544  return $nb;
545 }
546 
547 
555 function dol_filesize($pathoffile)
556 {
557  $newpathoffile = dol_osencode($pathoffile);
558  return filesize($newpathoffile);
559 }
560 
567 function dol_filemtime($pathoffile)
568 {
569  $newpathoffile = dol_osencode($pathoffile);
570  return @filemtime($newpathoffile); // @Is to avoid errors if files does not exists
571 }
572 
585 function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask = 0, $indexdatabase = 0, $arrayreplacementisregex = 0)
586 {
587  global $conf;
588 
589  dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase." arrayreplacementisregex=".$arrayreplacementisregex);
590 
591  if (empty($srcfile)) return -1;
592  if (empty($destfile)) $destfile = $srcfile;
593 
594  $destexists = dol_is_file($destfile);
595  if (($destfile != $srcfile) && $destexists) return 0;
596 
597  $tmpdestfile = $destfile.'.tmp';
598 
599  $newpathofsrcfile = dol_osencode($srcfile);
600  $newpathoftmpdestfile = dol_osencode($tmpdestfile);
601  $newpathofdestfile = dol_osencode($destfile);
602  $newdirdestfile = dirname($newpathofdestfile);
603 
604  if ($destexists && !is_writable($newpathofdestfile))
605  {
606  dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to overwrite target file", LOG_WARNING);
607  return -1;
608  }
609  if (!is_writable($newdirdestfile))
610  {
611  dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
612  return -2;
613  }
614 
615  dol_delete_file($tmpdestfile);
616 
617  // Create $newpathoftmpdestfile from $newpathofsrcfile
618  $content = file_get_contents($newpathofsrcfile, 'r');
619 
620  if (empty($arrayreplacementisregex))
621  {
622  $content = make_substitutions($content, $arrayreplacement, null);
623  } else {
624  foreach ($arrayreplacement as $key => $value)
625  {
626  $content = preg_replace($key, $value, $content);
627  }
628  }
629 
630  file_put_contents($newpathoftmpdestfile, $content);
631  @chmod($newpathoftmpdestfile, octdec($newmask));
632 
633  // Rename
634  $result = dol_move($newpathoftmpdestfile, $newpathofdestfile, $newmask, (($destfile == $srcfile) ? 1 : 0), 0, $indexdatabase);
635  if (!$result)
636  {
637  dol_syslog("files.lib.php::dolReplaceInFile failed to move tmp file to final dest", LOG_WARNING);
638  return -3;
639  }
640  if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) $newmask = $conf->global->MAIN_UMASK;
641  if (empty($newmask)) // This should no happen
642  {
643  dol_syslog("Warning: dolReplaceInFile called with empty value for newmask and no default value defined", LOG_WARNING);
644  $newmask = '0664';
645  }
646 
647  @chmod($newpathofdestfile, octdec($newmask));
648 
649  return 1;
650 }
651 
652 
663 function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1)
664 {
665  global $conf;
666 
667  dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
668 
669  if (empty($srcfile) || empty($destfile)) return -1;
670 
671  $destexists = dol_is_file($destfile);
672  if (!$overwriteifexists && $destexists) return 0;
673 
674  $newpathofsrcfile = dol_osencode($srcfile);
675  $newpathofdestfile = dol_osencode($destfile);
676  $newdirdestfile = dirname($newpathofdestfile);
677 
678  if ($destexists && !is_writable($newpathofdestfile))
679  {
680  dol_syslog("files.lib.php::dol_copy failed Permission denied to overwrite target file", LOG_WARNING);
681  return -1;
682  }
683  if (!is_writable($newdirdestfile))
684  {
685  dol_syslog("files.lib.php::dol_copy failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
686  return -2;
687  }
688  // Copy with overwriting if exists
689  $result = @copy($newpathofsrcfile, $newpathofdestfile);
690  //$result=copy($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
691  if (!$result)
692  {
693  dol_syslog("files.lib.php::dol_copy failed to copy", LOG_WARNING);
694  return -3;
695  }
696  if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) $newmask = $conf->global->MAIN_UMASK;
697  if (empty($newmask)) // This should no happen
698  {
699  dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
700  $newmask = '0664';
701  }
702 
703  @chmod($newpathofdestfile, octdec($newmask));
704 
705  return 1;
706 }
707 
720 function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null, $excludesubdir = 0)
721 {
722  global $conf;
723 
724  $result = 0;
725 
726  dol_syslog("files.lib.php::dolCopyDir srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
727 
728  if (empty($srcfile) || empty($destfile)) return -1;
729 
730  $destexists = dol_is_dir($destfile);
731  //if (! $overwriteifexists && $destexists) return 0; // The overwriteifexists is for files only, so propagated to dol_copy only.
732 
733  if (!$destexists)
734  {
735  // We must set mask just before creating dir, becaause it can be set differently by dol_copy
736  umask(0);
737  $dirmaskdec = octdec($newmask);
738  if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) $dirmaskdec = octdec($conf->global->MAIN_UMASK);
739  $dirmaskdec |= octdec('0200'); // Set w bit required to be able to create content for recursive subdirs files
740  dol_mkdir($destfile, '', decoct($dirmaskdec));
741  }
742 
743  $ossrcfile = dol_osencode($srcfile);
744  $osdestfile = dol_osencode($destfile);
745 
746  // Recursive function to copy all subdirectories and contents:
747  if (is_dir($ossrcfile))
748  {
749  $dir_handle = opendir($ossrcfile);
750  while ($file = readdir($dir_handle))
751  {
752  if ($file != "." && $file != ".." && !is_link($ossrcfile."/".$file))
753  {
754  if (is_dir($ossrcfile."/".$file))
755  {
756  if (empty($excludesubdir) || ($excludesubdir == 2 && strlen($file) == 2)) {
757  $newfile = $file;
758  // Replace destination filename with a new one
759  if (is_array($arrayreplacement))
760  {
761  foreach ($arrayreplacement as $key => $val)
762  {
763  $newfile = str_replace($key, $val, $newfile);
764  }
765  }
766  //var_dump("xxx dolCopyDir $srcfile/$file, $destfile/$file, $newmask, $overwriteifexists");
767  $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists, $arrayreplacement, $excludesubdir);
768  }
769  } else {
770  $newfile = $file;
771  // Replace destination filename with a new one
772  if (is_array($arrayreplacement))
773  {
774  foreach ($arrayreplacement as $key => $val)
775  {
776  $newfile = str_replace($key, $val, $newfile);
777  }
778  }
779  $tmpresult = dol_copy($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists);
780  }
781  // Set result
782  if ($result > 0 && $tmpresult >= 0)
783  {
784  // Do nothing, so we don't set result to 0 if tmpresult is 0 and result was success in a previous pass
785  } else {
786  $result = $tmpresult;
787  }
788  if ($result < 0) break;
789  }
790  }
791  closedir($dir_handle);
792  } else {
793  // Source directory does not exists
794  $result = -2;
795  }
796 
797  return $result;
798 }
799 
800 
817 function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1)
818 {
819  global $user, $db, $conf;
820  $result = false;
821 
822  dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
823  $srcexists = dol_is_file($srcfile);
824  $destexists = dol_is_file($destfile);
825 
826  if (!$srcexists)
827  {
828  dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request.");
829  return false;
830  }
831 
832  if ($overwriteifexists || !$destexists)
833  {
834  $newpathofsrcfile = dol_osencode($srcfile);
835  $newpathofdestfile = dol_osencode($destfile);
836 
837  // Check virus
838  $testvirusarray = array();
839  if ($testvirus)
840  {
841  $testvirusarray = dolCheckVirus($newpathofsrcfile);
842  if (count($testvirusarray))
843  {
844  dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. we ignore the move request.", LOG_WARNING);
845  return false;
846  }
847  }
848 
849  $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
850  if (!$result)
851  {
852  if ($destexists)
853  {
854  dol_syslog("files.lib.php::dol_move Failed. We try to delete target first and move after.", LOG_WARNING);
855  // We force delete and try again. Rename function sometimes fails to replace dest file with some windows NTFS partitions.
856  dol_delete_file($destfile);
857  $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
858  } else dol_syslog("files.lib.php::dol_move Failed.", LOG_WARNING);
859  }
860 
861  // Move ok
862  if ($result && $indexdatabase)
863  {
864  // Rename entry into ecm database
865  $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile);
866  $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile);
867  if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) // If not a tmp file
868  {
869  $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore);
870  $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter);
871  //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);exit;
872 
873  dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG);
874  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
875 
876  $ecmfiletarget = new EcmFiles($db);
877  $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetorenameafter);
878  if ($resultecmtarget > 0) // An entry for target name already exists for target, we delete it, a new one will be created.
879  {
880  $ecmfiletarget->delete($user);
881  }
882 
883  $ecmfile = new EcmFiles($db);
884  $resultecm = $ecmfile->fetch(0, '', $rel_filetorenamebefore);
885  if ($resultecm > 0) // If an entry was found for src file, we use it to move entry
886  {
887  $filename = basename($rel_filetorenameafter);
888  $rel_dir = dirname($rel_filetorenameafter);
889  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
890  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
891 
892  $ecmfile->filepath = $rel_dir;
893  $ecmfile->filename = $filename;
894 
895  $resultecm = $ecmfile->update($user);
896  } elseif ($resultecm == 0) // If no entry were found for src files, create/update target file
897  {
898  $filename = basename($rel_filetorenameafter);
899  $rel_dir = dirname($rel_filetorenameafter);
900  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
901  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
902 
903  $ecmfile->filepath = $rel_dir;
904  $ecmfile->filename = $filename;
905  $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
906  $ecmfile->fullpath_orig = $srcfile;
907  $ecmfile->gen_or_uploaded = 'unknown';
908  $ecmfile->description = ''; // indexed content
909  $ecmfile->keyword = ''; // keyword content
910  $resultecm = $ecmfile->create($user);
911  if ($resultecm < 0)
912  {
913  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
914  }
915  } elseif ($resultecm < 0)
916  {
917  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
918  }
919 
920  if ($resultecm > 0) $result = true;
921  else $result = false;
922  }
923  }
924 
925  if (empty($newmask)) $newmask = empty($conf->global->MAIN_UMASK) ? '0755' : $conf->global->MAIN_UMASK;
926  $newmaskdec = octdec($newmask);
927  // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too)
928  // to allow mask usage for dir, we shoul introduce a new param "isdir" to 1 to complete newmask like this
929  // if ($isdir) $newmaskdec |= octdec('0111'); // Set x bit required for directories
930  @chmod($newpathofdestfile, $newmaskdec);
931  }
932 
933  return $result;
934 }
935 
943 function dol_unescapefile($filename)
944 {
945  // Remove path information and dots around the filename, to prevent uploading
946  // into different directories or replacing hidden system files.
947  // Also remove control characters and spaces (\x00..\x20) around the filename:
948  return trim(basename($filename), ".\x00..\x20");
949 }
950 
951 
958 function dolCheckVirus($src_file)
959 {
960  global $conf;
961 
962  if (!empty($conf->global->MAIN_ANTIVIRUS_COMMAND))
963  {
964  if (!class_exists('AntiVir')) {
965  require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
966  }
967  $antivir = new AntiVir($db);
968  $result = $antivir->dol_avscan_file($src_file);
969  if ($result < 0) // If virus or error, we stop here
970  {
971  $reterrors = $antivir->errors;
972  return $reterrors;
973  }
974  }
975  return array();
976 }
977 
978 
999 function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile', $upload_dir = '')
1000 {
1001  global $conf, $db, $user, $langs;
1002  global $object, $hookmanager;
1003 
1004  $reshook = 0;
1005  $file_name = $dest_file;
1006  $successcode = 1;
1007 
1008  if (empty($nohook))
1009  {
1010  $reshook = $hookmanager->initHooks(array('fileslib'));
1011 
1012  $parameters = array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
1013  $reshook = $hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
1014  }
1015 
1016  if (empty($reshook))
1017  {
1018  // If an upload error has been reported
1019  if ($uploaderrorcode)
1020  {
1021  switch ($uploaderrorcode)
1022  {
1023  case UPLOAD_ERR_INI_SIZE: // 1
1024  return 'ErrorFileSizeTooLarge';
1025  case UPLOAD_ERR_FORM_SIZE: // 2
1026  return 'ErrorFileSizeTooLarge';
1027  case UPLOAD_ERR_PARTIAL: // 3
1028  return 'ErrorPartialFile';
1029  case UPLOAD_ERR_NO_TMP_DIR: //
1030  return 'ErrorNoTmpDir';
1031  case UPLOAD_ERR_CANT_WRITE:
1032  return 'ErrorFailedToWriteInDir';
1033  case UPLOAD_ERR_EXTENSION:
1034  return 'ErrorUploadBlockedByAddon';
1035  default:
1036  break;
1037  }
1038  }
1039 
1040  // If we need to make a virus scan
1041  if (empty($disablevirusscan) && file_exists($src_file))
1042  {
1043  $checkvirusarray = dolCheckVirus($src_file);
1044  if (count($checkvirusarray))
1045  {
1046  dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
1047  return 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray);
1048  }
1049  }
1050 
1051  // Security:
1052  // Disallow file with some extensions. We rename them.
1053  // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
1054  if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED))
1055  {
1056  // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
1057  $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
1058  if (!preg_match('/\/$/', $publicmediasdirwithslash)) $publicmediasdirwithslash .= '/';
1059 
1060  if (strpos($upload_dir, $publicmediasdirwithslash) !== 0) { // We never add .noexe on files into media directory
1061  $file_name .= '.noexe';
1062  $successcode = 2;
1063  }
1064  }
1065 
1066  // Security:
1067  // We refuse cache files/dirs, upload using .. and pipes into filenames.
1068  if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file))
1069  {
1070  dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
1071  return -1;
1072  }
1073 
1074  // Security:
1075  // We refuse cache files/dirs, upload using .. and pipes into filenames.
1076  if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file))
1077  {
1078  dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
1079  return -2;
1080  }
1081  }
1082 
1083  if ($reshook < 0) { // At least one blocking error returned by one hook
1084  $errmsg = join(',', $hookmanager->errors);
1085  if (empty($errmsg)) $errmsg = 'ErrorReturnedBySomeHooks'; // Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
1086  return $errmsg;
1087  } elseif (empty($reshook)) {
1088  // The file functions must be in OS filesystem encoding.
1089  $src_file_osencoded = dol_osencode($src_file);
1090  $file_name_osencoded = dol_osencode($file_name);
1091 
1092  // Check if destination dir is writable
1093  if (!is_writable(dirname($file_name_osencoded)))
1094  {
1095  dol_syslog("Files.lib::dol_move_uploaded_file Dir ".dirname($file_name_osencoded)." is not writable. Return 'ErrorDirNotWritable'", LOG_WARNING);
1096  return 'ErrorDirNotWritable';
1097  }
1098 
1099  // Check if destination file already exists
1100  if (!$allowoverwrite)
1101  {
1102  if (file_exists($file_name_osencoded))
1103  {
1104  dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
1105  return 'ErrorFileAlreadyExists';
1106  }
1107  } else { // We are allowed to erase
1108  if (is_dir($file_name_osencoded)) { // If there is a directory with name of file to create
1109  dol_syslog("Files.lib::dol_move_uploaded_file A directory with name ".$file_name." already exists. Return 'ErrorDirWithFileNameAlreadyExists'", LOG_WARNING);
1110  return 'ErrorDirWithFileNameAlreadyExists';
1111  }
1112  }
1113 
1114  // Move file
1115  $return = move_uploaded_file($src_file_osencoded, $file_name_osencoded);
1116  if ($return)
1117  {
1118  if (!empty($conf->global->MAIN_UMASK)) @chmod($file_name_osencoded, octdec($conf->global->MAIN_UMASK));
1119  dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG);
1120  return $successcode; // Success
1121  } else {
1122  dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
1123  return -3; // Unknown error
1124  }
1125  }
1126 
1127  return $successcode; // Success
1128 }
1129 
1144 function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1)
1145 {
1146  global $db, $conf, $user, $langs;
1147  global $hookmanager;
1148 
1149  // Load translation files required by the page
1150  $langs->loadLangs(array('other', 'errors'));
1151 
1152  dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook);
1153 
1154  // Security:
1155  // We refuse transversal using .. and pipes into filenames.
1156  if ((!$allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file))
1157  {
1158  dol_syslog("Refused to delete file ".$file, LOG_WARNING);
1159  return false;
1160  }
1161 
1162  $reshook = 0;
1163  if (empty($nohook))
1164  {
1165  $hookmanager->initHooks(array('fileslib'));
1166 
1167  $parameters = array(
1168  'GET' => $_GET,
1169  'file' => $file,
1170  'disableglob'=> $disableglob,
1171  'nophperrors' => $nophperrors
1172  );
1173  $reshook = $hookmanager->executeHooks('deleteFile', $parameters, $object);
1174  }
1175 
1176  if (empty($nohook) && $reshook != 0) // reshook = 0 to do standard actions, 1 = ok and replace, -1 = ko
1177  {
1178  dol_syslog("reshook=".$reshook);
1179  if ($reshook < 0) return false;
1180  return true;
1181  } else {
1182  $file_osencoded = dol_osencode($file); // New filename encoded in OS filesystem encoding charset
1183  if (empty($disableglob) && !empty($file_osencoded))
1184  {
1185  $ok = true;
1186  $globencoded = str_replace('[', '\[', $file_osencoded);
1187  $globencoded = str_replace(']', '\]', $globencoded);
1188  $listofdir = glob($globencoded);
1189  if (!empty($listofdir) && is_array($listofdir))
1190  {
1191  foreach ($listofdir as $filename)
1192  {
1193  if ($nophperrors) $ok = @unlink($filename);
1194  else $ok = unlink($filename);
1195 
1196  // If it fails and it is because of the missing write permission on parent dir
1197  if (!$ok && file_exists(dirname($filename)) && !(fileperms(dirname($filename)) & 0200)) {
1198  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);
1199  @chmod(dirname($filename), fileperms(dirname($filename)) | 0200);
1200  // Now we retry deletion
1201  if ($nophperrors) $ok = @unlink($filename);
1202  else $ok = unlink($filename);
1203  }
1204 
1205  if ($ok)
1206  {
1207  dol_syslog("Removed file ".$filename, LOG_DEBUG);
1208 
1209  // Delete entry into ecm database
1210  $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename);
1211  if (!preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) // If not a tmp file
1212  {
1213  if (is_object($db) && $indexdatabase) // $db may not be defined when lib is in a context with define('NOREQUIREDB',1)
1214  {
1215  $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete);
1216  $rel_filetodelete = preg_replace('/\.noexe$/', '', $rel_filetodelete);
1217 
1218  dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG);
1219  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1220  $ecmfile = new EcmFiles($db);
1221  $result = $ecmfile->fetch(0, '', $rel_filetodelete);
1222  if ($result >= 0 && $ecmfile->id > 0)
1223  {
1224  $result = $ecmfile->delete($user);
1225  }
1226  if ($result < 0)
1227  {
1228  setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1229  }
1230  }
1231  }
1232  } else {
1233  dol_syslog("Failed to remove file ".$filename, LOG_WARNING);
1234  // TODO Failure to remove can be because file was already removed or because of permission
1235  // If error because it does not exists, we should return true, and we should return false if this is a permission problem
1236  }
1237  }
1238  } else {
1239  dol_syslog("No files to delete found", LOG_DEBUG);
1240  }
1241  } else {
1242  $ok = false;
1243  if ($nophperrors) $ok = @unlink($file_osencoded);
1244  else $ok = unlink($file_osencoded);
1245  if ($ok) dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
1246  else dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
1247  }
1248 
1249  return $ok;
1250  }
1251 }
1252 
1262 function dol_delete_dir($dir, $nophperrors = 0)
1263 {
1264  // Security:
1265  // We refuse transversal using .. and pipes into filenames.
1266  if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir))
1267  {
1268  dol_syslog("Refused to delete dir ".$dir, LOG_WARNING);
1269  return false;
1270  }
1271 
1272  $dir_osencoded = dol_osencode($dir);
1273  return ($nophperrors ? @rmdir($dir_osencoded) : rmdir($dir_osencoded));
1274 }
1275 
1286 function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0)
1287 {
1288  dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG);
1289  if (dol_is_dir($dir))
1290  {
1291  $dir_osencoded = dol_osencode($dir);
1292  if ($handle = opendir("$dir_osencoded"))
1293  {
1294  while (false !== ($item = readdir($handle)))
1295  {
1296  if (!utf8_check($item)) $item = utf8_encode($item); // should be useless
1297 
1298  if ($item != "." && $item != "..")
1299  {
1300  if (is_dir(dol_osencode("$dir/$item")) && !is_link(dol_osencode("$dir/$item")))
1301  {
1302  $count = dol_delete_dir_recursive("$dir/$item", $count, $nophperrors, 0, $countdeleted);
1303  } else {
1304  $result = dol_delete_file("$dir/$item", 1, $nophperrors);
1305  $count++;
1306  if ($result) $countdeleted++;
1307  //else print 'Error on '.$item."\n";
1308  }
1309  }
1310  }
1311  closedir($handle);
1312 
1313  if (empty($onlysub))
1314  {
1315  $result = dol_delete_dir($dir, $nophperrors);
1316  $count++;
1317  if ($result) $countdeleted++;
1318  //else print 'Error on '.$dir."\n";
1319  }
1320  }
1321  }
1322 
1323  return $count;
1324 }
1325 
1326 
1335 function dol_delete_preview($object)
1336 {
1337  global $langs, $conf;
1338 
1339  // Define parent dir of elements
1340  $element = $object->element;
1341 
1342  if ($object->element == 'order_supplier') $dir = $conf->fournisseur->commande->dir_output;
1343  elseif ($object->element == 'invoice_supplier') $dir = $conf->fournisseur->facture->dir_output;
1344  elseif ($object->element == 'project') $dir = $conf->projet->dir_output;
1345  elseif ($object->element == 'shipping') $dir = $conf->expedition->dir_output.'/sending';
1346  elseif ($object->element == 'delivery') $dir = $conf->expedition->dir_output.'/receipt';
1347  elseif ($object->element == 'fichinter') $dir = $conf->ficheinter->dir_output;
1348  else $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1349 
1350  if (empty($dir)) return 'ErrorObjectNoSupportedByFunction';
1351 
1352  $refsan = dol_sanitizeFileName($object->ref);
1353  $dir = $dir."/".$refsan;
1354  $filepreviewnew = $dir."/".$refsan.".pdf_preview.png";
1355  $filepreviewnewbis = $dir."/".$refsan.".pdf_preview-0.png";
1356  $filepreviewold = $dir."/".$refsan.".pdf.png";
1357 
1358  // For new preview files
1359  if (file_exists($filepreviewnew) && is_writable($filepreviewnew))
1360  {
1361  if (!dol_delete_file($filepreviewnew, 1))
1362  {
1363  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnew);
1364  return 0;
1365  }
1366  }
1367  if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis))
1368  {
1369  if (!dol_delete_file($filepreviewnewbis, 1))
1370  {
1371  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis);
1372  return 0;
1373  }
1374  }
1375  // For old preview files
1376  if (file_exists($filepreviewold) && is_writable($filepreviewold))
1377  {
1378  if (!dol_delete_file($filepreviewold, 1))
1379  {
1380  $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewold);
1381  return 0;
1382  }
1383  } else {
1384  $multiple = $filepreviewold.".";
1385  for ($i = 0; $i < 20; $i++)
1386  {
1387  $preview = $multiple.$i;
1388 
1389  if (file_exists($preview) && is_writable($preview))
1390  {
1391  if (!dol_delete_file($preview, 1))
1392  {
1393  $object->error = $langs->trans("ErrorFailedToOpenFile", $preview);
1394  return 0;
1395  }
1396  }
1397  }
1398  }
1399 
1400  return 1;
1401 }
1402 
1411 function dol_meta_create($object)
1412 {
1413  global $conf;
1414 
1415  // Create meta file
1416  if (empty($conf->global->MAIN_DOC_CREATE_METAFILE)) return 0; // By default, no metafile.
1417 
1418  // Define parent dir of elements
1419  $element = $object->element;
1420 
1421  if ($object->element == 'order_supplier') $dir = $conf->fournisseur->dir_output.'/commande';
1422  elseif ($object->element == 'invoice_supplier') $dir = $conf->fournisseur->dir_output.'/facture';
1423  elseif ($object->element == 'project') $dir = $conf->projet->dir_output;
1424  elseif ($object->element == 'shipping') $dir = $conf->expedition->dir_output.'/sending';
1425  elseif ($object->element == 'delivery') $dir = $conf->expedition->dir_output.'/receipt';
1426  elseif ($object->element == 'fichinter') $dir = $conf->ficheinter->dir_output;
1427  else $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1428 
1429  if ($dir)
1430  {
1431  $object->fetch_thirdparty();
1432 
1433  $objectref = dol_sanitizeFileName($object->ref);
1434  $dir = $dir."/".$objectref;
1435  $file = $dir."/".$objectref.".meta";
1436 
1437  if (!is_dir($dir))
1438  {
1439  dol_mkdir($dir);
1440  }
1441 
1442  if (is_dir($dir))
1443  {
1444  $nblines = count($object->lines);
1445  $client = $object->thirdparty->name." ".$object->thirdparty->address." ".$object->thirdparty->zip." ".$object->thirdparty->town;
1446  $meta = "REFERENCE=\"".$object->ref."\"
1447  DATE=\"" . dol_print_date($object->date, '')."\"
1448  NB_ITEMS=\"" . $nblines."\"
1449  CLIENT=\"" . $client."\"
1450  AMOUNT_EXCL_TAX=\"" . $object->total_ht."\"
1451  AMOUNT=\"" . $object->total_ttc."\"\n";
1452 
1453  for ($i = 0; $i < $nblines; $i++)
1454  {
1455  //Pour les articles
1456  $meta .= "ITEM_".$i."_QUANTITY=\"".$object->lines[$i]->qty."\"
1457  ITEM_" . $i."_AMOUNT_WO_TAX=\"".$object->lines[$i]->total_ht."\"
1458  ITEM_" . $i."_VAT=\"".$object->lines[$i]->tva_tx."\"
1459  ITEM_" . $i."_DESCRIPTION=\"".str_replace("\r\n", "", nl2br($object->lines[$i]->desc))."\"
1460  ";
1461  }
1462  }
1463 
1464  $fp = fopen($file, "w");
1465  fputs($fp, $meta);
1466  fclose($fp);
1467  if (!empty($conf->global->MAIN_UMASK))
1468  @chmod($file, octdec($conf->global->MAIN_UMASK));
1469 
1470  return 1;
1471  } else {
1472  dol_syslog('FailedToDetectDirInDolMetaCreateFor'.$object->element, LOG_WARNING);
1473  }
1474 
1475  return 0;
1476 }
1477 
1478 
1479 
1488 function dol_init_file_process($pathtoscan = '', $trackid = '')
1489 {
1490  $listofpaths = array();
1491  $listofnames = array();
1492  $listofmimes = array();
1493 
1494  if ($pathtoscan)
1495  {
1496  $listoffiles = dol_dir_list($pathtoscan, 'files');
1497  foreach ($listoffiles as $key => $val)
1498  {
1499  $listofpaths[] = $val['fullname'];
1500  $listofnames[] = $val['name'];
1501  $listofmimes[] = dol_mimetype($val['name']);
1502  }
1503  }
1504  $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1505  $_SESSION["listofpaths".$keytoavoidconflict] = join(';', $listofpaths);
1506  $_SESSION["listofnames".$keytoavoidconflict] = join(';', $listofnames);
1507  $_SESSION["listofmimes".$keytoavoidconflict] = join(';', $listofmimes);
1508 }
1509 
1510 
1528 function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null)
1529 {
1530  global $db, $user, $conf, $langs;
1531 
1532  $res = 0;
1533 
1534  if (!empty($_FILES[$varfiles])) // For view $_FILES[$varfiles]['error']
1535  {
1536  dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG);
1537 
1538  if (dol_mkdir($upload_dir) >= 0)
1539  {
1540  $TFile = $_FILES[$varfiles];
1541  if (!is_array($TFile['name']))
1542  {
1543  foreach ($TFile as $key => &$val)
1544  {
1545  $val = array($val);
1546  }
1547  }
1548 
1549  $nbfile = count($TFile['name']);
1550  $nbok = 0;
1551  for ($i = 0; $i < $nbfile; $i++)
1552  {
1553  if (empty($TFile['name'][$i])) continue; // For example, when submitting a form with no file name
1554 
1555  // Define $destfull (path to file including filename) and $destfile (only filename)
1556  $destfull = $upload_dir."/".$TFile['name'][$i];
1557  $destfile = $TFile['name'][$i];
1558  $destfilewithoutext = preg_replace('/\.[^\.]+$/', '', $destfile);
1559 
1560  if ($savingdocmask && strpos($savingdocmask, $destfilewithoutext) !== 0)
1561  {
1562  $destfull = $upload_dir."/".preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask);
1563  $destfile = preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask);
1564  }
1565 
1566  $filenameto = basename($destfile);
1567  if (preg_match('/^\./', $filenameto)) {
1568  $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1569  setEventMessages($langs->trans("ErrorFilenameCantStartWithDot", $filenameto), null, 'errors');
1570  break;
1571  }
1572 
1573  // dol_sanitizeFileName the file name and lowercase extension
1574  $info = pathinfo($destfull);
1575  $destfull = $info['dirname'].'/'.dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1576  $info = pathinfo($destfile);
1577 
1578  $destfile = dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1579 
1580  // We apply dol_string_nohtmltag also to clean file names (this remove duplicate spaces) because
1581  // this function is also applied when we rename and when we make try to download file (by the GETPOST(filename, 'alphanohtml') call).
1582  $destfile = dol_string_nohtmltag($destfile);
1583  $destfull = dol_string_nohtmltag($destfull);
1584 
1585  // Move file from temp directory to final directory. A .noexe may also be appended on file name.
1586  $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir);
1587 
1588  if (is_numeric($resupload) && $resupload > 0) // $resupload can be 'ErrorFileAlreadyExists'
1589  {
1590  global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini;
1591 
1592  include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
1593 
1594  // Generate thumbs.
1595  if ($generatethumbs)
1596  {
1597  if (image_format_supported($destfull) == 1)
1598  {
1599  // Create thumbs
1600  // We can't use $object->addThumbs here because there is no $object known
1601 
1602  // Used on logon for example
1603  $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
1604  // Create mini thumbs for image (Ratio is near 16/9)
1605  // Used on menu or for setup page for example
1606  $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
1607  }
1608  }
1609 
1610  // Update session
1611  if (empty($donotupdatesession))
1612  {
1613  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1614  $formmail = new FormMail($db);
1615  $formmail->trackid = $trackid;
1616  $formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
1617  }
1618 
1619  // Update index table of files (llx_ecm_files)
1620  if ($donotupdatesession == 1)
1621  {
1622  $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', 0, $object);
1623  if ($result < 0)
1624  {
1625  if ($allowoverwrite) {
1626  // Do not show error message. We can have an error due to DB_ERROR_RECORD_ALREADY_EXISTS
1627  } else {
1628  setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', '', 'warnings');
1629  }
1630  }
1631  }
1632 
1633  $nbok++;
1634  } else {
1635  $langs->load("errors");
1636  if ($resupload < 0) // Unknown error
1637  {
1638  setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
1639  } elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) // Files infected by a virus
1640  {
1641  setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors');
1642  } else // Known error
1643  {
1644  setEventMessages($langs->trans($resupload), null, 'errors');
1645  }
1646  }
1647  }
1648  if ($nbok > 0)
1649  {
1650  $res = 1;
1651  setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs');
1652  }
1653  }
1654  } elseif ($link) {
1655  require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
1656  $linkObject = new Link($db);
1657  $linkObject->entity = $conf->entity;
1658  $linkObject->url = $link;
1659  $linkObject->objecttype = GETPOST('objecttype', 'alpha');
1660  $linkObject->objectid = GETPOST('objectid', 'int');
1661  $linkObject->label = GETPOST('label', 'alpha');
1662  $res = $linkObject->create($user);
1663  $langs->load('link');
1664  if ($res > 0) {
1665  setEventMessages($langs->trans("LinkComplete"), null, 'mesgs');
1666  } else {
1667  setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors');
1668  }
1669  } else {
1670  $langs->load("errors");
1671  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
1672  }
1673 
1674  return $res;
1675 }
1676 
1677 
1689 function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '')
1690 {
1691  global $db, $user, $conf, $langs, $_FILES;
1692 
1693  $keytodelete = $filenb;
1694  $keytodelete--;
1695 
1696  $listofpaths = array();
1697  $listofnames = array();
1698  $listofmimes = array();
1699  $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1700  if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
1701  if (!empty($_SESSION["listofnames".$keytoavoidconflict])) $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
1702  if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
1703 
1704  if ($keytodelete >= 0)
1705  {
1706  $pathtodelete = $listofpaths[$keytodelete];
1707  $filetodelete = $listofnames[$keytodelete];
1708  if (empty($donotdeletefile)) $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file
1709  else $result = 0;
1710  if ($result >= 0)
1711  {
1712  if (empty($donotdeletefile))
1713  {
1714  $langs->load("other");
1715  setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs');
1716  }
1717  if (empty($donotupdatesession))
1718  {
1719  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1720  $formmail = new FormMail($db);
1721  $formmail->trackid = $trackid;
1722  $formmail->remove_attached_files($keytodelete);
1723  }
1724  }
1725  }
1726 }
1727 
1728 
1742 function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null)
1743 {
1744  global $db, $user;
1745 
1746  $result = 0;
1747 
1748  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
1749 
1750  if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) // If not a tmp dir
1751  {
1752  $filename = basename(preg_replace('/\.noexe$/', '', $file));
1753  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1754  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1755 
1756  include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1757  $ecmfile = new EcmFiles($db);
1758  $ecmfile->filepath = $rel_dir;
1759  $ecmfile->filename = $filename;
1760  $ecmfile->label = md5_file(dol_osencode($dir.'/'.$file)); // MD5 of file content
1761  $ecmfile->fullpath_orig = $fullpathorig;
1762  $ecmfile->gen_or_uploaded = $mode;
1763  $ecmfile->description = ''; // indexed content
1764  $ecmfile->keyword = ''; // keyword content
1765 
1766  if (is_object($object) && $object->id > 0) {
1767  $ecmfile->src_object_id = $object->id;
1768  $ecmfile->src_object_type = $object->table_element;
1769  }
1770 
1771  if ($setsharekey)
1772  {
1773  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1774  $ecmfile->share = getRandomPassword(true);
1775  }
1776 
1777  $result = $ecmfile->create($user);
1778  if ($result < 0)
1779  {
1780  dol_syslog($ecmfile->error);
1781  }
1782  }
1783 
1784  return $result;
1785 }
1786 
1795 function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded')
1796 {
1797  global $conf, $db, $user;
1798 
1799  $error = 0;
1800 
1801  if (empty($dir))
1802  {
1803  dol_syslog("deleteFilesIntoDatabaseIndex: dir parameter can't be empty", LOG_ERR);
1804  return -1;
1805  }
1806 
1807  $db->begin();
1808 
1809  $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
1810 
1811  $filename = basename($file);
1812  $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1813  $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1814 
1815  if (!$error)
1816  {
1817  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'ecm_files';
1818  $sql .= ' WHERE entity = '.$conf->entity;
1819  $sql .= " AND filepath = '".$db->escape($rel_dir)."'";
1820  if ($file) $sql .= " AND filename = '".$db->escape($file)."'";
1821  if ($mode) $sql .= " AND gen_or_uploaded = '".$db->escape($mode)."'";
1822 
1823  $resql = $db->query($sql);
1824  if (!$resql)
1825  {
1826  $error++;
1827  dol_syslog(__METHOD__.' '.$db->lasterror(), LOG_ERR);
1828  }
1829  }
1830 
1831  // Commit or rollback
1832  if ($error) {
1833  $db->rollback();
1834  return -1 * $error;
1835  } else {
1836  $db->commit();
1837  return 1;
1838  }
1839 }
1840 
1841 
1852 function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '')
1853 {
1854  global $langs;
1855  if (class_exists('Imagick'))
1856  {
1857  $image = new Imagick();
1858  try {
1859  $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : '');
1860  //var_dump($filetoconvert);
1861  $ret = $image->readImage($filetoconvert);
1862  } catch (Exception $e) {
1863  $ext = pathinfo($fileinput, PATHINFO_EXTENSION);
1864  dol_syslog("Failed to read image using Imagick (Try to install package 'apt-get install php-imagick ghostscript' and check there is no policy to disable ".$ext." convertion in /etc/ImageMagick*/policy.xml): ".$e->getMessage(), LOG_WARNING);
1865  return 0;
1866  }
1867  if ($ret)
1868  {
1869  $ret = $image->setImageFormat($ext);
1870  if ($ret)
1871  {
1872  if (empty($fileoutput)) $fileoutput = $fileinput.".".$ext;
1873 
1874  $count = $image->getNumberImages();
1875 
1876  if (!dol_is_file($fileoutput) || is_writeable($fileoutput))
1877  {
1878  try {
1879  $ret = $image->writeImages($fileoutput, true);
1880  } catch (Exception $e)
1881  {
1882  dol_syslog($e->getMessage(), LOG_WARNING);
1883  }
1884  } else {
1885  dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR);
1886  }
1887  if ($ret) return $count;
1888  else return -3;
1889  } else {
1890  return -2;
1891  }
1892  } else {
1893  return -1;
1894  }
1895  } else {
1896  return 0;
1897  }
1898 }
1899 
1900 
1911 function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring = null)
1912 {
1913  global $conf;
1914 
1915  $foundhandler = 0;
1916 
1917  try {
1918  dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile);
1919 
1920  $data = implode("", file(dol_osencode($inputfile)));
1921  if ($mode == 'gz') { $foundhandler = 1; $compressdata = gzencode($data, 9); } elseif ($mode == 'bz') { $foundhandler = 1; $compressdata = bzcompress($data, 9); } elseif ($mode == 'zip')
1922  {
1923  if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS))
1924  {
1925  $foundhandler = 1;
1926 
1927  $rootPath = realpath($inputfile);
1928 
1929  dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath);
1930  $zip = new ZipArchive;
1931 
1932  if ($zip->open($outputfile, ZipArchive::CREATE) !== true) {
1933  $errorstring = "dol_compress_file failure - Failed to open file ".$outputfile."\n";
1934  dol_syslog($errorstring, LOG_ERR);
1935 
1936  global $errormsg;
1937  $errormsg = $errorstring;
1938 
1939  return -6;
1940  }
1941 
1942  // Create recursive directory iterator
1944  $files = new RecursiveIteratorIterator(
1945  new RecursiveDirectoryIterator($rootPath),
1946  RecursiveIteratorIterator::LEAVES_ONLY
1947  );
1948 
1949  foreach ($files as $name => $file)
1950  {
1951  // Skip directories (they would be added automatically)
1952  if (!$file->isDir())
1953  {
1954  // Get real and relative path for current file
1955  $filePath = $file->getRealPath();
1956  $relativePath = substr($filePath, strlen($rootPath) + 1);
1957 
1958  // Add current file to archive
1959  $zip->addFile($filePath, $relativePath);
1960  }
1961  }
1962 
1963  // Zip archive will be created only after closing object
1964  $zip->close();
1965 
1966  dol_syslog("dol_compress_file success - ".count($zip->numFiles)." files");
1967  return 1;
1968  }
1969 
1970  if (defined('ODTPHP_PATHTOPCLZIP'))
1971  {
1972  $foundhandler = 1;
1973 
1974  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
1975  $archive = new PclZip($outputfile);
1976  $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
1977 
1978  if ($result === 0)
1979  {
1980  global $errormsg;
1981  $errormsg = $archive->errorInfo(true);
1982 
1983  if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL)
1984  {
1985  $errorstring = "PCLZIP_ERR_WRITE_OPEN_FAIL";
1986  dol_syslog("dol_compress_file error - archive->errorCode() = PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR);
1987  return -4;
1988  }
1989 
1990  $errorstring = "dol_compress_file error archive->errorCode = ".$archive->errorCode()." errormsg=".$errormsg;
1991  dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR);
1992  return -3;
1993  } else {
1994  dol_syslog("dol_compress_file success - ".count($result)." files");
1995  return 1;
1996  }
1997  }
1998  }
1999 
2000  if ($foundhandler)
2001  {
2002  $fp = fopen($outputfile, "w");
2003  fwrite($fp, $compressdata);
2004  fclose($fp);
2005  return 1;
2006  } else {
2007  $errorstring = "Try to zip with format ".$mode." with no handler for this format";
2008  dol_syslog($errorstring, LOG_ERR);
2009 
2010  global $errormsg;
2011  $errormsg = $errorstring;
2012  return -2;
2013  }
2014  } catch (Exception $e)
2015  {
2016  global $langs, $errormsg;
2017  $langs->load("errors");
2018  $errormsg = $langs->trans("ErrorFailedToWriteInDir");
2019 
2020  $errorstring = "Failed to open file ".$outputfile;
2021  dol_syslog($errorstring, LOG_ERR);
2022  return -1;
2023  }
2024 }
2025 
2033 function dol_uncompress($inputfile, $outputdir)
2034 {
2035  global $conf, $langs;
2036 
2037  if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS))
2038  {
2039  dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
2040  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2041  $archive = new PclZip($inputfile);
2042 
2043  // Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
2044  $result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
2045 
2046  if (!is_array($result) && $result <= 0) return array('error'=>$archive->errorInfo(true));
2047  else {
2048  $ok = 1; $errmsg = '';
2049  // Loop on each file to check result for unzipping file
2050  foreach ($result as $key => $val)
2051  {
2052  if ($val['status'] == 'path_creation_fail')
2053  {
2054  $langs->load("errors");
2055  $ok = 0;
2056  $errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
2057  break;
2058  }
2059  }
2060 
2061  if ($ok) return array();
2062  else return array('error'=>$errmsg);
2063  }
2064  }
2065 
2066  if (class_exists('ZipArchive')) // Must install php-zip to have it
2067  {
2068  dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
2069  $zip = new ZipArchive;
2070  $res = $zip->open($inputfile);
2071  if ($res === true)
2072  {
2073  //$zip->extractTo($outputdir.'/');
2074  // We must extract one file at time so we can check that file name does not contains '..' to avoid transversal path of zip built for example using
2075  // python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
2076  // with -l is the range of dot to go back in path.
2077  // and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
2078  for ($i = 0; $i < $zip->numFiles; $i++) {
2079  if (preg_match('/\.\./', $zip->getNameIndex($i))) {
2080  dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
2081  continue; // Discard the file
2082  }
2083  $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
2084  }
2085 
2086  $zip->close();
2087  return array();
2088  } else {
2089  return array('error'=>'ErrUnzipFails');
2090  }
2091  }
2092 
2093  return array('error'=>'ErrNoZipEngine');
2094 }
2095 
2096 
2107 function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '', $rootdirinzip = '')
2108 {
2109  $foundhandler = 0;
2110 
2111  dol_syslog("Try to zip dir ".$inputdir." into ".$outputfile." mode=".$mode);
2112 
2113  if (!dol_is_dir(dirname($outputfile)) || !is_writable(dirname($outputfile)))
2114  {
2115  global $langs, $errormsg;
2116  $langs->load("errors");
2117  $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile);
2118  return -3;
2119  }
2120 
2121  try {
2122  if ($mode == 'gz') { $foundhandler = 0; } elseif ($mode == 'bz') { $foundhandler = 0; } elseif ($mode == 'zip')
2123  {
2124  /*if (defined('ODTPHP_PATHTOPCLZIP'))
2125  {
2126  $foundhandler=0; // TODO implement this
2127 
2128  include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2129  $archive = new PclZip($outputfile);
2130  $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2131  //$archive->add($inputfile);
2132  return 1;
2133  }
2134  else*/
2135  //if (class_exists('ZipArchive') && ! empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS))
2136  if (class_exists('ZipArchive'))
2137  {
2138  $foundhandler = 1;
2139 
2140  // Initialize archive object
2141  $zip = new ZipArchive();
2142  $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
2143  if (!$result)
2144  {
2145  global $langs, $errormsg;
2146  $langs->load("errors");
2147  $errormsg = $langs->trans("ErrorFailedToWriteInFile", $outputfile);
2148  return -4;
2149  }
2150 
2151  // Create recursive directory iterator
2153  $files = new RecursiveIteratorIterator(
2154  new RecursiveDirectoryIterator($inputdir),
2155  RecursiveIteratorIterator::LEAVES_ONLY
2156  );
2157 
2158  foreach ($files as $name => $file)
2159  {
2160  // Skip directories (they would be added automatically)
2161  if (!$file->isDir())
2162  {
2163  // Get real and relative path for current file
2164  $filePath = $file->getRealPath();
2165  $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($filePath, strlen($inputdir) + 1);
2166 
2167  if (empty($excludefiles) || !preg_match($excludefiles, $filePath))
2168  {
2169  // Add current file to archive
2170  $zip->addFile($filePath, $relativePath);
2171  }
2172  }
2173  }
2174 
2175  // Zip archive will be created only after closing object
2176  $zip->close();
2177 
2178  return 1;
2179  }
2180  }
2181 
2182  if (!$foundhandler)
2183  {
2184  dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR);
2185  return -2;
2186  } else {
2187  return 0;
2188  }
2189  } catch (Exception $e)
2190  {
2191  global $langs, $errormsg;
2192  $langs->load("errors");
2193  dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
2194  dol_syslog($e->getMessage(), LOG_ERR);
2195  $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile);
2196  return -1;
2197  }
2198 }
2199 
2200 
2201 
2212 function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$', '^\.'), $nohook = false, $mode = '')
2213 {
2214  $tmparray = dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook);
2215  return $tmparray[0];
2216 }
2217 
2230 function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = '', $refname = '', $mode = 'read')
2231 {
2232  global $conf, $db, $user;
2233  global $dolibarr_main_data_root, $dolibarr_main_document_root_alt;
2234 
2235  if (!is_object($fuser)) $fuser = $user;
2236 
2237  if (empty($modulepart)) return 'ErrorBadParameter';
2238  if (empty($entity))
2239  {
2240  if (empty($conf->multicompany->enabled)) $entity = 1;
2241  else $entity = 0;
2242  }
2243  // Fix modulepart
2244  if ($modulepart == 'users') $modulepart = 'user';
2245 
2246  dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
2247 
2248  // We define $accessallowed and $sqlprotectagainstexternals
2249  $accessallowed = 0;
2250  $sqlprotectagainstexternals = '';
2251  $ret = array();
2252 
2253  // Find the subdirectory name as the reference. For exemple original_file='10/myfile.pdf' -> refname='10'
2254  if (empty($refname)) $refname = basename(dirname($original_file)."/");
2255 
2256  // Define possible keys to use for permission check
2257  $lire = 'lire'; $read = 'read'; $download = 'download';
2258  if ($mode == 'write')
2259  {
2260  $lire = 'creer'; $read = 'write'; $download = 'upload';
2261  }
2262 
2263  // Wrapping for miscellaneous medias files
2264  if ($modulepart == 'medias' && !empty($dolibarr_main_data_root))
2265  {
2266  if (empty($entity) || empty($conf->medias->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2267  $accessallowed = 1;
2268  $original_file = $conf->medias->multidir_output[$entity].'/'.$original_file;
2269  } // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
2270  elseif ($modulepart == 'logs' && !empty($dolibarr_main_data_root))
2271  {
2272  $accessallowed = ($user->admin && basename($original_file) == $original_file && preg_match('/^dolibarr.*\.log$/', basename($original_file)));
2273  $original_file = $dolibarr_main_data_root.'/'.$original_file;
2274  } // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
2275  elseif ($modulepart == 'doctemplates' && !empty($dolibarr_main_data_root))
2276  {
2277  $accessallowed = $user->admin;
2278  $original_file = $dolibarr_main_data_root.'/doctemplates/'.$original_file;
2279  } // Wrapping for *.zip files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
2280  elseif ($modulepart == 'doctemplateswebsite' && !empty($dolibarr_main_data_root))
2281  {
2282  $accessallowed = ($fuser->rights->website->write && preg_match('/\.jpg$/i', basename($original_file)));
2283  $original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file;
2284  } // Wrapping for *.zip files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
2285  elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root))
2286  {
2287  // Dir for custom dirs
2288  $tmp = explode(',', $dolibarr_main_document_root_alt);
2289  $dirins = $tmp[0];
2290 
2291  $accessallowed = ($user->admin && preg_match('/^module_.*\.zip$/', basename($original_file)));
2292  $original_file = $dirins.'/'.$original_file;
2293  } // Wrapping for some images
2294  elseif ($modulepart == 'mycompany' && !empty($conf->mycompany->dir_output))
2295  {
2296  $accessallowed = 1;
2297  $original_file = $conf->mycompany->dir_output.'/'.$original_file;
2298  } // Wrapping for users photos
2299  elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output))
2300  {
2301  $accessallowed = 1;
2302  $original_file = $conf->user->dir_output.'/'.$original_file;
2303  } // Wrapping for members photos
2304  elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output))
2305  {
2306  $accessallowed = 1;
2307  $original_file = $conf->adherent->dir_output.'/'.$original_file;
2308  } // Wrapping pour les apercu factures
2309  elseif ($modulepart == 'apercufacture' && !empty($conf->facture->multidir_output[$entity]))
2310  {
2311  if ($fuser->rights->facture->{$lire}) $accessallowed = 1;
2312  $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2313  } // Wrapping pour les apercu propal
2314  elseif ($modulepart == 'apercupropal' && !empty($conf->propal->multidir_output[$entity]))
2315  {
2316  if ($fuser->rights->propale->{$lire}) $accessallowed = 1;
2317  $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
2318  } // Wrapping pour les apercu commande
2319  elseif ($modulepart == 'apercucommande' && !empty($conf->commande->multidir_output[$entity]))
2320  {
2321  if ($fuser->rights->commande->{$lire}) $accessallowed = 1;
2322  $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
2323  } // Wrapping pour les apercu intervention
2324  elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output))
2325  {
2326  if ($fuser->rights->ficheinter->{$lire}) $accessallowed = 1;
2327  $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2328  } // Wrapping pour les apercu conat
2329  elseif (($modulepart == 'apercucontract') && !empty($conf->contrat->multidir_output[$entity]))
2330  {
2331  if ($fuser->rights->contrat->{$lire}) $accessallowed = 1;
2332  $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
2333  } // Wrapping pour les apercu supplier proposal
2334  elseif (($modulepart == 'apercusupplier_proposal' || $modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output))
2335  {
2336  if ($fuser->rights->supplier_proposal->{$lire}) $accessallowed = 1;
2337  $original_file = $conf->supplier_proposal->dir_output.'/'.$original_file;
2338  } // Wrapping pour les apercu supplier order
2339  elseif (($modulepart == 'apercusupplier_order' || $modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output))
2340  {
2341  if ($fuser->rights->fournisseur->commande->{$lire}) $accessallowed = 1;
2342  $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
2343  } // Wrapping pour les apercu supplier invoice
2344  elseif (($modulepart == 'apercusupplier_invoice' || $modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output))
2345  {
2346  if ($fuser->rights->fournisseur->facture->{$lire}) $accessallowed = 1;
2347  $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
2348  } // Wrapping pour les apercu supplier invoice
2349  elseif (($modulepart == 'apercuexpensereport') && !empty($conf->expensereport->dir_output))
2350  {
2351  if ($fuser->rights->expensereport->{$lire}) $accessallowed = 1;
2352  $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2353  } // Wrapping pour les images des stats propales
2354  elseif ($modulepart == 'propalstats' && !empty($conf->propal->multidir_temp[$entity]))
2355  {
2356  if ($fuser->rights->propale->{$lire}) $accessallowed = 1;
2357  $original_file = $conf->propal->multidir_temp[$entity].'/'.$original_file;
2358  } // Wrapping pour les images des stats commandes
2359  elseif ($modulepart == 'orderstats' && !empty($conf->commande->dir_temp))
2360  {
2361  if ($fuser->rights->commande->{$lire}) $accessallowed = 1;
2362  $original_file = $conf->commande->dir_temp.'/'.$original_file;
2363  } elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output))
2364  {
2365  if ($fuser->rights->fournisseur->commande->{$lire}) $accessallowed = 1;
2366  $original_file = $conf->fournisseur->commande->dir_temp.'/'.$original_file;
2367  } // Wrapping pour les images des stats factures
2368  elseif ($modulepart == 'billstats' && !empty($conf->facture->dir_temp))
2369  {
2370  if ($fuser->rights->facture->{$lire}) $accessallowed = 1;
2371  $original_file = $conf->facture->dir_temp.'/'.$original_file;
2372  } elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output))
2373  {
2374  if ($fuser->rights->fournisseur->facture->{$lire}) $accessallowed = 1;
2375  $original_file = $conf->fournisseur->facture->dir_temp.'/'.$original_file;
2376  } // Wrapping pour les images des stats expeditions
2377  elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp))
2378  {
2379  if ($fuser->rights->expedition->{$lire}) $accessallowed = 1;
2380  $original_file = $conf->expedition->dir_temp.'/'.$original_file;
2381  } // Wrapping pour les images des stats expeditions
2382  elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp))
2383  {
2384  if ($fuser->rights->deplacement->{$lire}) $accessallowed = 1;
2385  $original_file = $conf->deplacement->dir_temp.'/'.$original_file;
2386  } // Wrapping pour les images des stats expeditions
2387  elseif ($modulepart == 'memberstats' && !empty($conf->adherent->dir_temp))
2388  {
2389  if ($fuser->rights->adherent->{$lire}) $accessallowed = 1;
2390  $original_file = $conf->adherent->dir_temp.'/'.$original_file;
2391  } // Wrapping pour les images des stats produits
2392  elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp))
2393  {
2394  if ($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) $accessallowed = 1;
2395  $original_file = (!empty($conf->product->multidir_temp[$entity]) ? $conf->product->multidir_temp[$entity] : $conf->service->multidir_temp[$entity]).'/'.$original_file;
2396  } // Wrapping for taxes
2397  elseif (in_array($modulepart, array('tax', 'tax-vat')) && !empty($conf->tax->dir_output))
2398  {
2399  if ($fuser->rights->tax->charges->{$lire}) $accessallowed = 1;
2400  $modulepartsuffix = str_replace('tax-', '', $modulepart);
2401  $original_file = $conf->tax->dir_output.'/'.($modulepartsuffix != 'tax' ? $modulepartsuffix.'/' : '').$original_file;
2402  } // Wrapping for events
2403  elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output))
2404  {
2405  if ($fuser->rights->agenda->myactions->{$read}) $accessallowed = 1;
2406  $original_file = $conf->agenda->dir_output.'/'.$original_file;
2407  } // Wrapping for categories
2408  elseif ($modulepart == 'category' && !empty($conf->categorie->multidir_output[$entity]))
2409  {
2410  if (empty($entity) || empty($conf->categorie->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2411  if ($fuser->rights->categorie->{$lire}) $accessallowed = 1;
2412  $original_file = $conf->categorie->multidir_output[$entity].'/'.$original_file;
2413  } // Wrapping pour les prelevements
2414  elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output))
2415  {
2416  if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i', $original_file)) $accessallowed = 1;
2417  $original_file = $conf->prelevement->dir_output.'/'.$original_file;
2418  } // Wrapping pour les graph energie
2419  elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp))
2420  {
2421  $accessallowed = 1;
2422  $original_file = $conf->stock->dir_temp.'/'.$original_file;
2423  } // Wrapping pour les graph fournisseurs
2424  elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp))
2425  {
2426  $accessallowed = 1;
2427  $original_file = $conf->fournisseur->dir_temp.'/'.$original_file;
2428  } // Wrapping pour les graph des produits
2429  elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp))
2430  {
2431  $accessallowed = 1;
2432  $original_file = $conf->product->multidir_temp[$entity].'/'.$original_file;
2433  } // Wrapping pour les code barre
2434  elseif ($modulepart == 'barcode')
2435  {
2436  $accessallowed = 1;
2437  // If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
2438  //$original_file=$conf->barcode->dir_temp.'/'.$original_file;
2439  $original_file = '';
2440  } // Wrapping pour les icones de background des mailings
2441  elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp))
2442  {
2443  $accessallowed = 1;
2444  $original_file = $conf->mailing->dir_temp.'/'.$original_file;
2445  } // Wrapping pour le scanner
2446  elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp))
2447  {
2448  $accessallowed = 1;
2449  $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
2450  } // Wrapping pour les images fckeditor
2451  elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output))
2452  {
2453  $accessallowed = 1;
2454  $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
2455  } // Wrapping for users
2456  elseif ($modulepart == 'user' && !empty($conf->user->dir_output))
2457  {
2458  $canreaduser = (!empty($fuser->admin) || $fuser->rights->user->user->{$lire});
2459  if ($fuser->id == (int) $refname) { $canreaduser = 1; } // A user can always read its own card
2460  if ($canreaduser || preg_match('/^specimen/i', $original_file))
2461  {
2462  $accessallowed = 1;
2463  }
2464  $original_file = $conf->user->dir_output.'/'.$original_file;
2465  } // Wrapping for third parties
2466  elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->multidir_output[$entity]))
2467  {
2468  if (empty($entity) || empty($conf->societe->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2469  if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i', $original_file))
2470  {
2471  $accessallowed = 1;
2472  }
2473  $original_file = $conf->societe->multidir_output[$entity].'/'.$original_file;
2474  $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe').")";
2475  } // Wrapping for contact
2476  elseif ($modulepart == 'contact' && !empty($conf->societe->multidir_output[$entity]))
2477  {
2478  if (empty($entity) || empty($conf->societe->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2479  if ($fuser->rights->societe->{$lire})
2480  {
2481  $accessallowed = 1;
2482  }
2483  $original_file = $conf->societe->multidir_output[$entity].'/contact/'.$original_file;
2484  } // Wrapping for invoices
2485  elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->multidir_output[$entity]))
2486  {
2487  if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file))
2488  {
2489  $accessallowed = 1;
2490  }
2491  $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2492  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('invoice').")";
2493  } // Wrapping for mass actions
2494  elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity]))
2495  {
2496  if ($fuser->rights->propal->{$lire} || preg_match('/^specimen/i', $original_file))
2497  {
2498  $accessallowed = 1;
2499  }
2500  $original_file = $conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2501  } elseif ($modulepart == 'massfilesarea_orders')
2502  {
2503  if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file))
2504  {
2505  $accessallowed = 1;
2506  }
2507  $original_file = $conf->commande->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2508  } elseif ($modulepart == 'massfilesarea_sendings')
2509  {
2510  if ($fuser->rights->expedition->{$lire} || preg_match('/^specimen/i', $original_file))
2511  {
2512  $accessallowed = 1;
2513  }
2514  $original_file = $conf->expedition->dir_output.'/sending/temp/massgeneration/'.$user->id.'/'.$original_file;
2515  } elseif ($modulepart == 'massfilesarea_invoices')
2516  {
2517  if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file))
2518  {
2519  $accessallowed = 1;
2520  }
2521  $original_file = $conf->facture->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2522  } elseif ($modulepart == 'massfilesarea_expensereport')
2523  {
2524  if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file))
2525  {
2526  $accessallowed = 1;
2527  }
2528  $original_file = $conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2529  } elseif ($modulepart == 'massfilesarea_interventions')
2530  {
2531  if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i', $original_file))
2532  {
2533  $accessallowed = 1;
2534  }
2535  $original_file = $conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2536  } elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output))
2537  {
2538  if ($fuser->rights->supplier_proposal->{$lire} || preg_match('/^specimen/i', $original_file))
2539  {
2540  $accessallowed = 1;
2541  }
2542  $original_file = $conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2543  } elseif ($modulepart == 'massfilesarea_supplier_order')
2544  {
2545  if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file))
2546  {
2547  $accessallowed = 1;
2548  }
2549  $original_file = $conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2550  } elseif ($modulepart == 'massfilesarea_supplier_invoice')
2551  {
2552  if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file))
2553  {
2554  $accessallowed = 1;
2555  }
2556  $original_file = $conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2557  } elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output))
2558  {
2559  if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file))
2560  {
2561  $accessallowed = 1;
2562  }
2563  $original_file = $conf->contrat->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2564  } // Wrapping for interventions
2565  elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output))
2566  {
2567  if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i', $original_file))
2568  {
2569  $accessallowed = 1;
2570  }
2571  $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2572  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2573  } // Wrapping pour les deplacements et notes de frais
2574  elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output))
2575  {
2576  if ($fuser->rights->deplacement->{$lire} || preg_match('/^specimen/i', $original_file))
2577  {
2578  $accessallowed = 1;
2579  }
2580  $original_file = $conf->deplacement->dir_output.'/'.$original_file;
2581  //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2582  } // Wrapping pour les propales
2583  elseif (($modulepart == 'propal' || $modulepart == 'propale') && !empty($conf->propal->multidir_output[$entity]))
2584  {
2585  if ($fuser->rights->propale->{$lire} || preg_match('/^specimen/i', $original_file))
2586  {
2587  $accessallowed = 1;
2588  }
2589  $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
2590  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('propal').")";
2591  } // Wrapping pour les commandes
2592  elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->multidir_output[$entity]))
2593  {
2594  if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file))
2595  {
2596  $accessallowed = 1;
2597  }
2598  $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
2599  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")";
2600  } // Wrapping pour les projets
2601  elseif ($modulepart == 'project' && !empty($conf->projet->dir_output))
2602  {
2603  if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i', $original_file))
2604  {
2605  $accessallowed = 1;
2606  }
2607  $original_file = $conf->projet->dir_output.'/'.$original_file;
2608  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
2609  } elseif ($modulepart == 'project_task' && !empty($conf->projet->dir_output))
2610  {
2611  if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i', $original_file))
2612  {
2613  $accessallowed = 1;
2614  }
2615  $original_file = $conf->projet->dir_output.'/'.$original_file;
2616  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
2617  } // Wrapping pour les commandes fournisseurs
2618  elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output))
2619  {
2620  if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file))
2621  {
2622  $accessallowed = 1;
2623  }
2624  $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
2625  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2626  } // Wrapping pour les factures fournisseurs
2627  elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output))
2628  {
2629  if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file))
2630  {
2631  $accessallowed = 1;
2632  }
2633  $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
2634  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2635  } // Wrapping pour les rapport de paiements
2636  elseif ($modulepart == 'supplier_payment')
2637  {
2638  if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file))
2639  {
2640  $accessallowed = 1;
2641  }
2642  $original_file = $conf->fournisseur->payment->dir_output.'/'.$original_file;
2643  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2644  } // Wrapping pour les rapport de paiements
2645  elseif ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output))
2646  {
2647  if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file))
2648  {
2649  $accessallowed = 1;
2650  }
2651  if ($fuser->societe_id > 0) $original_file = $conf->facture->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file;
2652  else $original_file = $conf->facture->dir_output.'/payments/'.$original_file;
2653  } // Wrapping for accounting exports
2654  elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output))
2655  {
2656  if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i', $original_file))
2657  {
2658  $accessallowed = 1;
2659  }
2660  $original_file = $conf->accounting->dir_output.'/'.$original_file;
2661  } // Wrapping pour les expedition
2662  elseif (($modulepart == 'expedition' || $modulepart == 'shipment') && !empty($conf->expedition->dir_output))
2663  {
2664  if ($fuser->rights->expedition->{$lire} || preg_match('/^specimen/i', $original_file))
2665  {
2666  $accessallowed = 1;
2667  }
2668  $original_file = $conf->expedition->dir_output."/sending/".$original_file;
2669  } // Delivery Note Wrapping
2670  elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output))
2671  {
2672  if ($fuser->rights->expedition->delivery->{$lire} || preg_match('/^specimen/i', $original_file))
2673  {
2674  $accessallowed = 1;
2675  }
2676  $original_file = $conf->expedition->dir_output."/receipt/".$original_file;
2677  } // Wrapping pour les actions
2678  elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output))
2679  {
2680  if ($fuser->rights->agenda->myactions->{$read} || preg_match('/^specimen/i', $original_file))
2681  {
2682  $accessallowed = 1;
2683  }
2684  $original_file = $conf->agenda->dir_output.'/'.$original_file;
2685  } // Wrapping pour les actions
2686  elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp))
2687  {
2688  if ($fuser->rights->agenda->allactions->{$read} || preg_match('/^specimen/i', $original_file))
2689  {
2690  $accessallowed = 1;
2691  }
2692  $original_file = $conf->agenda->dir_temp."/".$original_file;
2693  } // Wrapping pour les produits et services
2694  elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service')
2695  {
2696  if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2697  if (($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) || preg_match('/^specimen/i', $original_file))
2698  {
2699  $accessallowed = 1;
2700  }
2701  if (!empty($conf->product->enabled)) $original_file = $conf->product->multidir_output[$entity].'/'.$original_file;
2702  elseif (!empty($conf->service->enabled)) $original_file = $conf->service->multidir_output[$entity].'/'.$original_file;
2703  } // Wrapping pour les lots produits
2704  elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot')
2705  {
2706  if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2707  if (($fuser->rights->produit->{$lire} ) || preg_match('/^specimen/i', $original_file))
2708  {
2709  $accessallowed = 1;
2710  }
2711  if (!empty($conf->productbatch->enabled)) $original_file = $conf->productbatch->multidir_output[$entity].'/'.$original_file;
2712  } // Wrapping for stock movements
2713  elseif ($modulepart == 'movement' || $modulepart == 'mouvement')
2714  {
2715  if (empty($entity) || empty($conf->stock->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2716  if (($fuser->rights->stock->{$lire} || $fuser->rights->stock->movement->{$lire} || $fuser->rights->stock->mouvement->{$lire}) || preg_match('/^specimen/i', $original_file))
2717  {
2718  $accessallowed = 1;
2719  }
2720  if (!empty($conf->stock->enabled)) $original_file = $conf->stock->multidir_output[$entity].'/movement/'.$original_file;
2721  } // Wrapping pour les contrats
2722  elseif ($modulepart == 'contract' && !empty($conf->contrat->multidir_output[$entity]))
2723  {
2724  if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file))
2725  {
2726  $accessallowed = 1;
2727  }
2728  $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
2729  $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract').")";
2730  } // Wrapping pour les dons
2731  elseif ($modulepart == 'donation' && !empty($conf->don->dir_output))
2732  {
2733  if ($fuser->rights->don->{$lire} || preg_match('/^specimen/i', $original_file))
2734  {
2735  $accessallowed = 1;
2736  }
2737  $original_file = $conf->don->dir_output.'/'.$original_file;
2738  } // Wrapping pour les dons
2739  elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output))
2740  {
2741  if ($fuser->rights->resource->{$read} || preg_match('/^specimen/i', $original_file))
2742  {
2743  $accessallowed = 1;
2744  }
2745  $original_file = $conf->resource->dir_output.'/'.$original_file;
2746  } // Wrapping pour les remises de cheques
2747  elseif ($modulepart == 'remisecheque' && !empty($conf->bank->dir_output))
2748  {
2749  if ($fuser->rights->banque->{$lire} || preg_match('/^specimen/i', $original_file))
2750  {
2751  $accessallowed = 1;
2752  }
2753 
2754  $original_file = $conf->bank->dir_output.'/checkdeposits/'.$original_file; // original_file should contains relative path so include the get_exdir result
2755  } // Wrapping for bank
2756  elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output))
2757  {
2758  if ($fuser->rights->banque->{$lire})
2759  {
2760  $accessallowed = 1;
2761  }
2762  $original_file = $conf->bank->dir_output.'/'.$original_file;
2763  } // Wrapping for export module
2764  elseif ($modulepart == 'export' && !empty($conf->export->dir_temp))
2765  {
2766  // Aucun test necessaire car on force le rep de download sur
2767  // le rep export qui est propre a l'utilisateur
2768  $accessallowed = 1;
2769  $original_file = $conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file;
2770  } // Wrapping for import module
2771  elseif ($modulepart == 'import' && !empty($conf->import->dir_temp))
2772  {
2773  $accessallowed = 1;
2774  $original_file = $conf->import->dir_temp.'/'.$original_file;
2775  } // Wrapping pour l'editeur wysiwyg
2776  elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output))
2777  {
2778  $accessallowed = 1;
2779  $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
2780  } // Wrapping for backups
2781  elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output))
2782  {
2783  if ($fuser->admin) $accessallowed = 1;
2784  $original_file = $conf->admin->dir_output.'/'.$original_file;
2785  } // Wrapping for upload file test
2786  elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp))
2787  {
2788  if ($fuser->admin) $accessallowed = 1;
2789  $original_file = $conf->admin->dir_temp.'/'.$original_file;
2790  } // Wrapping pour BitTorrent
2791  elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output))
2792  {
2793  $accessallowed = 1;
2794  $dir = 'files';
2795  if (dol_mimetype($original_file) == 'application/x-bittorrent') $dir = 'torrents';
2796  $original_file = $conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
2797  } // Wrapping pour Foundation module
2798  elseif ($modulepart == 'member' && !empty($conf->adherent->dir_output))
2799  {
2800  if ($fuser->rights->adherent->{$lire} || preg_match('/^specimen/i', $original_file))
2801  {
2802  $accessallowed = 1;
2803  }
2804  $original_file = $conf->adherent->dir_output.'/'.$original_file;
2805  } // Wrapping for Scanner
2806  elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp))
2807  {
2808  $accessallowed = 1;
2809  $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
2810  } // GENERIC Wrapping
2811  // If modulepart=module_user_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser
2812  // If modulepart=module_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp
2813  // If modulepart=module_user Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser
2814  // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
2815  // If modulepart=module-abc Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
2816  else {
2817  //var_dump($modulepart);
2818  //var_dump($original_file);
2819  if (preg_match('/^specimen/i', $original_file)) $accessallowed = 1; // If link to a file called specimen. Test must be done before changing $original_file int full path.
2820  if ($fuser->admin) $accessallowed = 1; // If user is admin
2821  $tmpmodulepart = explode('-', $modulepart);
2822  if (!empty($tmpmodulepart[1])) {
2823  $modulepart = $tmpmodulepart[0];
2824  $original_file = $tmpmodulepart[1].'/'.$original_file;
2825  }
2826 
2827  // Define $accessallowed
2828  $reg = array();
2829  if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg))
2830  {
2831  if (empty($conf->{$reg[1]}->dir_temp)) // modulepart not supported
2832  {
2833  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
2834  exit;
2835  }
2836  if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed = 1;
2837  $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
2838  } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg))
2839  {
2840  if (empty($conf->{$reg[1]}->dir_temp)) // modulepart not supported
2841  {
2842  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
2843  exit;
2844  }
2845  if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed = 1;
2846  $original_file = $conf->{$reg[1]}->dir_temp.'/'.$original_file;
2847  } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg))
2848  {
2849  if (empty($conf->{$reg[1]}->dir_output)) // modulepart not supported
2850  {
2851  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
2852  exit;
2853  }
2854  if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed = 1;
2855  $original_file = $conf->{$reg[1]}->dir_output.'/'.$fuser->id.'/'.$original_file;
2856  } elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg))
2857  {
2858  if (empty($conf->{$reg[1]}->dir_output)) // modulepart not supported
2859  {
2860  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
2861  exit;
2862  }
2863  if ($fuser->rights->{$reg[1]}->{$lire} || preg_match('/^specimen/i', $original_file))
2864  {
2865  $accessallowed = 1;
2866  }
2867  $original_file = $conf->{$reg[1]}->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2868  } else {
2869  if (empty($conf->$modulepart->dir_output)) // modulepart not supported
2870  {
2871  dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.'). The module for this modulepart value may not be activated.');
2872  exit;
2873  }
2874 
2875  // Check fuser->rights->modulepart->myobject->read and fuser->rights->modulepart->read
2876  $partsofdirinoriginalfile = explode('/', $original_file);
2877  if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use)
2878  $partofdirinoriginalfile = $partsofdirinoriginalfile[0];
2879  if ($partofdirinoriginalfile && !empty($fuser->rights->$modulepart->$partofdirinoriginalfile) && ($fuser->rights->$modulepart->$partofdirinoriginalfile->{$lire} || $fuser->rights->$modulepart->$partofdirinoriginalfile->{$read})) $accessallowed = 1;
2880  }
2881  if (!empty($fuser->rights->$modulepart->{$lire}) || !empty($fuser->rights->$modulepart->{$read})) $accessallowed = 1;
2882 
2883  if (is_array($conf->$modulepart->multidir_output) && !empty($conf->$modulepart->multidir_output[$entity])) {
2884  $original_file = $conf->$modulepart->multidir_output[$entity].'/'.$original_file;
2885  } else {
2886  $original_file = $conf->$modulepart->dir_output.'/'.$original_file;
2887  }
2888  }
2889 
2890  // For modules who wants to manage different levels of permissions for documents
2891  $subPermCategoryConstName = strtoupper($modulepart).'_SUBPERMCATEGORY_FOR_DOCUMENTS';
2892  if (!empty($conf->global->$subPermCategoryConstName))
2893  {
2894  $subPermCategory = $conf->global->$subPermCategoryConstName;
2895  if (!empty($subPermCategory) && (($fuser->rights->$modulepart->$subPermCategory->{$lire}) || ($fuser->rights->$modulepart->$subPermCategory->{$read}) || ($fuser->rights->$modulepart->$subPermCategory->{$download})))
2896  {
2897  $accessallowed = 1;
2898  }
2899  }
2900 
2901  // Define $sqlprotectagainstexternals for modules who want to protect access using a SQL query.
2902  $sqlProtectConstName = strtoupper($modulepart).'_SQLPROTECTAGAINSTEXTERNALS_FOR_DOCUMENTS';
2903  if (!empty($conf->global->$sqlProtectConstName)) // If module want to define its own $sqlprotectagainstexternals
2904  {
2905  // Example: mymodule__SQLPROTECTAGAINSTEXTERNALS_FOR_DOCUMENTS = "SELECT fk_soc FROM ".MAIN_DB_PREFIX.$modulepart." WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2906  eval('$sqlprotectagainstexternals = "'.$conf->global->$sqlProtectConstName.'";');
2907  }
2908  }
2909 
2910  $ret = array(
2911  'accessallowed' => $accessallowed,
2912  'sqlprotectagainstexternals'=>$sqlprotectagainstexternals,
2913  'original_file'=>$original_file
2914  );
2915 
2916  return $ret;
2917 }
2918 
2927 function dol_filecache($directory, $filename, $object)
2928 {
2929  if (!dol_is_dir($directory)) dol_mkdir($directory);
2930  $cachefile = $directory.$filename;
2931  file_put_contents($cachefile, serialize($object), LOCK_EX);
2932  @chmod($cachefile, 0644);
2933 }
2934 
2943 function dol_cache_refresh($directory, $filename, $cachetime)
2944 {
2945  $now = dol_now();
2946  $cachefile = $directory.$filename;
2947  $refresh = !file_exists($cachefile) || ($now - $cachetime) > dol_filemtime($cachefile);
2948  return $refresh;
2949 }
2950 
2958 function dol_readcachefile($directory, $filename)
2959 {
2960  $cachefile = $directory.$filename;
2961  $object = unserialize(file_get_contents($cachefile));
2962  return $object;
2963 }
2964 
2965 
2977 function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
2978 {
2979  global $conffile;
2980 
2981  $exclude = 'install';
2982 
2983  foreach ($dir->md5file as $file) // $file is a simpleXMLElement
2984  {
2985  $filename = $path.$file['name'];
2986  $file_list['insignature'][] = $filename;
2987  $expectedsize = (empty($file['size']) ? '' : $file['size']);
2988  $expectedmd5 = (string) $file;
2989 
2990  //if (preg_match('#'.$exclude.'#', $filename)) continue;
2991 
2992  if (!file_exists($pathref.'/'.$filename))
2993  {
2994  $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize);
2995  } else {
2996  $md5_local = md5_file($pathref.'/'.$filename);
2997 
2998  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
2999  {
3000  $checksumconcat[] = $expectedmd5;
3001  } else {
3002  if ($md5_local != $expectedmd5) $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize, 'md5'=>(string) $md5_local);
3003  $checksumconcat[] = $md5_local;
3004  }
3005  }
3006  }
3007 
3008  foreach ($dir->dir as $subdir) // $subdir['name'] is '' or '/accountancy/admin' for example
3009  {
3010  getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat);
3011  }
3012 
3013  return $file_list;
3014 }
dol_convert_file($fileinput, $ext= 'png', $fileoutput= '', $page= '')
Convert an image file into another format.
Definition: files.lib.php:1852
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_compare_file($a, $b)
Fast compare of 2 files identified by their properties -&gt;name, -&gt;date and -&gt;size. ...
Definition: files.lib.php:399
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto= 'UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1)
Copy a file to another file.
Definition: files.lib.php:663
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:425
dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null, $excludesubdir=0)
Copy a dir to another dir.
Definition: files.lib.php:720
getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path= '', $pathref= '', &$checksumconcat=array())
Function to get list of updated or modified files.
Definition: files.lib.php:2977
Classe permettant la generation du formulaire html d&#39;envoi de mail unitaire Usage: $formail = new For...
dol_unescapefile($filename)
Unescape a file submitted by upload.
Definition: files.lib.php:943
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:223
dol_cache_refresh($directory, $filename, $cachetime)
Test if Refresh needed.
Definition: files.lib.php:2943
deleteFilesIntoDatabaseIndex($dir, $file, $mode= 'uploaded')
Delete files into database index using search criterias.
Definition: files.lib.php:1795
completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
Complete $filearray with data from database.
Definition: files.lib.php:301
dol_now($mode= 'auto')
Return date for now.
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1335
Class to scan for virus.
dol_filesize($pathoffile)
Return size of a file.
Definition: files.lib.php:555
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:432
dolCheckVirus($src_file)
Check virus into a file.
Definition: files.lib.php:958
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Definition: images.lib.php:39
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:817
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
dol_is_url($url)
Return if path is an URL.
Definition: files.lib.php:481
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser= '', $refname= '', $mode= 'read')
Security check when accessing to a document (used by document.php, viewimage.php and webservices) ...
Definition: files.lib.php:2230
dol_mimetype($file, $default= 'application/octet-stream', $mode=0)
Return mime type of a file.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories) ...
Definition: files.lib.php:1286
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition: files.lib.php:36
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1)
Remove a file or several files with a mask.
Definition: files.lib.php:1144
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
dol_sanitizeFileName($str, $newstr= '_', $unaccent=1)
Clean a string to use it as a file name.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
utf8_check($str)
Check if a string is in UTF8.
dol_count_nb_of_line($file)
Count number of lines in a file.
Definition: files.lib.php:524
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles= 'addedfile', $upload_dir= '')
Make control on an uploaded file from an GUI page and move it to final destination.
Definition: files.lib.php:999
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:457
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:1689
dolReplaceInFile($srcfile, $arrayreplacement, $destfile= '', $newmask=0, $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
Definition: files.lib.php:585
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:1488
dol_sort_array(&$array, $index, $order= 'asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
Definition: files.lib.php:2033
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:567
dol_most_recent_file($dir, $regexfilter= '', $excludefilter=array('(\.meta|_preview.*\.png)$', '^\.'), $nohook=false, $mode= '')
Return file(s) into a directory (by default most recent)
Definition: files.lib.php:2212
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
addFileIntoDatabaseIndex($dir, $file, $fullpathorig= '', $mode= 'uploaded', $setsharekey=0, $object=null)
Add a file into database index.
Definition: files.lib.php:1742
dol_readcachefile($directory, $filename)
Read object from cachefile.
Definition: files.lib.php:2958
dol_is_link($pathoffile)
Return if path is a symbolic link.
Definition: files.lib.php:469
make_substitutions($text, $substitutionarray, $outputlangs=null)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=&gt;newva...
dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesession=0, $varfiles= 'addedfile', $savingdocmask= '', $link=null, $trackid= '', $generatethumbs=1, $object=null)
Get and save an upload file (for example after submitting a new file a mail form).
Definition: files.lib.php:1528
dol_dir_is_emtpy($folder)
Test if a folder is empty.
Definition: files.lib.php:497
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
Definition: files.lib.php:1262
Class to manage ECM files.
dol_meta_create($object)
Create a meta file with document file into same directory.
Definition: files.lib.php:1411
dol_filecache($directory, $filename, $object)
Store object in file.
Definition: files.lib.php:2927
dol_mkdir($dir, $dataroot= '', $newmask=null)
Creation of a directory (this can create recursive subdir)
dol_is_dir_empty($dir)
Return if path is empty.
Definition: files.lib.php:445