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