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