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