dolibarr 21.0.4
files.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2008-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2012-2021 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2012-2016 Juanjo Menent <jmenent@2byte.es>
5 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
6 * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
7 * Copyright (C) 2019-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
1036function dol_move($srcfile, $destfile, $newmask = '0', $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1, $moreinfo = array(), $entity = 0)
1037{
1038 global $user, $db;
1039 $result = false;
1040
1041 dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
1042 $srcexists = dol_is_file($srcfile);
1043 $destexists = dol_is_file($destfile);
1044
1045 if (!$srcexists) {
1046 dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request.");
1047 return false;
1048 }
1049
1050 if ($overwriteifexists || !$destexists) {
1051 $newpathofsrcfile = dol_osencode($srcfile);
1052 $newpathofdestfile = dol_osencode($destfile);
1053
1054 // Check on virus
1055 $testvirusarray = array();
1056 if ($testvirus) {
1057 // Check using filename + antivirus
1058 $testvirusarray = dolCheckVirus($newpathofsrcfile, $newpathofdestfile);
1059 if (count($testvirusarray)) {
1060 dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. We ignore the move request.", LOG_WARNING);
1061 return false;
1062 }
1063 } else {
1064 // Check using filename only
1065 $testvirusarray = dolCheckOnFileName($newpathofsrcfile, $newpathofdestfile);
1066 if (count($testvirusarray)) {
1067 dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. We ignore the move request.", LOG_WARNING);
1068 return false;
1069 }
1070 }
1071
1072 global $dolibarr_main_restrict_os_commands;
1073 if (!empty($dolibarr_main_restrict_os_commands)) {
1074 $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
1075 $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
1076 if (in_array(basename($destfile), $arrayofallowedcommand)) {
1077 //$langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1078 //setEventMessages($langs->trans("ErrorFilenameReserved", basename($destfile)), null, 'errors');
1079 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);
1080 return false;
1081 }
1082 }
1083
1084 $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
1085 if (!$result) {
1086 if ($destexists) {
1087 dol_syslog("files.lib.php::dol_move Failed. We try to delete target first and move after.", LOG_WARNING);
1088 // We force delete and try again. Rename function sometimes fails to replace dest file with some windows NTFS partitions.
1089 dol_delete_file($destfile);
1090 $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
1091 } else {
1092 dol_syslog("files.lib.php::dol_move Failed.", LOG_WARNING);
1093 }
1094 }
1095
1096 // Move ok
1097 if ($result && $indexdatabase) {
1098 // Rename entry into ecm database
1099 $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile);
1100 $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile);
1101 if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) { // If not a tmp file
1102 $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore);
1103 $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter);
1104 //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);exit;
1105
1106 dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG);
1107 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1108
1109 $ecmfiletarget = new EcmFiles($db);
1110 $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetorenameafter, '', '', '', 0, $entity);
1111 if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created.
1112 $ecmfiletarget->delete($user);
1113 }
1114
1115 $ecmfile = new EcmFiles($db);
1116 $resultecm = $ecmfile->fetch(0, '', $rel_filetorenamebefore, '', '', '', 0, $entity);
1117 if ($resultecm > 0) { // If an entry was found for src file, we use it to move entry
1118 $filename = basename($rel_filetorenameafter);
1119 $rel_dir = dirname($rel_filetorenameafter);
1120 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1121 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1122
1123 $ecmfile->filepath = $rel_dir;
1124 $ecmfile->filename = $filename;
1125
1126 $resultecm = $ecmfile->update($user);
1127 } elseif ($resultecm == 0) { // If no entry were found for src files, create/update target file
1128 $filename = basename($rel_filetorenameafter);
1129 $rel_dir = dirname($rel_filetorenameafter);
1130 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1131 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1132
1133 $ecmfile->filepath = $rel_dir;
1134 $ecmfile->filename = $filename;
1135 $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
1136 $ecmfile->fullpath_orig = basename($srcfile);
1137 if (!empty($moreinfo) && !empty($moreinfo['gen_or_uploaded'])) {
1138 $ecmfile->gen_or_uploaded = $moreinfo['gen_or_uploaded'];
1139 } else {
1140 $ecmfile->gen_or_uploaded = 'uploaded';
1141 }
1142 if (!empty($moreinfo) && !empty($moreinfo['description'])) {
1143 $ecmfile->description = $moreinfo['description']; // indexed content
1144 } else {
1145 $ecmfile->description = ''; // indexed content
1146 }
1147 if (!empty($moreinfo) && !empty($moreinfo['keywords'])) {
1148 $ecmfile->keywords = $moreinfo['keywords']; // indexed content
1149 } else {
1150 $ecmfile->keywords = ''; // keyword content
1151 }
1152 if (!empty($moreinfo) && !empty($moreinfo['note_private'])) {
1153 $ecmfile->note_private = $moreinfo['note_private'];
1154 }
1155 if (!empty($moreinfo) && !empty($moreinfo['note_public'])) {
1156 $ecmfile->note_public = $moreinfo['note_public'];
1157 }
1158 if (!empty($moreinfo) && !empty($moreinfo['src_object_type'])) {
1159 $ecmfile->src_object_type = $moreinfo['src_object_type'];
1160 }
1161 if (!empty($moreinfo) && !empty($moreinfo['src_object_id'])) {
1162 $ecmfile->src_object_id = $moreinfo['src_object_id'];
1163 }
1164 if (!empty($moreinfo) && !empty($moreinfo['position'])) {
1165 $ecmfile->position = $moreinfo['position'];
1166 }
1167 if (!empty($moreinfo) && !empty($moreinfo['cover'])) {
1168 $ecmfile->cover = $moreinfo['cover'];
1169 }
1170 if (! empty($entity)) {
1171 $ecmfile->entity = $entity;
1172 }
1173
1174 $resultecm = $ecmfile->create($user);
1175 if ($resultecm < 0) {
1176 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1177 } else {
1178 if (!empty($moreinfo) && !empty($moreinfo['array_options']) && is_array($moreinfo['array_options'])) {
1179 $ecmfile->array_options = $moreinfo['array_options'];
1180 $resultecm = $ecmfile->insertExtraFields();
1181 if ($resultecm < 0) {
1182 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1183 }
1184 }
1185 }
1186 } elseif ($resultecm < 0) {
1187 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1188 }
1189
1190 if ($resultecm > 0) {
1191 $result = true;
1192 } else {
1193 $result = false;
1194 }
1195 }
1196 }
1197
1198 if (empty($newmask)) {
1199 $newmask = getDolGlobalString('MAIN_UMASK', '0755');
1200 }
1201
1202 // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too)
1203 // to allow mask usage for dir, we should introduce a new param "isdir" to 1 to complete newmask like this
1204 // if ($isdir) $newmaskdec |= octdec('0111'); // Set x bit required for directories
1205 dolChmod($newpathofdestfile, $newmask);
1206 }
1207
1208 return $result;
1209}
1210
1221function dol_move_dir($srcdir, $destdir, $overwriteifexists = 1, $indexdatabase = 1, $renamedircontent = 1)
1222{
1223 $result = false;
1224
1225 dol_syslog("files.lib.php::dol_move_dir srcdir=".$srcdir." destdir=".$destdir." overwritifexists=".$overwriteifexists." indexdatabase=".$indexdatabase." renamedircontent=".$renamedircontent);
1226 $srcexists = dol_is_dir($srcdir);
1227 $srcbasename = basename($srcdir);
1228 $destexists = dol_is_dir($destdir);
1229
1230 if (!$srcexists) {
1231 dol_syslog("files.lib.php::dol_move_dir srcdir does not exists. Move fails");
1232 return false;
1233 }
1234
1235 if ($overwriteifexists || !$destexists) {
1236 $newpathofsrcdir = dol_osencode($srcdir);
1237 $newpathofdestdir = dol_osencode($destdir);
1238
1239 // On windows, if destination directory exists and is empty, command fails. So if overwrite is on, we first remove destination directory.
1240 // On linux, if destination directory exists and is empty, command succeed. So no need to delete di destination directory first.
1241 // Note: If dir exists and is not empty, it will and must fail on both linux and windows even, if option $overwriteifexists is on.
1242 if ($overwriteifexists) {
1243 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
1244 if (is_dir($newpathofdestdir)) {
1245 @rmdir($newpathofdestdir);
1246 }
1247 }
1248 }
1249
1250 $result = @rename($newpathofsrcdir, $newpathofdestdir);
1251
1252 // Now rename contents in the directory after the move to match the new destination
1253 if ($result && $renamedircontent) {
1254 if (file_exists($newpathofdestdir)) {
1255 $destbasename = basename($newpathofdestdir);
1256 $files = dol_dir_list($newpathofdestdir);
1257 if (!empty($files) && is_array($files)) {
1258 foreach ($files as $key => $file) {
1259 if (!file_exists($file["fullname"])) {
1260 continue;
1261 }
1262 $filepath = $file["path"];
1263 $oldname = $file["name"];
1264
1265 $newname = str_replace($srcbasename, $destbasename, $oldname);
1266 if (!empty($newname) && $newname !== $oldname) {
1267 if ($file["type"] == "dir") {
1268 $res = dol_move_dir($filepath.'/'.$oldname, $filepath.'/'.$newname, $overwriteifexists, $indexdatabase, $renamedircontent);
1269 } else {
1270 $res = dol_move($filepath.'/'.$oldname, $filepath.'/'.$newname, '0', $overwriteifexists, 0, $indexdatabase);
1271 }
1272 if (!$res) {
1273 return $result;
1274 }
1275 }
1276 }
1277 $result = true;
1278 }
1279 }
1280 }
1281 }
1282 return $result;
1283}
1284
1292function dol_unescapefile($filename)
1293{
1294 // Remove path information and dots around the filename, to prevent uploading
1295 // into different directories or replacing hidden system files.
1296 // Also remove control characters and spaces (\x00..\x20) around the filename:
1297 return trim(basename($filename), ".\x00..\x20");
1298}
1299
1300
1308function dolCheckVirus($src_file, $dest_file = '')
1309{
1310 global $db;
1311
1312 $reterrors = dolCheckOnFileName($src_file, $dest_file);
1313 if (!empty($reterrors)) {
1314 return $reterrors;
1315 }
1316
1317 if (getDolGlobalString('MAIN_ANTIVIRUS_COMMAND')) {
1318 if (!class_exists('AntiVir')) {
1319 require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
1320 }
1321 $antivir = new AntiVir($db);
1322 $result = $antivir->dol_avscan_file($src_file);
1323 if ($result < 0) { // If virus or error, we stop here
1324 $reterrors = $antivir->errors;
1325 return $reterrors;
1326 }
1327 }
1328 return array();
1329}
1330
1338function dolCheckOnFileName($src_file, $dest_file = '')
1339{
1340 if (preg_match('/\.pdf$/i', $dest_file)) {
1341 if (!getDolGlobalString('MAIN_ANTIVIRUS_ALLOW_JS_IN_PDF')) {
1342 dol_syslog("dolCheckOnFileName Check that pdf does not contains js code");
1343
1344 $tmp = file_get_contents(trim($src_file));
1345 if (preg_match('/[\n\s]+\/JavaScript[\n\s]+/m', $tmp)) {
1346 return array('File is a PDF with javascript inside');
1347 }
1348 } else {
1349 dol_syslog("dolCheckOnFileName Check js into pdf disabled");
1350 }
1351 }
1352
1353 return array();
1354}
1355
1356
1377function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile', $upload_dir = '')
1378{
1379 global $conf;
1380 global $object, $hookmanager;
1381
1382 $reshook = 0;
1383 $file_name = $dest_file;
1384 $successcode = 1;
1385
1386 if (empty($nohook)) {
1387 $reshook = $hookmanager->initHooks(array('fileslib'));
1388
1389 $parameters = array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
1390 $reshook = $hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
1391 }
1392
1393 if (empty($reshook)) {
1394 // If an upload error has been reported
1395 if ($uploaderrorcode) {
1396 switch ($uploaderrorcode) {
1397 case UPLOAD_ERR_INI_SIZE: // 1
1398 return 'ErrorFileSizeTooLarge';
1399 case UPLOAD_ERR_FORM_SIZE: // 2
1400 return 'ErrorFileSizeTooLarge';
1401 case UPLOAD_ERR_PARTIAL: // 3
1402 return 'ErrorPartialFile';
1403 case UPLOAD_ERR_NO_TMP_DIR: //
1404 return 'ErrorNoTmpDir';
1405 case UPLOAD_ERR_CANT_WRITE:
1406 return 'ErrorFailedToWriteInDir';
1407 case UPLOAD_ERR_EXTENSION:
1408 return 'ErrorUploadBlockedByAddon';
1409 default:
1410 break;
1411 }
1412 }
1413
1414 // Security:
1415 // If we need to make a virus scan
1416 if (empty($disablevirusscan) && file_exists($src_file)) {
1417 $checkvirusarray = dolCheckVirus($src_file, $dest_file);
1418 if (count($checkvirusarray)) {
1419 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.implode(',', $checkvirusarray), LOG_WARNING);
1420 return 'ErrorFileIsInfectedWithAVirus: '.implode(',', $checkvirusarray);
1421 }
1422 }
1423
1424 // Security:
1425 // Disallow file with some extensions. We rename them.
1426 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
1427 if (isAFileWithExecutableContent($dest_file) && !getDolGlobalString('MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED')) {
1428 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
1429 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
1430 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
1431 $publicmediasdirwithslash .= '/';
1432 }
1433
1434 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
1435 $file_name .= '.noexe';
1436 $successcode = 2;
1437 }
1438 }
1439
1440 // Security:
1441 // We refuse cache files/dirs, upload using .. and pipes into filenames.
1442 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
1443 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
1444 return -1;
1445 }
1446
1447 // Security:
1448 // We refuse cache files/dirs, upload using .. and pipes into filenames.
1449 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
1450 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
1451 return -2;
1452 }
1453 }
1454
1455 if ($reshook < 0) { // At least one blocking error returned by one hook
1456 $errmsg = implode(',', $hookmanager->errors);
1457 if (empty($errmsg)) {
1458 $errmsg = 'ErrorReturnedBySomeHooks'; // Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
1459 }
1460 return $errmsg;
1461 } elseif (empty($reshook)) {
1462 // The file functions must be in OS filesystem encoding.
1463 $src_file_osencoded = dol_osencode($src_file);
1464 $file_name_osencoded = dol_osencode($file_name);
1465
1466 // Check if destination dir is writable
1467 if (!is_writable(dirname($file_name_osencoded))) {
1468 dol_syslog("Files.lib::dol_move_uploaded_file Dir ".dirname($file_name_osencoded)." is not writable. Return 'ErrorDirNotWritable'", LOG_WARNING);
1469 return 'ErrorDirNotWritable';
1470 }
1471
1472 // Check if destination file already exists
1473 if (!$allowoverwrite) {
1474 if (file_exists($file_name_osencoded)) {
1475 dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
1476 return 'ErrorFileAlreadyExists';
1477 }
1478 } else { // We are allowed to erase
1479 if (is_dir($file_name_osencoded)) { // If there is a directory with name of file to create
1480 dol_syslog("Files.lib::dol_move_uploaded_file A directory with name ".$file_name." already exists. Return 'ErrorDirWithFileNameAlreadyExists'", LOG_WARNING);
1481 return 'ErrorDirWithFileNameAlreadyExists';
1482 }
1483 }
1484
1485 // Move file
1486 $return = move_uploaded_file($src_file_osencoded, $file_name_osencoded);
1487 if ($return) {
1488 dolChmod($file_name_osencoded);
1489 dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=" . getDolGlobalString('MAIN_UMASK'), LOG_DEBUG);
1490 return $successcode; // Success
1491 } else {
1492 dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
1493 return -3; // Unknown error
1494 }
1495 }
1496
1497 return $successcode; // Success
1498}
1499
1515function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1, $nolog = 0)
1516{
1517 global $db, $user;
1518 global $hookmanager;
1519
1520 if (empty($nolog)) {
1521 dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook);
1522 }
1523
1524 // Security:
1525 // We refuse transversal using .. and pipes into filenames.
1526 if ((!$allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file)) {
1527 dol_syslog("Refused to delete file ".$file, LOG_WARNING);
1528 return false;
1529 }
1530
1531 $reshook = 0;
1532 if (empty($nohook) && !empty($hookmanager)) {
1533 $hookmanager->initHooks(array('fileslib'));
1534
1535 $parameters = array(
1536 'file' => $file,
1537 'disableglob' => $disableglob,
1538 'nophperrors' => $nophperrors
1539 );
1540 $reshook = $hookmanager->executeHooks('deleteFile', $parameters, $object);
1541 }
1542
1543 if (empty($nohook) && $reshook != 0) { // reshook = 0 to do standard actions, 1 = ok and replace, -1 = ko
1544 dol_syslog("reshook=".$reshook);
1545 if ($reshook < 0) {
1546 return false;
1547 }
1548 return true;
1549 } else {
1550 $file_osencoded = dol_osencode($file); // New filename encoded in OS filesystem encoding charset
1551 if (empty($disableglob) && !empty($file_osencoded)) {
1552 $ok = true;
1553 $globencoded = str_replace('[', '\[', $file_osencoded);
1554 $globencoded = str_replace(']', '\]', $globencoded);
1555 $listofdir = glob($globencoded); // This scan dir for files. If file does not exists, return empty.
1556
1557 if (!empty($listofdir) && is_array($listofdir)) {
1558 foreach ($listofdir as $filename) {
1559 if ($nophperrors) {
1560 $ok = @unlink($filename);
1561 } else {
1562 $ok = unlink($filename);
1563 }
1564
1565 // If it fails and it is because of the missing write permission on parent dir
1566 if (!$ok && file_exists(dirname($filename)) && !(fileperms(dirname($filename)) & 0200)) {
1567 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);
1568 dolChmod(dirname($filename), decoct(fileperms(dirname($filename)) | 0200));
1569 // Now we retry deletion
1570 if ($nophperrors) {
1571 $ok = @unlink($filename);
1572 } else {
1573 $ok = unlink($filename);
1574 }
1575 }
1576
1577 if ($ok) {
1578 if (empty($nolog)) {
1579 dol_syslog("Removed file ".$filename, LOG_DEBUG);
1580 }
1581
1582 // Delete entry into ecm database
1583 $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename);
1584 if (!preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) { // If not a tmp file
1585 if (is_object($db) && $indexdatabase) { // $db may not be defined when lib is in a context with define('NOREQUIREDB',1)
1586 $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete);
1587 $rel_filetodelete = preg_replace('/\.noexe$/', '', $rel_filetodelete);
1588
1589 dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG);
1590 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1591 $ecmfile = new EcmFiles($db);
1592 $result = $ecmfile->fetch(0, '', $rel_filetodelete, '', '', '', 0, $object->entity ?? 0);
1593 if ($result >= 0 && $ecmfile->id > 0) {
1594 $result = $ecmfile->delete($user);
1595 }
1596 if ($result < 0) {
1597 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1598 }
1599 }
1600 }
1601 } else {
1602 dol_syslog("Failed to remove file ".$filename, LOG_WARNING);
1603 // TODO Failure to remove can be because file was already removed or because of permission
1604 // If error because it does not exists, we should return true, and we should return false if this is a permission problem
1605 }
1606 }
1607 } else {
1608 $ok = true; // nothing to delete when glob is on must return ok
1609 dol_syslog("No files to delete found", LOG_DEBUG);
1610 }
1611 } else {
1612 $ok = false;
1613 if ($nophperrors) {
1614 $ok = @unlink($file_osencoded);
1615 } else {
1616 $ok = unlink($file_osencoded);
1617 }
1618 if ($ok) {
1619 if (empty($nolog)) {
1620 dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
1621 }
1622 } else {
1623 dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
1624 }
1625 }
1626
1627 return $ok;
1628 }
1629}
1630
1640function dol_delete_dir($dir, $nophperrors = 0)
1641{
1642 // Security:
1643 // We refuse transversal using .. and pipes into filenames.
1644 if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) {
1645 dol_syslog("Refused to delete dir ".$dir.' (contains invalid char sequence)', LOG_WARNING);
1646 return false;
1647 }
1648
1649 $dir_osencoded = dol_osencode($dir);
1650 return ($nophperrors ? @rmdir($dir_osencoded) : rmdir($dir_osencoded));
1651}
1652
1666function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0, $indexdatabase = 1, $nolog = 0, $level = 0)
1667{
1668 if (empty($nolog) || empty($level)) {
1669 dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG);
1670 }
1671 if ($level > 1000) {
1672 dol_syslog("functions.lib:dol_delete_dir_recursive too many depth", LOG_WARNING);
1673 }
1674
1675 if (dol_is_dir($dir)) {
1676 $dir_osencoded = dol_osencode($dir);
1677 if ($handle = opendir("$dir_osencoded")) {
1678 while (false !== ($item = readdir($handle))) {
1679 if (!utf8_check($item)) {
1680 $item = mb_convert_encoding($item, 'UTF-8', 'ISO-8859-1'); // should be useless
1681 }
1682
1683 if ($item != "." && $item != "..") {
1684 if (is_dir(dol_osencode("$dir/$item")) && !is_link(dol_osencode("$dir/$item"))) {
1685 $count = dol_delete_dir_recursive("$dir/$item", $count, $nophperrors, 0, $countdeleted, $indexdatabase, $nolog, ($level + 1));
1686 } else {
1687 $result = dol_delete_file("$dir/$item", 1, $nophperrors, 0, null, false, $indexdatabase, $nolog);
1688 $count++;
1689 if ($result) {
1690 $countdeleted++;
1691 }
1692 //else print 'Error on '.$item."\n";
1693 }
1694 }
1695 }
1696 closedir($handle);
1697
1698 // Delete also the main directory
1699 if (empty($onlysub)) {
1700 $result = dol_delete_dir($dir, $nophperrors);
1701 $count++;
1702 if ($result) {
1703 $countdeleted++;
1704 }
1705 //else print 'Error on '.$dir."\n";
1706 }
1707 }
1708 }
1709
1710 return $count;
1711}
1712
1713
1723{
1724 global $langs, $conf;
1725
1726 // Define parent dir of elements
1727 $element = $object->element;
1728
1729 if ($object->element == 'order_supplier') {
1730 $dir = $conf->fournisseur->commande->dir_output;
1731 } elseif ($object->element == 'invoice_supplier') {
1732 $dir = $conf->fournisseur->facture->dir_output;
1733 } elseif ($object->element == 'project') {
1734 $dir = $conf->project->dir_output;
1735 } elseif ($object->element == 'shipping') {
1736 $dir = $conf->expedition->dir_output.'/sending';
1737 } elseif ($object->element == 'delivery') {
1738 $dir = $conf->expedition->dir_output.'/receipt';
1739 } elseif ($object->element == 'fichinter') {
1740 $dir = $conf->ficheinter->dir_output;
1741 } else {
1742 $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1743 }
1744
1745 if (empty($dir)) {
1746 $object->error = $langs->trans('ErrorObjectNoSupportedByFunction');
1747 return 0;
1748 }
1749
1750 $refsan = dol_sanitizeFileName($object->ref);
1751 $dir = $dir."/".$refsan;
1752 $filepreviewnew = $dir."/".$refsan.".pdf_preview.png";
1753 $filepreviewnewbis = $dir."/".$refsan.".pdf_preview-0.png";
1754 $filepreviewold = $dir."/".$refsan.".pdf.png";
1755
1756 // For new preview files
1757 if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) {
1758 if (!dol_delete_file($filepreviewnew, 1)) {
1759 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnew);
1760 return 0;
1761 }
1762 }
1763 if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) {
1764 if (!dol_delete_file($filepreviewnewbis, 1)) {
1765 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis);
1766 return 0;
1767 }
1768 }
1769 // For old preview files
1770 if (file_exists($filepreviewold) && is_writable($filepreviewold)) {
1771 if (!dol_delete_file($filepreviewold, 1)) {
1772 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewold);
1773 return 0;
1774 }
1775 } else {
1776 $multiple = $filepreviewold.".";
1777 for ($i = 0; $i < 20; $i++) {
1778 $preview = $multiple.$i;
1779
1780 if (file_exists($preview) && is_writable($preview)) {
1781 if (!dol_delete_file($preview, 1)) {
1782 $object->error = $langs->trans("ErrorFailedToOpenFile", $preview);
1783 return 0;
1784 }
1785 }
1786 }
1787 }
1788
1789 return 1;
1790}
1791
1801{
1802 global $conf;
1803
1804 // Create meta file
1805 if (!getDolGlobalString('MAIN_DOC_CREATE_METAFILE')) {
1806 return 0; // By default, no metafile.
1807 }
1808
1809 // Define parent dir of elements
1810 $element = $object->element;
1811
1812 if ($object->element == 'order_supplier') {
1813 $dir = $conf->fournisseur->dir_output.'/commande';
1814 } elseif ($object->element == 'invoice_supplier') {
1815 $dir = $conf->fournisseur->dir_output.'/facture';
1816 } elseif ($object->element == 'project') {
1817 $dir = $conf->project->dir_output;
1818 } elseif ($object->element == 'shipping') {
1819 $dir = $conf->expedition->dir_output.'/sending';
1820 } elseif ($object->element == 'delivery') {
1821 $dir = $conf->expedition->dir_output.'/receipt';
1822 } elseif ($object->element == 'fichinter') {
1823 $dir = $conf->ficheinter->dir_output;
1824 } else {
1825 $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1826 }
1827
1828 if ($dir) {
1829 $object->fetch_thirdparty();
1830
1831 $objectref = dol_sanitizeFileName($object->ref);
1832 $dir = $dir."/".$objectref;
1833 $file = $dir."/".$objectref.".meta";
1834
1835 if (!is_dir($dir)) {
1836 dol_mkdir($dir);
1837 }
1838
1839 $meta = '';
1840 if (is_dir($dir)) {
1841 if (is_countable($object->lines) && count($object->lines) > 0) {
1842 $nblines = count($object->lines);
1843 } else {
1844 $nblines = 0;
1845 }
1846 $client = $object->thirdparty->name." ".$object->thirdparty->address." ".$object->thirdparty->zip." ".$object->thirdparty->town;
1847 $meta = "REFERENCE=\"".$object->ref."\"
1848 DATE=\"" . dol_print_date($object->date, '')."\"
1849 NB_ITEMS=\"" . $nblines."\"
1850 CLIENT=\"" . $client."\"
1851 AMOUNT_EXCL_TAX=\"" . $object->total_ht."\"
1852 AMOUNT=\"" . $object->total_ttc."\"\n";
1853
1854 for ($i = 0; $i < $nblines; $i++) {
1855 //Pour les articles
1856 $meta .= "ITEM_".$i."_QUANTITY=\"".$object->lines[$i]->qty."\"
1857 ITEM_" . $i."_AMOUNT_WO_TAX=\"".$object->lines[$i]->total_ht."\"
1858 ITEM_" . $i."_VAT=\"".$object->lines[$i]->tva_tx."\"
1859 ITEM_" . $i."_DESCRIPTION=\"".str_replace("\r\n", "", nl2br($object->lines[$i]->desc))."\"
1860 ";
1861 }
1862 }
1863
1864 $fp = fopen($file, "w");
1865 fwrite($fp, $meta);
1866 fclose($fp);
1867
1868 dolChmod($file);
1869
1870 return 1;
1871 } else {
1872 dol_syslog('FailedToDetectDirInDolMetaCreateFor'.$object->element, LOG_WARNING);
1873 }
1874
1875 return 0;
1876}
1877
1878
1879
1888function dol_init_file_process($pathtoscan = '', $trackid = '')
1889{
1890 $listofpaths = array();
1891 $listofnames = array();
1892 $listofmimes = array();
1893
1894 if ($pathtoscan) {
1895 $listoffiles = dol_dir_list($pathtoscan, 'files');
1896 foreach ($listoffiles as $key => $val) {
1897 $listofpaths[] = $val['fullname'];
1898 $listofnames[] = $val['name'];
1899 $listofmimes[] = dol_mimetype($val['name']);
1900 }
1901 }
1902 $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1903 $_SESSION["listofpaths".$keytoavoidconflict] = implode(';', $listofpaths);
1904 $_SESSION["listofnames".$keytoavoidconflict] = implode(';', $listofnames);
1905 $_SESSION["listofmimes".$keytoavoidconflict] = implode(';', $listofmimes);
1906}
1907
1908
1927function dol_add_file_process($upload_dir, $allowoverwrite = 0, $updatesessionordb = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null, $forceFullTextIndexation = '')
1928{
1929 global $db, $user, $conf, $langs;
1930
1931 $res = 0;
1932
1933 if (!empty($_FILES[$varfiles])) { // For view $_FILES[$varfiles]['error']
1934 dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' updatesessionordb='.$updatesessionordb.' savingdocmask='.$savingdocmask, LOG_DEBUG);
1935 $maxfilesinform = getDolGlobalInt("MAIN_SECURITY_MAX_ATTACHMENT_ON_FORMS", 10);
1936 if (is_array($_FILES[$varfiles]["name"]) && count($_FILES[$varfiles]["name"]) > $maxfilesinform) {
1937 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1938 setEventMessages($langs->trans("ErrorTooMuchFileInForm", $maxfilesinform), null, "errors");
1939 return -1;
1940 }
1941
1942 $result = dol_mkdir($upload_dir);
1943 //var_dump($result);exit;
1944
1945 if ($result >= 0) {
1946 $TFile = $_FILES[$varfiles];
1947 // Convert value of $TFile
1948 if (!is_array($TFile['name'])) {
1949 foreach ($TFile as $key => &$val) {
1950 $val = array($val);
1951 }
1952 }
1953
1954 $nbfile = count($TFile['name']);
1955 $nbok = 0;
1956 for ($i = 0; $i < $nbfile; $i++) {
1957 if (empty($TFile['name'][$i])) {
1958 continue; // For example, when submitting a form with no file name
1959 }
1960
1961 // Define $destfull (path to file including filename) and $destfile (only filename)
1962 $destfile = trim($TFile['name'][$i]);
1963 $destfull = $upload_dir."/".$destfile;
1964 $destfilewithoutext = preg_replace('/\.[^\.]+$/', '', $destfile);
1965
1966 if ($savingdocmask && strpos($savingdocmask, $destfilewithoutext) !== 0) {
1967 $destfile = trim(preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask));
1968 $destfull = $upload_dir."/".$destfile;
1969 }
1970
1971 $filenameto = basename($destfile);
1972 if (preg_match('/^\./', $filenameto)) {
1973 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1974 setEventMessages($langs->trans("ErrorFilenameCantStartWithDot", $filenameto), null, 'errors');
1975 break;
1976 }
1977 // dol_sanitizeFileName the file name and lowercase extension
1978 $info = pathinfo($destfull);
1979 $destfull = $info['dirname'].'/'.dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1980 $info = pathinfo($destfile);
1981 $destfile = dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1982
1983 // We apply dol_string_nohtmltag also to clean file names (this remove duplicate spaces) because
1984 // this function is also applied when we rename and when we make try to download file (by the GETPOST(filename, 'alphanohtml') call).
1985 $destfile = dol_string_nohtmltag($destfile);
1986 $destfull = dol_string_nohtmltag($destfull);
1987
1988 // Check that filename is not the one of a reserved allowed CLI command
1989 global $dolibarr_main_restrict_os_commands;
1990 if (!empty($dolibarr_main_restrict_os_commands)) {
1991 $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
1992 $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
1993 if (in_array($destfile, $arrayofallowedcommand)) {
1994 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1995 setEventMessages($langs->trans("ErrorFilenameReserved", $destfile), null, 'errors');
1996 return -1;
1997 }
1998 }
1999
2000 // Move file from temp directory to final directory. A .noexe may also be appended on file name.
2001 $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir);
2002
2003 if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists', 'ErrorFileIsInfectedWithAVirus...'
2004 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
2005
2006 $tmparraysize = getDefaultImageSizes();
2007 $maxwidthsmall = $tmparraysize['maxwidthsmall'];
2008 $maxheightsmall = $tmparraysize['maxheightsmall'];
2009 $maxwidthmini = $tmparraysize['maxwidthmini'];
2010 $maxheightmini = $tmparraysize['maxheightmini'];
2011 //$quality = $tmparraysize['quality'];
2012 $quality = 50; // For thumbs, we force quality to 50
2013
2014 // Generate thumbs.
2015 if ($generatethumbs) {
2016 if (image_format_supported($destfull) == 1) {
2017 // Create thumbs
2018 // We can't use $object->addThumbs here because there is no $object known
2019
2020 // Used on logon for example
2021 $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', $quality, "thumbs");
2022 // Create mini thumbs for image (Ratio is near 16/9)
2023 // Used on menu or for setup page for example
2024 $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', $quality, "thumbs");
2025 }
2026 }
2027
2028 // Update session
2029 if (empty($updatesessionordb)) {
2030 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2031 $formmail = new FormMail($db);
2032 $formmail->trackid = $trackid;
2033 $formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
2034 }
2035
2036 // Update index table of files (llx_ecm_files)
2037 if ($updatesessionordb == 1) {
2038 $sharefile = 0;
2039 if ($TFile['type'][$i] == 'application/pdf' && strpos($_SERVER["REQUEST_URI"], 'product') !== false && getDolGlobalString('PRODUCT_ALLOW_EXTERNAL_DOWNLOAD')) {
2040 $sharefile = 1;
2041 }
2042
2043 // If we allow overwrite, we may need to also overwrite index, so we delete index first so insert can work
2044 if ($allowoverwrite) {
2045 deleteFilesIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), '', $object);
2046 }
2047
2048 $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', $sharefile, $object, $forceFullTextIndexation);
2049 if ($result < 0) {
2050 if ($allowoverwrite) {
2051 // Do not show error message. We can have an error due to DB_ERROR_RECORD_ALREADY_EXISTS
2052 } else {
2053 setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', null, 'warnings');
2054 }
2055 }
2056 }
2057
2058 $nbok++;
2059 } else {
2060 $langs->load("errors");
2061 if (is_numeric($resupload) && $resupload < 0) { // Unknown error
2062 setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
2063 } elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) { // Files infected by a virus
2064 if (preg_match('/File is a PDF with javascript inside/', $resupload)) {
2065 setEventMessages($langs->trans("ErrorFileIsAnInfectedPDFWithJSInside"), null, 'errors');
2066 } else {
2067 setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus").'<br>'.dolGetFirstLineOfText($resupload), null, 'errors');
2068 }
2069 } else { // Known error
2070 setEventMessages($langs->trans($resupload), null, 'errors');
2071 }
2072 }
2073 }
2074 if ($nbok > 0) {
2075 $res = $nbok;
2076 setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs');
2077 }
2078 } else {
2079 setEventMessages($langs->trans("ErrorFailedToCreateDir", $upload_dir), null, 'errors');
2080 }
2081 } elseif ($link) {
2082 require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
2083 $linkObject = new Link($db);
2084 $linkObject->entity = $conf->entity;
2085 $linkObject->url = $link;
2086 $linkObject->objecttype = GETPOST('objecttype', 'alpha');
2087 $linkObject->objectid = GETPOSTINT('objectid');
2088 $linkObject->label = GETPOST('label', 'alpha');
2089 $res = $linkObject->create($user);
2090
2091 if ($res > 0) {
2092 setEventMessages($langs->trans("LinkComplete"), null, 'mesgs');
2093 } else {
2094 setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors');
2095 }
2096 } else {
2097 $langs->load("errors");
2098 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
2099 }
2100
2101 return $res;
2102}
2103
2104
2116function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '')
2117{
2118 global $db, $user, $conf, $langs, $_FILES;
2119
2120 $keytodelete = $filenb;
2121 $keytodelete--;
2122
2123 $listofpaths = array();
2124 $listofnames = array();
2125 $listofmimes = array();
2126 $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
2127 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
2128 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
2129 }
2130 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
2131 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
2132 }
2133 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
2134 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
2135 }
2136
2137 if ($keytodelete >= 0) {
2138 $pathtodelete = $listofpaths[$keytodelete];
2139 $filetodelete = $listofnames[$keytodelete];
2140 if (empty($donotdeletefile)) {
2141 $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file
2142 } else {
2143 $result = 0;
2144 }
2145 if ($result >= 0) {
2146 if (empty($donotdeletefile)) {
2147 $langs->load("other");
2148 setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs');
2149 }
2150 if (empty($donotupdatesession)) {
2151 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2152 $formmail = new FormMail($db);
2153 $formmail->trackid = $trackid;
2154 $formmail->remove_attached_files($keytodelete);
2155 }
2156 }
2157 }
2158}
2159
2160
2175function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null, $forceFullTextIndexation = '')
2176{
2177 global $db, $user, $conf;
2178
2179 $result = 0;
2180 $error = 0;
2181
2182 dol_syslog("addFileIntoDatabaseIndex dir=".$dir." file=".$file, LOG_DEBUG);
2183
2184 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2185
2186 if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a temporary directory. TODO Does this test work ?
2187 $filename = basename(preg_replace('/\.noexe$/', '', $file));
2188 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2189 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2190
2191 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
2192 $ecmfile = new EcmFiles($db);
2193 $ecmfile->filepath = $rel_dir;
2194 $ecmfile->filename = $filename;
2195 $ecmfile->label = md5_file(dol_osencode($dir.'/'.$file)); // MD5 of file content
2196 $ecmfile->fullpath_orig = $fullpathorig;
2197 $ecmfile->gen_or_uploaded = $mode;
2198 $ecmfile->description = ''; // indexed content
2199 $ecmfile->keywords = ''; // keyword content
2200
2201 if (is_object($object) && $object->id > 0) {
2202 $ecmfile->src_object_id = $object->id;
2203 if (isset($object->table_element)) {
2204 $ecmfile->src_object_type = $object->table_element;
2205 } else {
2206 dol_syslog('Error: object ' . get_class($object) . ' has no table_element attribute.');
2207 return -1;
2208 }
2209 if (isset($object->src_object_description)) {
2210 $ecmfile->description = $object->src_object_description;
2211 }
2212 if (isset($object->src_object_keywords)) {
2213 $ecmfile->keywords = $object->src_object_keywords;
2214 }
2215 if (isset($object->entity)) {
2216 $ecmfile->entity = $object->entity;
2217 }
2218 }
2219
2220 if (getDolGlobalString('MAIN_FORCE_SHARING_ON_ANY_UPLOADED_FILE')) {
2221 $setsharekey = 1;
2222 }
2223
2224 if ($setsharekey) {
2225 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
2226 $ecmfile->share = getRandomPassword(true);
2227 }
2228
2229 // Use a convertisser Doc to Text
2230 $useFullTextIndexation = getDolGlobalString('MAIN_SAVE_FILE_CONTENT_AS_TEXT');
2231 if (empty($useFullTextIndexation) && $forceFullTextIndexation == '1') {
2232 if (getDolGlobalString('MAIN_SAVE_FILE_CONTENT_AS_TEXT_PDFTOTEXT')) {
2233 $useFullTextIndexation = 'pdftotext';
2234 } elseif (getDolGlobalString('MAIN_SAVE_FILE_CONTENT_AS_TEXT_DOCLING')) {
2235 $useFullTextIndexation = 'docling';
2236 }
2237 }
2238
2239 //$useFullTextIndexation = 1;
2240 if ($useFullTextIndexation) {
2241 $ecmfile->filepath = $rel_dir;
2242 $ecmfile->filename = $filename;
2243
2244 $filetoprocess = $dir.'/'.$ecmfile->filename;
2245
2246 $textforfulltextindex = '';
2247 $keywords = '';
2248 $cmd = '';
2249 if (preg_match('/\.pdf/i', $filename)) {
2250 // TODO Move this into external submodule files
2251
2252 // TODO Develop a native PHP parser using sample code in https://github.com/adeel/php-pdf-parser
2253
2254 // Use the method pdftotext to generate a HTML
2255 if (preg_match('/pdftotext/i', $useFullTextIndexation)) {
2256 include_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
2257 $utils = new Utils($db);
2258 $outputfile = $conf->admin->dir_temp.'/tmppdftotext.'.$user->id.'.out'; // File used with popen method
2259
2260 // We also exclude '/temp/' dir and 'documents/admin/documents'
2261 // We make escapement here and call executeCLI without escapement because we don't want to have the '*.log' escaped.
2262 $cmd = getDolGlobalString('MAIN_SAVE_FILE_CONTENT_AS_TEXT_PDFTOTEXT', 'pdftotext')." -htmlmeta '".escapeshellcmd($filetoprocess)."' - ";
2263 $resultexec = $utils->executeCLI($cmd, $outputfile, 0, null, 1);
2264
2265 if (!$resultexec['error']) {
2266 $txt = $resultexec['output'];
2267 $matches = array();
2268 if (preg_match('/<meta name="Keywords" content="([^\/]+)"\s*\/>/i', $txt, $matches)) {
2269 $keywords = $matches[1];
2270 }
2271 if (preg_match('/<pre>(.*)<\/pre>/si', $txt, $matches)) {
2272 $textforfulltextindex = dol_string_nounprintableascii($matches[1], 0);
2273 }
2274 } else {
2275 dol_syslog($resultexec['error']);
2276 $error++;
2277 }
2278 }
2279
2280 // Use the method docling to generate a .md (https://ds4sd.github.io/docling/)
2281 if (preg_match('/docling/i', $useFullTextIndexation)) {
2282 include_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
2283 $utils = new Utils($db);
2284 $outputfile = $conf->admin->dir_temp.'/tmpdocling.'.$user->id.'.out'; // File used with popen method
2285
2286 // We also exclude '/temp/' dir and 'documents/admin/documents'
2287 // We make escapement here and call executeCLI without escapement because we don't want to have the '*.log' escaped.
2288 $cmd = getDolGlobalString('MAIN_SAVE_FILE_CONTENT_AS_TEXT_DOCLING', 'docling')." --from pdf --to text '".escapeshellcmd($filetoprocess)."'";
2289 $resultexec = $utils->executeCLI($cmd, $outputfile, 0, null, 1);
2290
2291 if (!$resultexec['error']) {
2292 $txt = $resultexec['output'];
2293 //$matches = array();
2294 //if (preg_match('/<meta name="Keywords" content="([^\/]+)"\s*\/>/i', $txt, $matches)) {
2295 // $keywords = $matches[1];
2296 //}
2297 //if (preg_match('/<pre>(.*)<\/pre>/si', $txt, $matches)) {
2298 // $textforfulltextindex = dol_string_nounprintableascii($matches[1], 0);
2299 //}
2300 $textforfulltextindex = $txt;
2301 } else {
2302 dol_syslog($resultexec['error']);
2303 $error++;
2304 }
2305 }
2306 }
2307
2308 if ($cmd) {
2309 $ecmfile->description = 'File content generated by '.$cmd;
2310 }
2311 $ecmfile->content = $textforfulltextindex;
2312 $ecmfile->keywords = $keywords;
2313 }
2314
2315 if (!$error) {
2316 $result = $ecmfile->create($user);
2317 if ($result < 0) {
2318 dol_syslog($ecmfile->error);
2319 }
2320 }
2321 }
2322
2323 return $result;
2324}
2325
2335function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded', $object = null)
2336{
2337 global $conf, $db;
2338
2339 $error = 0;
2340
2341 if (empty($dir)) {
2342 dol_syslog("deleteFilesIntoDatabaseIndex: dir parameter can't be empty", LOG_ERR);
2343 return -1;
2344 }
2345
2346 dol_syslog("deleteFilesIntoDatabaseIndex dir=".$dir." file=".$file, LOG_DEBUG);
2347
2348 $db->begin();
2349
2350 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2351
2352 if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a temporary directory. TODO Does this test work ?
2353 $filename = basename($file);
2354 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2355 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2356
2357 if (!$error) {
2358 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'ecm_files';
2359 if (isset($object->entity)) {
2360 $sql .= ' WHERE entity = ' . ((int) $object->entity);
2361 } else {
2362 $sql .= ' WHERE entity = ' . ((int) $conf->entity);
2363 }
2364 $sql .= " AND filepath = '".$db->escape($rel_dir)."'";
2365 if ($file) {
2366 $sql .= " AND filename = '".$db->escape($file)."'";
2367 }
2368 if ($mode) {
2369 $sql .= " AND gen_or_uploaded = '".$db->escape($mode)."'";
2370 }
2371
2372 $resql = $db->query($sql);
2373 if (!$resql) {
2374 $error++;
2375 dol_syslog(__FUNCTION__.' '.$db->lasterror(), LOG_ERR);
2376 }
2377 }
2378 }
2379
2380 // Commit or rollback
2381 if ($error) {
2382 $db->rollback();
2383 return -1 * $error;
2384 } else {
2385 $db->commit();
2386 return 1;
2387 }
2388}
2389
2390
2402function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '')
2403{
2404 if (class_exists('Imagick')) {
2405 $image = new Imagick();
2406 try {
2407 $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : '');
2408 //var_dump($filetoconvert);
2409 $ret = $image->readImage($filetoconvert);
2410 } catch (Exception $e) {
2411 $ext = pathinfo($fileinput, PATHINFO_EXTENSION);
2412 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);
2413 return 0;
2414 }
2415 if ($ret) {
2416 $ret = $image->setImageFormat($ext);
2417 if ($ret) {
2418 if (empty($fileoutput)) {
2419 $fileoutput = $fileinput.".".$ext;
2420 }
2421
2422 $count = $image->getNumberImages();
2423
2424 if (!dol_is_file($fileoutput) || is_writable($fileoutput)) {
2425 try {
2426 $ret = $image->writeImages($fileoutput, true);
2427 } catch (Exception $e) {
2428 dol_syslog($e->getMessage(), LOG_WARNING);
2429 }
2430 } else {
2431 dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR);
2432 }
2433 if ($ret) {
2434 return $count;
2435 } else {
2436 return -3;
2437 }
2438 } else {
2439 return -2;
2440 }
2441 } else {
2442 return -1;
2443 }
2444 } else {
2445 return 0;
2446 }
2447}
2448
2449
2461function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring = null)
2462{
2463 $foundhandler = 0;
2464 //var_dump(basename($inputfile)); exit;
2465
2466 try {
2467 dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile);
2468
2469 $data = implode("", file(dol_osencode($inputfile)));
2470 $compressdata = null;
2471 if ($mode == 'gz' && function_exists('gzencode')) {
2472 $foundhandler = 1;
2473 $compressdata = gzencode($data, 9);
2474 } elseif ($mode == 'bz' && function_exists('bzcompress')) {
2475 $foundhandler = 1;
2476 $compressdata = bzcompress($data, 9);
2477 } elseif ($mode == 'zstd' && function_exists('zstd_compress')) {
2478 $foundhandler = 1;
2479 $compressdata = zstd_compress($data, 9);
2480 } elseif ($mode == 'zip') {
2481 if (class_exists('ZipArchive') && getDolGlobalString('MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS')) {
2482 $foundhandler = 1;
2483
2484 $rootPath = realpath($inputfile);
2485
2486 dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath);
2487 $zip = new ZipArchive();
2488
2489 if ($zip->open($outputfile, ZipArchive::CREATE) !== true) {
2490 $errorstring = "dol_compress_file failure - Failed to open file ".$outputfile."\n";
2491 dol_syslog($errorstring, LOG_ERR);
2492
2493 global $errormsg;
2494 $errormsg = $errorstring;
2495
2496 return -6;
2497 }
2498
2499 // Create recursive directory iterator
2501 $files = new RecursiveIteratorIterator(
2502 new RecursiveDirectoryIterator($rootPath, FilesystemIterator::UNIX_PATHS),
2503 RecursiveIteratorIterator::LEAVES_ONLY
2504 );
2505 '@phan-var-force SplFileInfo[] $files';
2506
2507 foreach ($files as $name => $file) {
2508 // Skip directories (they would be added automatically)
2509 if (!$file->isDir()) {
2510 // Get real and relative path for current file
2511 $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2512 $fileName = $file->getFilename();
2513 $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2514
2515 //$relativePath = substr($fileFullRealPath, strlen($rootPath) + 1);
2516 $relativePath = substr(($filePath ? $filePath.'/' : '').$fileName, strlen($rootPath) + 1);
2517
2518 // Add current file to archive
2519 $zip->addFile($fileFullRealPath, $relativePath);
2520 }
2521 }
2522
2523 // Zip archive will be created only after closing object
2524 $zip->close();
2525
2526 dol_syslog("dol_compress_file success - ".$zip->numFiles." files");
2527 return 1;
2528 }
2529
2530 if (defined('ODTPHP_PATHTOPCLZIP')) {
2531 $foundhandler = 1;
2532
2533 include_once ODTPHP_PATHTOPCLZIP.'pclzip.lib.php';
2534 $archive = new PclZip($outputfile);
2535
2536 $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2537
2538 if ($result === 0) {
2539 global $errormsg;
2540 $errormsg = $archive->errorInfo(true);
2541
2542 if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) {
2543 $errorstring = "PCLZIP_ERR_WRITE_OPEN_FAIL";
2544 dol_syslog("dol_compress_file error - archive->errorCode() = PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR);
2545 return -4;
2546 }
2547
2548 $errorstring = "dol_compress_file error archive->errorCode = ".$archive->errorCode()." errormsg=".$errormsg;
2549 dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR);
2550 return -3;
2551 } else {
2552 dol_syslog("dol_compress_file success - ".count($result)." files");
2553 return 1;
2554 }
2555 }
2556 }
2557
2558 if ($foundhandler && is_string($compressdata)) {
2559 $fp = fopen($outputfile, "w");
2560 fwrite($fp, $compressdata);
2561 fclose($fp);
2562 return 1;
2563 } else {
2564 $errorstring = "Try to zip with format ".$mode." with no handler for this format";
2565 dol_syslog($errorstring, LOG_ERR);
2566
2567 global $errormsg;
2568 $errormsg = $errorstring;
2569 return -2;
2570 }
2571 } catch (Exception $e) {
2572 global $langs, $errormsg;
2573 $langs->load("errors");
2574 $errormsg = $langs->trans("ErrorFailedToWriteInDir");
2575
2576 $errorstring = "Failed to open file ".$outputfile;
2577 dol_syslog($errorstring, LOG_ERR);
2578 return -1;
2579 }
2580}
2581
2590function dol_uncompress($inputfile, $outputdir)
2591{
2592 global $langs, $db;
2593
2594 $fileinfo = pathinfo($inputfile);
2595 $fileinfo["extension"] = strtolower($fileinfo["extension"]);
2596
2597 if ($fileinfo["extension"] == "zip") {
2598 if (defined('ODTPHP_PATHTOPCLZIP') && !getDolGlobalString('MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS')) {
2599 dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
2600 include_once ODTPHP_PATHTOPCLZIP.'pclzip.lib.php';
2601 $archive = new PclZip($inputfile);
2602
2603 // We create output dir manually, so it uses the correct permission (When created by the archive->extract, dir is rwx for everybody).
2604 dol_mkdir(dol_sanitizePathName($outputdir));
2605
2606 try {
2607 // Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
2608 $result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
2609 } catch (Exception $e) {
2610 return array('error' => $e->getMessage());
2611 }
2612
2613 if (!is_array($result) && $result <= 0) {
2614 return array('error' => $archive->errorInfo(true));
2615 } else {
2616 $ok = 1;
2617 $errmsg = '';
2618 // Loop on each file to check result for unzipping file
2619 foreach ($result as $key => $val) {
2620 if ($val['status'] == 'path_creation_fail') {
2621 $langs->load("errors");
2622 $ok = 0;
2623 $errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
2624 break;
2625 }
2626 if ($val['status'] == 'write_protected') {
2627 $langs->load("errors");
2628 $ok = 0;
2629 $errmsg = $langs->trans("ErrorFailToCreateFile", $val['filename']);
2630 break;
2631 }
2632 }
2633
2634 if ($ok) {
2635 return array();
2636 } else {
2637 return array('error' => $errmsg);
2638 }
2639 }
2640 }
2641
2642 if (class_exists('ZipArchive')) { // Must install php-zip to have it
2643 dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
2644 $zip = new ZipArchive();
2645 $res = $zip->open($inputfile);
2646 if ($res === true) {
2647 //$zip->extractTo($outputdir.'/');
2648 // 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
2649 // python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
2650 // with -l is the range of dot to go back in path.
2651 // and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
2652 for ($i = 0; $i < $zip->numFiles; $i++) {
2653 if (preg_match('/\.\./', $zip->getNameIndex($i))) {
2654 dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
2655 continue; // Discard the file
2656 }
2657 $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
2658 }
2659
2660 $zip->close();
2661 return array();
2662 } else {
2663 return array('error' => 'ErrUnzipFails');
2664 }
2665 }
2666
2667 return array('error' => 'ErrNoZipEngine');
2668 } elseif (in_array($fileinfo["extension"], array('gz', 'bz2', 'zst'))) {
2669 include_once DOL_DOCUMENT_ROOT."/core/class/utils.class.php";
2670 $utils = new Utils($db);
2671
2672 dol_mkdir(dol_sanitizePathName($outputdir));
2673 $outputfilename = escapeshellcmd(dol_sanitizePathName($outputdir).'/'.dol_sanitizeFileName($fileinfo["filename"]));
2674 dol_delete_file($outputfilename.'.tmp');
2675 dol_delete_file($outputfilename.'.err');
2676
2677 $extension = strtolower(pathinfo($fileinfo["filename"], PATHINFO_EXTENSION));
2678 if ($extension == "tar") {
2679 $cmd = 'tar -C '.escapeshellcmd(dol_sanitizePathName($outputdir)).' -xvf '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2680
2681 $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, $outputfilename.'.err', 0);
2682 if ($resarray["result"] != 0) {
2683 $resarray["error"] .= file_get_contents($outputfilename.'.err');
2684 }
2685 } else {
2686 $program = "";
2687 if ($fileinfo["extension"] == "gz") {
2688 $program = 'gzip';
2689 } elseif ($fileinfo["extension"] == "bz2") {
2690 $program = 'bzip2';
2691 } elseif ($fileinfo["extension"] == "zst") {
2692 $program = 'zstd';
2693 } else {
2694 return array('error' => 'ErrorBadFileExtension');
2695 }
2696 $cmd = $program.' -dc '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2697 $cmd .= ' > '.$outputfilename;
2698
2699 $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, null, 1, $outputfilename.'.err');
2700 if ($resarray["result"] != 0) {
2701 $errfilecontent = @file_get_contents($outputfilename.'.err');
2702 if ($errfilecontent) {
2703 $resarray["error"] .= " - ".$errfilecontent;
2704 }
2705 }
2706 }
2707 return $resarray["result"] != 0 ? array('error' => $resarray["error"]) : array();
2708 }
2709
2710 return array('error' => 'ErrorBadFileExtension');
2711}
2712
2713
2726function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '', $rootdirinzip = '', $newmask = '0')
2727{
2728 $foundhandler = 0;
2729
2730 dol_syslog("Try to zip dir ".$inputdir." into ".$outputfile." mode=".$mode);
2731
2732 if (!dol_is_dir(dirname($outputfile)) || !is_writable(dirname($outputfile))) {
2733 global $langs, $errormsg;
2734 $langs->load("errors");
2735 $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile);
2736 return -3;
2737 }
2738
2739 try {
2740 if ($mode == 'gz') {
2741 $foundhandler = 0;
2742 } elseif ($mode == 'bz') {
2743 $foundhandler = 0;
2744 } elseif ($mode == 'zip') {
2745 /*if (defined('ODTPHP_PATHTOPCLZIP'))
2746 {
2747 $foundhandler=0; // TODO implement this
2748
2749 include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2750 $archive = new PclZip($outputfile);
2751 $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2752 //$archive->add($inputfile);
2753 return 1;
2754 }
2755 else*/
2756 //if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS))
2757
2758 if (class_exists('ZipArchive')) {
2759 $foundhandler = 1;
2760
2761 // Initialize archive object
2762 $zip = new ZipArchive();
2763 $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
2764 if ($result !== true) {
2765 global $langs, $errormsg;
2766 $langs->load("errors");
2767 $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile);
2768 return -4;
2769 }
2770
2771 // Create recursive directory iterator
2772 // This does not return symbolic links
2774 $files = new RecursiveIteratorIterator(
2775 new RecursiveDirectoryIterator($inputdir, FilesystemIterator::UNIX_PATHS),
2776 RecursiveIteratorIterator::LEAVES_ONLY
2777 );
2778 '@phan-var-force SplFileInfo[] $files';
2779
2780 //var_dump($inputdir);
2781 foreach ($files as $name => $file) {
2782 // Skip directories (they would be added automatically)
2783 if (!$file->isDir()) {
2784 // Get real and relative path for current file
2785 $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2786 $fileName = $file->getFilename();
2787 $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2788
2789 //$relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($fileFullRealPath, strlen($inputdir) + 1);
2790 $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr(($filePath ? $filePath.'/' : '').$fileName, strlen($inputdir) + 1);
2791
2792 //var_dump($filePath);var_dump($fileFullRealPath);var_dump($relativePath);
2793 if (empty($excludefiles) || !preg_match($excludefiles, $fileFullRealPath)) {
2794 // Add current file to archive
2795 $zip->addFile($fileFullRealPath, $relativePath);
2796 }
2797 }
2798 }
2799
2800 // Zip archive will be created only after closing object
2801 $zip->close();
2802
2803 if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
2804 $newmask = getDolGlobalString('MAIN_UMASK');
2805 }
2806 if (empty($newmask)) { // This should no happen
2807 dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
2808 $newmask = '0664';
2809 }
2810
2811 dolChmod($outputfile, $newmask);
2812
2813 return 1;
2814 }
2815 }
2816
2817 if (!$foundhandler) {
2818 dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR);
2819 return -2;
2820 } else {
2821 return 0;
2822 }
2823 } catch (Exception $e) {
2824 global $langs, $errormsg;
2825 $langs->load("errors");
2826 dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
2827 dol_syslog($e->getMessage(), LOG_ERR);
2828 $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile).' - '.$e->getMessage();
2829 return -1;
2830 }
2831}
2832
2833
2834
2845function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$', '^\.'), $nohook = 0, $mode = 0)
2846{
2847 $tmparray = dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook);
2848 return isset($tmparray[0]) ? $tmparray[0] : null;
2849}
2850
2864function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = null, $refname = '', $mode = 'read')
2865{
2866 global $conf, $db, $user, $hookmanager;
2867 global $dolibarr_main_data_root, $dolibarr_main_document_root_alt;
2868 global $object;
2869
2870 if (!is_object($fuser)) {
2871 $fuser = $user;
2872 }
2873
2874 if (empty($modulepart)) {
2875 return 'ErrorBadParameter';
2876 }
2877 if (empty($entity)) {
2878 if (!isModEnabled('multicompany')) {
2879 $entity = 1;
2880 } else {
2881 $entity = 0;
2882 }
2883 }
2884 // Fix modulepart for backward compatibility
2885 if ($modulepart == 'facture') {
2886 $modulepart = 'invoice';
2887 } elseif ($modulepart == 'users') {
2888 $modulepart = 'user';
2889 } elseif ($modulepart == 'tva') {
2890 $modulepart = 'tax-vat';
2891 } elseif ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) {
2892 // Fix modulepart delivery
2893 $modulepart = 'delivery';
2894 } elseif ($modulepart == 'propale') {
2895 $modulepart = 'propal';
2896 }
2897
2898 //print 'dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity;
2899 dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
2900
2901 // We define $accessallowed and $sqlprotectagainstexternals
2902 $accessallowed = 0;
2903 $sqlprotectagainstexternals = '';
2904 $ret = array();
2905
2906 // Find the subdirectory name as the reference. For example original_file='10/myfile.pdf' -> refname='10'
2907 if (empty($refname)) {
2908 $refname = basename(dirname($original_file)."/");
2909 if ($refname == 'thumbs' || $refname == 'temp') {
2910 // If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10'
2911 $refname = basename(dirname(dirname($original_file))."/");
2912 }
2913 }
2914
2915 // Define possible keys to use for permission check
2916 $lire = 'lire';
2917 $read = 'read';
2918 $download = 'download';
2919 if ($mode == 'write') {
2920 $lire = 'creer';
2921 $read = 'write';
2922 $download = 'upload';
2923 }
2924
2925 // Wrapping for miscellaneous medias files
2926 if ($modulepart == 'common') {
2927 // Wrapping for some images
2928 $accessallowed = 1;
2929 $original_file = DOL_DOCUMENT_ROOT.'/public/theme/common/'.$original_file;
2930 } elseif ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) {
2931 /* the medias directory is by default a public directory accessible online for everybody, so test on permission per entity has no sense
2932 if (isModEnabled('multicompany') && (empty($entity) || empty($conf->medias->multidir_output[$entity]))) {
2933 return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
2934 } */
2935 if (empty($entity)) {
2936 $entity = 1;
2937 }
2938 $accessallowed = 1;
2939 $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;
2940 } elseif ($modulepart == 'logs' && !empty($dolibarr_main_data_root)) {
2941 // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
2942 $accessallowed = ($user->admin && basename($original_file) == $original_file && preg_match('/^dolibarr.*\.(log|json)$/', basename($original_file)));
2943 $original_file = $dolibarr_main_data_root.'/'.$original_file;
2944 } elseif ($modulepart == 'doctemplates' && !empty($dolibarr_main_data_root)) {
2945 // Wrapping for doctemplates
2946 $accessallowed = $user->admin;
2947 $original_file = $dolibarr_main_data_root.'/doctemplates/'.$original_file;
2948 } elseif ($modulepart == 'doctemplateswebsite' && !empty($dolibarr_main_data_root)) {
2949 // Wrapping for doctemplates of websites
2950 $accessallowed = ($fuser->hasRight('website', 'write') && preg_match('/\.jpg$/i', basename($original_file)));
2951 $original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file;
2952 } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) { // To download zip of modules
2953 // Wrapping for *.zip package files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
2954 // Dir for custom dirs
2955 $tmp = explode(',', $dolibarr_main_document_root_alt);
2956 $dirins = $tmp[0];
2957
2958 $accessallowed = ($user->admin && preg_match('/^module_.*\.zip$/', basename($original_file)));
2959 $original_file = $dirins.'/'.$original_file;
2960 } elseif ($modulepart == 'mycompany' && !empty($conf->mycompany->dir_output)) {
2961 // Wrapping for some images
2962 $accessallowed = 1;
2963 $original_file = $conf->mycompany->dir_output.'/'.$original_file;
2964 } elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output)) {
2965 // Wrapping for users photos (user photos are allowed to any connected users)
2966 $accessallowed = 0;
2967 if (preg_match('/^\d+\/photos\//', $original_file)) {
2968 $accessallowed = 1;
2969 }
2970 $original_file = $conf->user->dir_output.'/'.$original_file;
2971 } elseif ($modulepart == 'userphotopublic' && !empty($conf->user->dir_output)) {
2972 // Wrapping for users photos that were set to public (for virtual credit card) by their owner (public user photos can be read
2973 // with the public link and securekey)
2974 $accessok = false;
2975 $reg = array();
2976 if (preg_match('/^(\d+)\/photos\//', $original_file, $reg)) {
2977 if ($reg[1]) {
2978 $tmpobject = new User($db);
2979 $tmpobject->fetch($reg[1], '', '', 1);
2980 if (getDolUserInt('USER_ENABLE_PUBLIC', 0, $tmpobject)) {
2981 $securekey = GETPOST('securekey', 'alpha', 1);
2982 // Security check
2983 global $dolibarr_main_cookie_cryptkey, $dolibarr_main_instance_unique_id;
2984 $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
2985 $encodedsecurekey = dol_hash($valuetouse.'uservirtualcard'.$tmpobject->id.'-'.$tmpobject->login, 'md5');
2986 if ($encodedsecurekey == $securekey) {
2987 $accessok = true;
2988 }
2989 }
2990 }
2991 }
2992 if ($accessok) {
2993 $accessallowed = 1;
2994 }
2995 $original_file = $conf->user->dir_output.'/'.$original_file;
2996 } elseif (($modulepart == 'companylogo') && !empty($conf->mycompany->dir_output)) {
2997 // Wrapping for company logos (company logos are allowed to anyboby, they are public)
2998 $accessallowed = 1;
2999 $original_file = $conf->mycompany->dir_output.'/logos/'.$original_file;
3000 } elseif ($modulepart == 'memberphoto' && !empty($conf->member->dir_output)) {
3001 // Wrapping for members photos
3002 $accessallowed = 0;
3003 if (preg_match('/^\d+\/photos\//', $original_file)) {
3004 $accessallowed = 1;
3005 }
3006 $original_file = $conf->member->dir_output.'/'.$original_file;
3007 } elseif ($modulepart == 'apercufacture' && !empty($conf->invoice->multidir_output[$entity])) {
3008 // Wrapping for invoices (user need permission to read invoices)
3009 if ($fuser->hasRight('facture', $lire)) {
3010 $accessallowed = 1;
3011 }
3012 $original_file = $conf->invoice->multidir_output[$entity].'/'.$original_file;
3013 } elseif ($modulepart == 'apercupropal' && !empty($conf->propal->multidir_output[$entity])) {
3014 // Wrapping pour les apercu propal
3015 if ($fuser->hasRight('propal', $lire)) {
3016 $accessallowed = 1;
3017 }
3018 $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
3019 } elseif ($modulepart == 'apercucommande' && !empty($conf->order->multidir_output[$entity])) {
3020 // Wrapping pour les apercu commande
3021 if ($fuser->hasRight('commande', $lire)) {
3022 $accessallowed = 1;
3023 }
3024 $original_file = $conf->order->multidir_output[$entity].'/'.$original_file;
3025 } elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output)) {
3026 // Wrapping pour les apercu intervention
3027 if ($fuser->hasRight('ficheinter', $lire)) {
3028 $accessallowed = 1;
3029 }
3030 $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
3031 } elseif (($modulepart == 'apercucontract') && !empty($conf->contract->multidir_output[$entity])) {
3032 // Wrapping pour les apercu contrat
3033 if ($fuser->hasRight('contrat', $lire)) {
3034 $accessallowed = 1;
3035 }
3036 $original_file = $conf->contract->multidir_output[$entity].'/'.$original_file;
3037 } elseif (($modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output)) {
3038 // Wrapping pour les apercu supplier proposal
3039 if ($fuser->hasRight('supplier_proposal', $lire)) {
3040 $accessallowed = 1;
3041 }
3042 $original_file = $conf->supplier_proposal->dir_output.'/'.$original_file;
3043 } elseif (($modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output)) {
3044 // Wrapping pour les apercu supplier order
3045 if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
3046 $accessallowed = 1;
3047 }
3048 $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
3049 } elseif (($modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output)) {
3050 // Wrapping pour les apercu supplier invoice
3051 if ($fuser->hasRight('fournisseur', $lire)) {
3052 $accessallowed = 1;
3053 }
3054 $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
3055 } elseif (($modulepart == 'holiday') && !empty($conf->holiday->dir_output)) {
3056 if ($fuser->hasRight('holiday', $read) || $fuser->hasRight('holiday', 'readall') || preg_match('/^specimen/i', $original_file)) {
3057 $accessallowed = 1;
3058 // If we known $id of holiday, call checkUserAccessToObject to check permission on properties and hierarchy of leave request
3059 if ($refname && !$fuser->hasRight('holiday', 'readall') && !preg_match('/^specimen/i', $original_file)) {
3060 include_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
3061 $tmpholiday = new Holiday($db);
3062 $tmpholiday->fetch(0, $refname);
3063 $accessallowed = checkUserAccessToObject($user, array('holiday'), $tmpholiday, 'holiday', '', '', 'rowid', '');
3064 }
3065 }
3066 $original_file = $conf->holiday->dir_output.'/'.$original_file;
3067 } elseif (($modulepart == 'expensereport') && !empty($conf->expensereport->dir_output)) {
3068 if ($fuser->hasRight('expensereport', $lire) || $fuser->hasRight('expensereport', 'readall') || preg_match('/^specimen/i', $original_file)) {
3069 $accessallowed = 1;
3070 // If we known $id of expensereport, call checkUserAccessToObject to check permission on properties and hierarchy of expense report
3071 if ($refname && !$fuser->hasRight('expensereport', 'readall') && !preg_match('/^specimen/i', $original_file)) {
3072 include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
3073 $tmpexpensereport = new ExpenseReport($db);
3074 $tmpexpensereport->fetch(0, $refname);
3075 $accessallowed = checkUserAccessToObject($user, array('expensereport'), $tmpexpensereport, 'expensereport', '', '', 'rowid', '');
3076 }
3077 }
3078 $original_file = $conf->expensereport->dir_output.'/'.$original_file;
3079 } elseif (($modulepart == 'apercuexpensereport') && !empty($conf->expensereport->dir_output)) {
3080 // Wrapping pour les apercu expense report
3081 if ($fuser->hasRight('expensereport', $lire)) {
3082 $accessallowed = 1;
3083 }
3084 $original_file = $conf->expensereport->dir_output.'/'.$original_file;
3085 } elseif ($modulepart == 'propalstats' && !empty($conf->propal->multidir_temp[$entity])) {
3086 // Wrapping pour les images des stats propales
3087 if ($fuser->hasRight('propal', $lire)) {
3088 $accessallowed = 1;
3089 }
3090 $original_file = $conf->propal->multidir_temp[$entity].'/'.$original_file;
3091 } elseif ($modulepart == 'orderstats' && !empty($conf->order->dir_temp)) {
3092 // Wrapping pour les images des stats commandes
3093 if ($fuser->hasRight('commande', $lire)) {
3094 $accessallowed = 1;
3095 }
3096 $original_file = $conf->order->dir_temp.'/'.$original_file;
3097 } elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output)) {
3098 if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
3099 $accessallowed = 1;
3100 }
3101 $original_file = $conf->fournisseur->commande->dir_temp.'/'.$original_file;
3102 } elseif ($modulepart == 'billstats' && !empty($conf->invoice->dir_temp)) {
3103 // Wrapping pour les images des stats factures
3104 if ($fuser->hasRight('facture', $lire)) {
3105 $accessallowed = 1;
3106 }
3107 $original_file = $conf->invoice->dir_temp.'/'.$original_file;
3108 } elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output)) {
3109 if ($fuser->hasRight('fournisseur', 'facture', $lire)) {
3110 $accessallowed = 1;
3111 }
3112 $original_file = $conf->fournisseur->facture->dir_temp.'/'.$original_file;
3113 } elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp)) {
3114 // Wrapping pour les images des stats expeditions
3115 if ($fuser->hasRight('expedition', $lire)) {
3116 $accessallowed = 1;
3117 }
3118 $original_file = $conf->expedition->dir_temp.'/'.$original_file;
3119 } elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp)) {
3120 // Wrapping pour les images des stats expeditions
3121 if ($fuser->hasRight('deplacement', $lire)) {
3122 $accessallowed = 1;
3123 }
3124 $original_file = $conf->deplacement->dir_temp.'/'.$original_file;
3125 } elseif ($modulepart == 'memberstats' && !empty($conf->member->dir_temp)) {
3126 // Wrapping pour les images des stats expeditions
3127 if ($fuser->hasRight('adherent', $lire)) {
3128 $accessallowed = 1;
3129 }
3130 $original_file = $conf->member->dir_temp.'/'.$original_file;
3131 } elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) {
3132 // Wrapping pour les images des stats produits
3133 if ($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) {
3134 $accessallowed = 1;
3135 }
3136 $original_file = (!empty($conf->product->multidir_temp[$entity]) ? $conf->product->multidir_temp[$entity] : $conf->service->multidir_temp[$entity]).'/'.$original_file;
3137 } elseif (in_array($modulepart, array('tax', 'tax-vat', 'tva')) && !empty($conf->tax->dir_output)) {
3138 // Wrapping for taxes
3139 if ($fuser->hasRight('tax', 'charges', $lire)) {
3140 $accessallowed = 1;
3141 }
3142 $modulepartsuffix = str_replace('tax-', '', $modulepart);
3143 $original_file = $conf->tax->dir_output.'/'.($modulepartsuffix != 'tax' ? $modulepartsuffix.'/' : '').$original_file;
3144 } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
3145 // Wrapping for events
3146 if ($fuser->hasRight('agenda', 'myactions', $read)) {
3147 $accessallowed = 1;
3148 // If we known $id of project, call checkUserAccessToObject to check permission on the given agenda event on properties and assigned users
3149 if ($refname && !preg_match('/^specimen/i', $original_file)) {
3150 include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
3151 $tmpobject = new ActionComm($db);
3152 $tmpobject->fetch((int) $refname);
3153 $accessallowed = checkUserAccessToObject($user, array('agenda'), $tmpobject->id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id', '');
3154 if ($user->socid && $tmpobject->socid) {
3155 $accessallowed = checkUserAccessToObject($user, array('societe'), $tmpobject->socid);
3156 }
3157 }
3158 }
3159 $original_file = $conf->agenda->dir_output.'/'.$original_file;
3160 } elseif ($modulepart == 'category' && !empty($conf->categorie->multidir_output[$entity])) {
3161 // Wrapping for categories (categories are allowed if user has permission to read categories or to work on TakePos)
3162 if (empty($entity) || empty($conf->categorie->multidir_output[$entity])) {
3163 return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3164 }
3165 if ($fuser->hasRight("categorie", $lire) || $fuser->hasRight("takepos", "run")) {
3166 $accessallowed = 1;
3167 }
3168 $original_file = $conf->categorie->multidir_output[$entity].'/'.$original_file;
3169 } elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) {
3170 // Wrapping pour les prelevements
3171 if ($fuser->hasRight('prelevement', 'bons', $lire) || preg_match('/^specimen/i', $original_file)) {
3172 $accessallowed = 1;
3173 }
3174 $original_file = $conf->prelevement->dir_output.'/'.$original_file;
3175 } elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp)) {
3176 // Wrapping pour les graph energie
3177 $accessallowed = 1;
3178 $original_file = $conf->stock->dir_temp.'/'.$original_file;
3179 } elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp)) {
3180 // Wrapping pour les graph fournisseurs
3181 $accessallowed = 1;
3182 $original_file = $conf->fournisseur->dir_temp.'/'.$original_file;
3183 } elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp)) {
3184 // Wrapping pour les graph des produits
3185 $accessallowed = 1;
3186 $original_file = $conf->product->multidir_temp[$entity].'/'.$original_file;
3187 } elseif ($modulepart == 'barcode') {
3188 // Wrapping pour les code barre
3189 $accessallowed = 1;
3190 // If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
3191 //$original_file=$conf->barcode->dir_temp.'/'.$original_file;
3192 $original_file = '';
3193 } elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp)) {
3194 // Wrapping for icon of background of mailings
3195 $accessallowed = 1;
3196 $original_file = $conf->mailing->dir_temp.'/'.$original_file;
3197 } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
3198 // Wrapping pour le scanner
3199 $accessallowed = 1;
3200 $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
3201 } elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output)) {
3202 // Wrapping pour les images fckeditor
3203 $accessallowed = 1;
3204 $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
3205 } elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) {
3206 // Wrapping for users
3207 $canreaduser = (!empty($fuser->admin) || $fuser->hasRight('user', 'user', $lire));
3208 if ($fuser->id == (int) $refname) {
3209 $canreaduser = 1;
3210 } // A user can always read its own card
3211 if ($canreaduser || preg_match('/^specimen/i', $original_file)) {
3212 $accessallowed = 1;
3213 }
3214 $original_file = $conf->user->dir_output.'/'.$original_file;
3215 } elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->multidir_output[$entity])) {
3216 // Wrapping for third parties
3217 if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
3218 return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3219 }
3220 if ($fuser->hasRight('societe', $lire) || preg_match('/^specimen/i', $original_file)) {
3221 $accessallowed = 1;
3222 }
3223 $original_file = $conf->societe->multidir_output[$entity].'/'.$original_file;
3224 $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe').")";
3225 } elseif ($modulepart == 'contact' && !empty($conf->societe->multidir_output[$entity])) {
3226 // Wrapping for contact
3227 if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
3228 return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3229 }
3230 if ($fuser->hasRight('societe', $lire)) {
3231 $accessallowed = 1;
3232 }
3233 $original_file = $conf->societe->multidir_output[$entity].'/contact/'.$original_file;
3234 } elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->invoice->multidir_output[$entity])) {
3235 // Wrapping for invoices
3236 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3237 $accessallowed = 1;
3238 }
3239 $original_file = $conf->invoice->multidir_output[$entity].'/'.$original_file;
3240 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('invoice').")";
3241 } elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) {
3242 // Wrapping for mass actions
3243 if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
3244 $accessallowed = 1;
3245 }
3246 $original_file = $conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
3247 } elseif ($modulepart == 'massfilesarea_orders') {
3248 if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3249 $accessallowed = 1;
3250 }
3251 $original_file = $conf->order->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
3252 } elseif ($modulepart == 'massfilesarea_sendings') {
3253 if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
3254 $accessallowed = 1;
3255 }
3256 $original_file = $conf->expedition->dir_output.'/sending/temp/massgeneration/'.$user->id.'/'.$original_file;
3257 } elseif ($modulepart == 'massfilesarea_receipts') {
3258 if ($fuser->hasRight('reception', $lire) || preg_match('/^specimen/i', $original_file)) {
3259 $accessallowed = 1;
3260 }
3261 $original_file = $conf->reception->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3262 } elseif ($modulepart == 'massfilesarea_invoices') {
3263 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3264 $accessallowed = 1;
3265 }
3266 $original_file = $conf->invoice->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
3267 } elseif ($modulepart == 'massfilesarea_expensereport') {
3268 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3269 $accessallowed = 1;
3270 }
3271 $original_file = $conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3272 } elseif ($modulepart == 'massfilesarea_interventions') {
3273 if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
3274 $accessallowed = 1;
3275 }
3276 $original_file = $conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3277 } elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) {
3278 if ($fuser->hasRight('supplier_proposal', $lire) || preg_match('/^specimen/i', $original_file)) {
3279 $accessallowed = 1;
3280 }
3281 $original_file = $conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3282 } elseif ($modulepart == 'massfilesarea_supplier_order') {
3283 if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3284 $accessallowed = 1;
3285 }
3286 $original_file = $conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3287 } elseif ($modulepart == 'massfilesarea_supplier_invoice') {
3288 if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3289 $accessallowed = 1;
3290 }
3291 $original_file = $conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3292 } elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contract->dir_output)) {
3293 if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
3294 $accessallowed = 1;
3295 }
3296 $original_file = $conf->contract->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3297 } elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) {
3298 // Wrapping for interventions
3299 if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
3300 $accessallowed = 1;
3301 }
3302 $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
3303 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3304 } elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) {
3305 // Wrapping pour les deplacements et notes de frais
3306 if ($fuser->hasRight('deplacement', $lire) || preg_match('/^specimen/i', $original_file)) {
3307 $accessallowed = 1;
3308 }
3309 $original_file = $conf->deplacement->dir_output.'/'.$original_file;
3310 //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3311 } elseif (($modulepart == 'propal' || $modulepart == 'propale') && isset($conf->propal->multidir_output[$entity])) {
3312 // Wrapping pour les propales
3313 if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
3314 $accessallowed = 1;
3315 }
3316 $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
3317 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('propal').")";
3318 } elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->order->multidir_output[$entity])) {
3319 // Wrapping pour les commandes
3320 if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3321 $accessallowed = 1;
3322 }
3323 $original_file = $conf->order->multidir_output[$entity].'/'.$original_file;
3324 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")";
3325 } elseif ($modulepart == 'project' && !empty($conf->project->multidir_output[$entity])) {
3326 // Wrapping pour les projects
3327 if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3328 $accessallowed = 1;
3329 // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3330 if ($refname && !preg_match('/^specimen/i', $original_file)) {
3331 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
3332 $tmpproject = new Project($db);
3333 $tmpproject->fetch(0, $refname);
3334 $accessallowed = checkUserAccessToObject($user, array('projet'), $tmpproject->id, 'projet&project', '', '', 'rowid', '');
3335 }
3336 }
3337 $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3338 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3339 } elseif ($modulepart == 'project_task' && !empty($conf->project->multidir_output[$entity])) {
3340 if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3341 $accessallowed = 1;
3342 // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3343 if ($refname && !preg_match('/^specimen/i', $original_file)) {
3344 include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
3345 $tmptask = new Task($db);
3346 $tmptask->fetch(0, $refname);
3347 $accessallowed = checkUserAccessToObject($user, array('projet_task'), $tmptask->id, 'projet_task&project', '', '', 'rowid', '');
3348 }
3349 }
3350 $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3351 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3352 } elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) {
3353 // Wrapping pour les commandes fournisseurs
3354 if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3355 $accessallowed = 1;
3356 }
3357 $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
3358 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3359 } elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) {
3360 // Wrapping pour les factures fournisseurs
3361 if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3362 $accessallowed = 1;
3363 }
3364 $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
3365 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3366 } elseif ($modulepart == 'supplier_payment') {
3367 // Wrapping pour les rapport de paiements
3368 if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3369 $accessallowed = 1;
3370 }
3371 $original_file = $conf->fournisseur->payment->dir_output.'/'.$original_file;
3372 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3373 } elseif ($modulepart == 'payment') {
3374 // Wrapping pour les rapport de paiements
3375 if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) {
3376 $accessallowed = 1;
3377 }
3378 $original_file = $conf->compta->payment->dir_output.'/'.$original_file;
3379 } elseif ($modulepart == 'facture_paiement' && !empty($conf->invoice->dir_output)) {
3380 // Wrapping pour les rapport de paiements
3381 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3382 $accessallowed = 1;
3383 }
3384 if ($fuser->socid > 0) {
3385 $original_file = $conf->invoice->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file;
3386 } else {
3387 $original_file = $conf->invoice->dir_output.'/payments/'.$original_file;
3388 }
3389 } elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) {
3390 // Wrapping for accounting exports
3391 if ($fuser->hasRight('accounting', 'bind', 'write') || preg_match('/^specimen/i', $original_file)) {
3392 $accessallowed = 1;
3393 }
3394 $original_file = $conf->accounting->dir_output.'/'.$original_file;
3395 } elseif (($modulepart == 'expedition' || $modulepart == 'shipment') && !empty($conf->expedition->dir_output)) {
3396 // Wrapping pour les expedition
3397 if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
3398 $accessallowed = 1;
3399 }
3400 $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'sending/') === 0 ? '' : 'sending/').$original_file;
3401 //$original_file = $conf->expedition->dir_output."/".$original_file;
3402 } elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output)) {
3403 // Delivery Note Wrapping
3404 if ($fuser->hasRight('expedition', 'delivery', $lire) || preg_match('/^specimen/i', $original_file)) {
3405 $accessallowed = 1;
3406 }
3407 $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'receipt/') === 0 ? '' : 'receipt/').$original_file;
3408 } elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) {
3409 // Wrapping pour les actions
3410 if ($fuser->hasRight('agenda', 'allactions', $read) || preg_match('/^specimen/i', $original_file)) {
3411 $accessallowed = 1;
3412 }
3413 $original_file = $conf->agenda->dir_temp."/".$original_file;
3414 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
3415 // Wrapping pour les produits et services
3416 if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) {
3417 return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3418 }
3419 if (($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) || preg_match('/^specimen/i', $original_file)) {
3420 $accessallowed = 1;
3421 }
3422 if (isModEnabled("product")) {
3423 $original_file = $conf->product->multidir_output[$entity].'/'.$original_file;
3424 } elseif (isModEnabled("service")) {
3425 $original_file = $conf->service->multidir_output[$entity].'/'.$original_file;
3426 }
3427 } elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') {
3428 // Wrapping pour les lots produits
3429 if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) {
3430 return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3431 }
3432 if (($fuser->hasRight('produit', $lire)) || preg_match('/^specimen/i', $original_file)) {
3433 $accessallowed = 1;
3434 }
3435 if (isModEnabled('productbatch')) {
3436 $original_file = $conf->productbatch->multidir_output[$entity].'/'.$original_file;
3437 }
3438 } elseif ($modulepart == 'movement' || $modulepart == 'mouvement') {
3439 // Wrapping for stock movements
3440 if (empty($entity) || empty($conf->stock->multidir_output[$entity])) {
3441 return array('accessallowed' => 0, 'error' => 'Value entity must be provided');
3442 }
3443 if (($fuser->hasRight('stock', $lire) || $fuser->hasRight('stock', 'movement', $lire) || $fuser->hasRight('stock', 'mouvement', $lire)) || preg_match('/^specimen/i', $original_file)) {
3444 $accessallowed = 1;
3445 }
3446 if (isModEnabled('stock')) {
3447 $original_file = $conf->stock->multidir_output[$entity].'/movement/'.$original_file;
3448 }
3449 } elseif ($modulepart == 'contract' && !empty($conf->contract->multidir_output[$entity])) {
3450 // Wrapping pour les contrats
3451 if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
3452 $accessallowed = 1;
3453 }
3454 $original_file = $conf->contract->multidir_output[$entity].'/'.$original_file;
3455 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract').")";
3456 } elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) {
3457 // Wrapping pour les dons
3458 if ($fuser->hasRight('don', $lire) || preg_match('/^specimen/i', $original_file)) {
3459 $accessallowed = 1;
3460 }
3461 $original_file = $conf->don->dir_output.'/'.$original_file;
3462 } elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) {
3463 // Wrapping pour les dons
3464 if ($fuser->hasRight('resource', $read) || preg_match('/^specimen/i', $original_file)) {
3465 $accessallowed = 1;
3466 }
3467 $original_file = $conf->resource->dir_output.'/'.$original_file;
3468 } elseif (($modulepart == 'remisecheque' || $modulepart == 'chequereceipt') && !empty($conf->bank->dir_output)) {
3469 // Wrapping pour les remises de cheques
3470 if ($fuser->hasRight('banque', $lire) || preg_match('/^specimen/i', $original_file)) {
3471 $accessallowed = 1;
3472 }
3473 $original_file = $conf->bank->dir_output.'/checkdeposits/'.$original_file; // original_file should contains relative path so include the get_exdir result
3474 } elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) {
3475 // Wrapping for bank
3476 if ($fuser->hasRight('banque', $lire)) {
3477 $accessallowed = 1;
3478 }
3479 $original_file = $conf->bank->dir_output.'/'.$original_file;
3480 } elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) {
3481 // Wrapping for export module
3482 // Note that a test may not be required because we force the dir of download on the directory of the user that export
3483 $accessallowed = $user->hasRight('export', 'lire');
3484 $original_file = $conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file;
3485 } elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) {
3486 // Wrapping for import module
3487 $accessallowed = $user->hasRight('import', 'run');
3488 $original_file = $conf->import->dir_temp.'/'.$original_file;
3489 } elseif ($modulepart == 'recruitment' && !empty($conf->recruitment->dir_output)) {
3490 // Wrapping for recruitment module
3491 $accessallowed = $user->hasRight('recruitment', 'recruitmentjobposition', 'read');
3492 $original_file = $conf->recruitment->dir_output.'/'.$original_file;
3493 } elseif ($modulepart == 'hrm' && !empty($conf->hrm->dir_output)) {
3494 // Wrapping for hrm module
3495 $accessallowed = $user->hasRight('hrm', 'all', 'read');
3496 $original_file = $conf->hrm->dir_output.'/'.$original_file;
3497 } elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) {
3498 // Wrapping for wysiwyg editor
3499 $accessallowed = 1;
3500 $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
3501 } elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) {
3502 // Wrapping for backups
3503 if ($fuser->admin) {
3504 $accessallowed = 1;
3505 }
3506 $original_file = $conf->admin->dir_output.'/'.$original_file;
3507 } elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) {
3508 // Wrapping for upload file test
3509 if ($fuser->admin) {
3510 $accessallowed = 1;
3511 }
3512 $original_file = $conf->admin->dir_temp.'/'.$original_file;
3513 } elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) {
3514 // Wrapping pour BitTorrent
3515 $accessallowed = 1;
3516 $dir = 'files';
3517 if (dol_mimetype($original_file) == 'application/x-bittorrent') {
3518 $dir = 'torrents';
3519 }
3520 $original_file = $conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
3521 } elseif ($modulepart == 'member' && !empty($conf->member->dir_output)) {
3522 // Wrapping pour Foundation module
3523 if ($fuser->hasRight('adherent', $lire) || preg_match('/^specimen/i', $original_file)) {
3524 $accessallowed = 1;
3525 }
3526 $original_file = $conf->member->dir_output.'/'.$original_file;
3527 // If modulepart=module_user_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser
3528 // If modulepart=module_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp
3529 // If modulepart=module_user Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser
3530 // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3531 // If modulepart=module-abc Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3532 } else {
3533 // GENERIC Wrapping
3534 //var_dump($modulepart);
3535 //var_dump($original_file);
3536 if (preg_match('/^specimen/i', $original_file)) {
3537 $accessallowed = 1; // If link to a file called specimen. Test must be done before changing $original_file int full path.
3538 }
3539 if ($fuser->admin) {
3540 $accessallowed = 1; // If user is admin
3541 }
3542
3543 $tmpmodulepart = explode('-', $modulepart);
3544 if (!empty($tmpmodulepart[1])) {
3545 $modulepart = $tmpmodulepart[0];
3546 $original_file = $tmpmodulepart[1].'/'.$original_file;
3547 }
3548
3549 // Define $accessallowed
3550 $reg = array();
3551 if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) {
3552 $tmpmodule = $reg[1];
3553 if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3554 dol_print_error(null, 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3555 exit;
3556 }
3557 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3558 $accessallowed = 1;
3559 }
3560 $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
3561 } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) {
3562 $tmpmodule = $reg[1];
3563 if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3564 dol_print_error(null, 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3565 exit;
3566 }
3567 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3568 $accessallowed = 1;
3569 }
3570 $original_file = $conf->$tmpmodule->dir_temp.'/'.$original_file;
3571 } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) {
3572 $tmpmodule = $reg[1];
3573 if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3574 dol_print_error(null, 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3575 exit;
3576 }
3577 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3578 $accessallowed = 1;
3579 }
3580 $original_file = $conf->$tmpmodule->dir_output.'/'.$fuser->id.'/'.$original_file;
3581 } elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) {
3582 $tmpmodule = $reg[1];
3583 if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3584 dol_print_error(null, 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3585 exit;
3586 }
3587 if ($fuser->hasRight($tmpmodule, $lire) || preg_match('/^specimen/i', $original_file)) {
3588 $accessallowed = 1;
3589 }
3590 $original_file = $conf->$tmpmodule->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3591 } else {
3592 if (empty($conf->$modulepart->dir_output)) { // modulepart not supported
3593 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.');
3594 exit;
3595 }
3596
3597 // Check fuser->hasRight('modulepart', 'myobject', 'read') and fuser->hasRight('modulepart', 'read')
3598 $partsofdirinoriginalfile = explode('/', $original_file);
3599 if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use)
3600 $partofdirinoriginalfile = $partsofdirinoriginalfile[0];
3601 if ($partofdirinoriginalfile && ($fuser->hasRight($modulepart, $partofdirinoriginalfile, 'lire') || $fuser->hasRight($modulepart, $partofdirinoriginalfile, 'read'))) {
3602 $accessallowed = 1;
3603 }
3604 }
3605 if (($fuser->hasRight($modulepart, $lire) || $fuser->hasRight($modulepart, $read)) || ($fuser->hasRight($modulepart, 'all', $lire) || $fuser->hasRight($modulepart, 'all', $read))) {
3606 $accessallowed = 1;
3607 }
3608
3609 if (is_array($conf->$modulepart->multidir_output) && !empty($conf->$modulepart->multidir_output[$entity])) {
3610 $original_file = $conf->$modulepart->multidir_output[$entity].'/'.$original_file;
3611 } else {
3612 $original_file = $conf->$modulepart->dir_output.'/'.$original_file;
3613 }
3614 }
3615
3616 $parameters = array(
3617 'modulepart' => $modulepart,
3618 'original_file' => $original_file,
3619 'entity' => $entity,
3620 'fuser' => $fuser,
3621 'refname' => '',
3622 'mode' => $mode
3623 );
3624 $reshook = $hookmanager->executeHooks('checkSecureAccess', $parameters, $object);
3625 if ($reshook > 0) {
3626 if (!empty($hookmanager->resArray['original_file'])) {
3627 $original_file = $hookmanager->resArray['original_file'];
3628 }
3629 if (!empty($hookmanager->resArray['accessallowed'])) {
3630 $accessallowed = $hookmanager->resArray['accessallowed'];
3631 }
3632 if (!empty($hookmanager->resArray['sqlprotectagainstexternals'])) {
3633 $sqlprotectagainstexternals = $hookmanager->resArray['sqlprotectagainstexternals'];
3634 }
3635 }
3636 }
3637
3638 $ret = array(
3639 'accessallowed' => ($accessallowed ? 1 : 0),
3640 'sqlprotectagainstexternals' => $sqlprotectagainstexternals,
3641 'original_file' => $original_file
3642 );
3643
3644 return $ret;
3645}
3646
3655function dol_filecache($directory, $filename, $object)
3656{
3657 if (!dol_is_dir($directory)) {
3658 $result = dol_mkdir($directory);
3659 if ($result < -1) {
3660 dol_syslog("Failed to create the cache directory ".$directory, LOG_WARNING);
3661 }
3662 }
3663 $cachefile = $directory.$filename;
3664
3665 file_put_contents($cachefile, serialize($object), LOCK_EX);
3666
3667 dolChmod($cachefile, '0644');
3668}
3669
3678function dol_cache_refresh($directory, $filename, $cachetime)
3679{
3680 $now = dol_now();
3681 $cachefile = $directory.$filename;
3682 $refresh = !file_exists($cachefile) || ($now - $cachetime) > dol_filemtime($cachefile);
3683 return $refresh;
3684}
3685
3693function dol_readcachefile($directory, $filename)
3694{
3695 $cachefile = $directory.$filename;
3696 $object = unserialize(file_get_contents($cachefile));
3697 return $object;
3698}
3699
3706function dirbasename($pathfile)
3707{
3708 return preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'\//', '', $pathfile);
3709}
3710
3711
3723function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
3724{
3725 global $conffile;
3726
3727 $exclude = 'install';
3728
3729 foreach ($dir->md5file as $file) { // $file is a simpleXMLElement
3730 $filename = $path.$file['name'];
3731 $file_list['insignature'][] = $filename;
3732 $expectedsize = (empty($file['size']) ? '' : $file['size']);
3733 $expectedmd5 = (string) $file;
3734
3735 if (!file_exists($pathref.'/'.$filename)) {
3736 $file_list['missing'][] = array('filename' => $filename, 'expectedmd5' => $expectedmd5, 'expectedsize' => $expectedsize);
3737 } else {
3738 $md5_local = md5_file($pathref.'/'.$filename);
3739
3740 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
3741 $checksumconcat[] = $expectedmd5;
3742 } else {
3743 if ($md5_local != $expectedmd5) {
3744 $file_list['updated'][] = array('filename' => $filename, 'expectedmd5' => $expectedmd5, 'expectedsize' => $expectedsize, 'md5' => (string) $md5_local);
3745 }
3746 $checksumconcat[] = $md5_local;
3747 }
3748 }
3749 }
3750
3751 foreach ($dir->dir as $subdir) { // $subdir['name'] is '' or '/accountancy/admin' for example
3752 getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat);
3753 }
3754
3755 return $file_list;
3756}
3757
3765function dragAndDropFileUpload($htmlname)
3766{
3767 global $object, $langs;
3768
3769 $out = "";
3770 $out .= '<div id="'.$htmlname.'Message" class="dragDropAreaMessage hidden"><span>'.img_picto("", 'download').'<br>'.$langs->trans("DropFileToAddItToObject").'</span></div>';
3771 $out .= "\n<!-- JS CODE TO ENABLE DRAG AND DROP OF FILE -->\n";
3772 $out .= "<script>";
3773 $out .= '
3774 jQuery(document).ready(function() {
3775 var enterTargetDragDrop = null;
3776
3777 $("#'.$htmlname.'").addClass("cssDragDropArea");
3778
3779 $(".cssDragDropArea").on("dragenter", function(ev, ui) {
3780 var dataTransfer = ev.originalEvent.dataTransfer;
3781 var dataTypes = dataTransfer.types;
3782 //console.log(dataTransfer);
3783 //console.log(dataTypes);
3784
3785 if (!dataTypes || ($.inArray(\'Files\', dataTypes) === -1)) {
3786 // The element dragged is not a file, so we avoid the "dragenter"
3787 ev.preventDefault();
3788 return false;
3789 }
3790
3791 // Entering drop area. Highlight area
3792 console.log("dragAndDropFileUpload: We add class highlightDragDropArea")
3793 enterTargetDragDrop = ev.target;
3794 $(this).addClass("highlightDragDropArea");
3795 $("#'.$htmlname.'Message").removeClass("hidden");
3796 ev.preventDefault();
3797 });
3798
3799 $(".cssDragDropArea").on("dragleave", function(ev) {
3800 // Going out of drop area. Remove Highlight
3801 if (enterTargetDragDrop == ev.target){
3802 console.log("dragAndDropFileUpload: We remove class highlightDragDropArea")
3803 $("#'.$htmlname.'Message").addClass("hidden");
3804 $(this).removeClass("highlightDragDropArea");
3805 }
3806 });
3807
3808 $(".cssDragDropArea").on("dragover", function(ev) {
3809 ev.preventDefault();
3810 return false;
3811 });
3812
3813 $(".cssDragDropArea").on("drop", function(e) {
3814 console.log("Trigger event file dropped. fk_element='.dol_escape_js($object->id).' element='.dol_escape_js($object->element).'");
3815 e.preventDefault();
3816 fd = new FormData();
3817 fd.append("fk_element", "'.dol_escape_js($object->id).'");
3818 fd.append("element", "'.dol_escape_js($object->element).'");
3819 fd.append("token", "'.currentToken().'");
3820 fd.append("action", "linkit");
3821
3822 var dataTransfer = e.originalEvent.dataTransfer;
3823
3824 if (dataTransfer.files && dataTransfer.files.length){
3825 var droppedFiles = e.originalEvent.dataTransfer.files;
3826 $.each(droppedFiles, function(index,file){
3827 fd.append("files[]", file,file.name)
3828 });
3829 }
3830 $(".cssDragDropArea").removeClass("highlightDragDropArea");
3831 counterdragdrop = 0;
3832 $.ajax({
3833 url: "'.DOL_URL_ROOT.'/core/ajax/fileupload.php",
3834 type: "POST",
3835 processData: false,
3836 contentType: false,
3837 data: fd,
3838 success:function() {
3839 console.log("Uploaded.", arguments);
3840 /* arguments[0] is the json string of files */
3841 /* arguments[1] is the value for variable "success", can be 0 or 1 */
3842 let listoffiles = JSON.parse(arguments[0]);
3843 console.log(listoffiles);
3844 let nboferror = 0;
3845 for (let i = 0; i < listoffiles.length; i++) {
3846 console.log(listoffiles[i].error);
3847 if (listoffiles[i].error) {
3848 nboferror++;
3849 }
3850 }
3851 console.log(nboferror);
3852 if (nboferror > 0) {
3853 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorOnAtLeastOneFileUpload:warnings";
3854 } else {
3855 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=UploadFileDragDropSuccess:mesgs";
3856 }
3857 },
3858 error:function() {
3859 console.log("Error Uploading.", arguments)
3860 if (arguments[0].status == 403) {
3861 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadPermissionDenied:errors";
3862 }
3863 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadFileDragDropPermissionDenied:errors";
3864 },
3865 })
3866 });
3867 });
3868 ';
3869 $out .= "</script>\n";
3870 return $out;
3871}
3872
3883function archiveOrBackupFile($srcfile, $max_versions = 5, $archivedir = '', $suffix = "v", $moveorcopy = 'move')
3884{
3885 $base_file_pattern = ($archivedir ? $archivedir : dirname($srcfile)).'/'.basename($srcfile).".".$suffix;
3886 $files_in_directory = glob($base_file_pattern . "*");
3887
3888 // Extract the modification timestamps for each file
3889 $files_with_timestamps = [];
3890 foreach ($files_in_directory as $file) {
3891 $files_with_timestamps[] = [
3892 'file' => $file,
3893 'timestamp' => filemtime($file)
3894 ];
3895 }
3896
3897 // Sort the files by modification date
3898 $sorted_files = [];
3899 while (count($files_with_timestamps) > 0) {
3900 $latest_file = null;
3901 $latest_index = null;
3902
3903 // Find the latest file by timestamp
3904 foreach ($files_with_timestamps as $index => $file_info) {
3905 if ($latest_file === null || (is_array($latest_file) && $file_info['timestamp'] > $latest_file['timestamp'])) {
3906 $latest_file = $file_info;
3907 $latest_index = $index;
3908 }
3909 }
3910
3911 // Add the latest file to the sorted list and remove it from the original list
3912 if ($latest_file !== null) {
3913 $sorted_files[] = $latest_file['file'];
3914 unset($files_with_timestamps[$latest_index]);
3915 }
3916 }
3917
3918 // Delete the oldest files to keep only the allowed number of versions
3919 if (count($sorted_files) >= $max_versions) {
3920 $oldest_files = array_slice($sorted_files, $max_versions - 1);
3921 foreach ($oldest_files as $oldest_file) {
3922 dol_delete_file($oldest_file, 0, 0, 0, null, false, 0);
3923 }
3924 }
3925
3926 $timestamp = dol_now('gmt');
3927 $new_backup = $srcfile . ".v" . $timestamp;
3928
3929 // Move or copy the original file to the new backup with the timestamp
3930 if ($moveorcopy == 'move') {
3931 $result = dol_move($srcfile, $new_backup, '0', 1, 0, 0);
3932 } else {
3933 $result = dol_copy($srcfile, $new_backup, '0', 1, 0, 0);
3934 }
3935
3936 if (!$result) {
3937 return false;
3938 }
3939
3940 return true;
3941}
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.
dol_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array(), $entity=0)
Move a file into another name.
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_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_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).
dol_add_file_process($upload_dir, $allowoverwrite=0, $updatesessionordb=0, $varfiles='addedfile', $savingdocmask='', $link=null, $trackid='', $generatethumbs=1, $object=null, $forceFullTextIndexation='')
Get and save an upload 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
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.
deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded', $object=null)
Delete files into database index using search criteria.
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.