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