dolibarr 19.0.4
files.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2008-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2012-2021 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2012-2016 Juanjo Menent <jmenent@2byte.es>
5 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
6 * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
7 * Copyright (C) 2019-2024 Frédéric France <frederic.france@netlogic.fr>
8 * Copyright (C) 2023 Lenin Rivas <lenin.rivas777@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 * or see https://www.gnu.org/
23 */
24
37function dol_basename($pathfile)
38{
39 return preg_replace('/^.*\/([^\/]+)$/', '$1', rtrim($pathfile, '/'));
40}
41
62function dol_dir_list($path, $types = "all", $recursive = 0, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0, $nohook = 0, $relativename = "", $donotfollowsymlinks = 0, $nbsecondsold = 0)
63{
64 global $db, $hookmanager;
65 global $object;
66
67 if ($recursive <= 1) { // Avoid too verbose log
68 dol_syslog("files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter));
69 //print 'xxx'."files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter);
70 }
71
72 $loaddate = ($mode == 1 || $mode == 2 || $nbsecondsold) ? true : false;
73 $loadsize = ($mode == 1 || $mode == 3) ? true : false;
74 $loadperm = ($mode == 1 || $mode == 4) ? true : false;
75
76 // Clean parameters
77 $path = preg_replace('/([\\/]+)$/i', '', $path);
78 $newpath = dol_osencode($path);
79 $now = dol_now();
80
81 $reshook = 0;
82 $file_list = array();
83
84 if (is_object($hookmanager) && !$nohook) {
85 $hookmanager->resArray = array();
86
87 $hookmanager->initHooks(array('fileslib'));
88
89 $parameters = array(
90 'path' => $newpath,
91 'types'=> $types,
92 'recursive' => $recursive,
93 'filter' => $filter,
94 'excludefilter' => $excludefilter,
95 'sortcriteria' => $sortcriteria,
96 'sortorder' => $sortorder,
97 'loaddate' => $loaddate,
98 'loadsize' => $loadsize,
99 'mode' => $mode
100 );
101 $reshook = $hookmanager->executeHooks('getDirList', $parameters, $object);
102 }
103
104 // $hookmanager->resArray may contain array stacked by other modules
105 if (empty($reshook)) {
106 if (!is_dir($newpath)) {
107 return array();
108 }
109
110 if ($dir = opendir($newpath)) {
111 $filedate = '';
112 $filesize = '';
113 $fileperm = '';
114 while (false !== ($file = readdir($dir))) { // $file is always a basename (into directory $newpath)
115 if (!utf8_check($file)) {
116 $file = mb_convert_encoding($file, 'UTF-8', 'ISO-8859-1'); // To be sure data is stored in utf8 in memory
117 }
118 $fullpathfile = ($newpath ? $newpath.'/' : '').$file;
119
120 $qualified = 1;
121
122 // Define excludefilterarray
123 $excludefilterarray = array('^\.');
124 if (is_array($excludefilter)) {
125 $excludefilterarray = array_merge($excludefilterarray, $excludefilter);
126 } elseif ($excludefilter) {
127 $excludefilterarray[] = $excludefilter;
128 }
129 // Check if file is qualified
130 foreach ($excludefilterarray as $filt) {
131 if (preg_match('/'.$filt.'/i', $file) || preg_match('/'.$filt.'/i', $fullpathfile)) {
132 $qualified = 0;
133 break;
134 }
135 }
136 //print $fullpathfile.' '.$file.' '.$qualified.'<br>';
137
138 if ($qualified) {
139 $isdir = is_dir(dol_osencode($path."/".$file));
140 // Check whether this is a file or directory and whether we're interested in that type
141 if ($isdir && (($types == "directories") || ($types == "all") || $recursive > 0)) {
142 // Add entry into file_list array
143 if (($types == "directories") || ($types == "all")) {
144 if ($loaddate || $sortcriteria == 'date') {
145 $filedate = dol_filemtime($path."/".$file);
146 }
147 if ($loadsize || $sortcriteria == 'size') {
148 $filesize = dol_filesize($path."/".$file);
149 }
150 if ($loadperm || $sortcriteria == 'perm') {
151 $fileperm = dol_fileperm($path."/".$file);
152 }
153
154 if (!$filter || preg_match('/'.$filter.'/i', $file)) { // We do not search key $filter into all $path, only into $file part
155 $reg = array();
156 preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg);
157 $level1name = (isset($reg[1]) ? $reg[1] : '');
158 $file_list[] = array(
159 "name" => $file,
160 "path" => $path,
161 "level1name" => $level1name,
162 "relativename" => ($relativename ? $relativename.'/' : '').$file,
163 "fullname" => $path.'/'.$file,
164 "date" => $filedate,
165 "size" => $filesize,
166 "perm" => $fileperm,
167 "type" => 'dir'
168 );
169 }
170 }
171
172 // if we're in a directory and we want recursive behavior, call this function again
173 if ($recursive > 0) {
174 if (empty($donotfollowsymlinks) || !is_link($path."/".$file)) {
175 //var_dump('eee '. $path."/".$file. ' '.is_dir($path."/".$file).' '.is_link($path."/".$file));
176 $file_list = array_merge($file_list, dol_dir_list($path."/".$file, $types, $recursive + 1, $filter, $excludefilter, $sortcriteria, $sortorder, $mode, $nohook, ($relativename != '' ? $relativename.'/' : '').$file, $donotfollowsymlinks, $nbsecondsold));
177 }
178 }
179 } elseif (!$isdir && (($types == "files") || ($types == "all"))) {
180 // Add file into file_list array
181 if ($loaddate || $sortcriteria == 'date') {
182 $filedate = dol_filemtime($path."/".$file);
183 }
184 if ($loadsize || $sortcriteria == 'size') {
185 $filesize = dol_filesize($path."/".$file);
186 }
187
188 if (!$filter || preg_match('/'.$filter.'/i', $file)) { // We do not search key $filter into $path, only into $file
189 if (empty($nbsecondsold) || $filedate <= ($now - $nbsecondsold)) {
190 preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg);
191 $level1name = (isset($reg[1]) ? $reg[1] : '');
192 $file_list[] = array(
193 "name" => $file,
194 "path" => $path,
195 "level1name" => $level1name,
196 "relativename" => ($relativename ? $relativename.'/' : '').$file,
197 "fullname" => $path.'/'.$file,
198 "date" => $filedate,
199 "size" => $filesize,
200 "type" => 'file'
201 );
202 }
203 }
204 }
205 }
206 }
207 closedir($dir);
208
209 // Obtain a list of columns
210 if (!empty($sortcriteria) && $sortorder) {
211 $file_list = dol_sort_array($file_list, $sortcriteria, ($sortorder == SORT_ASC ? 'asc' : 'desc'));
212 }
213 }
214 }
215
216 if (is_object($hookmanager) && is_array($hookmanager->resArray)) {
217 $file_list = array_merge($file_list, $hookmanager->resArray);
218 }
219
220 return $file_list;
221}
222
223
237function dol_dir_list_in_database($path, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0)
238{
239 global $conf, $db;
240
241 $sql = " SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams,";
242 $sql .= " date_c, tms as date_m, fk_user_c, fk_user_m, acl, position, share";
243 if ($mode) {
244 $sql .= ", description";
245 }
246 $sql .= " FROM ".MAIN_DB_PREFIX."ecm_files";
247 $sql .= " WHERE entity = ".$conf->entity;
248 if (preg_match('/%$/', $path)) {
249 $sql .= " AND filepath LIKE '".$db->escape($path)."'";
250 } else {
251 $sql .= " AND filepath = '".$db->escape($path)."'";
252 }
253
254 $resql = $db->query($sql);
255 if ($resql) {
256 $file_list = array();
257 $num = $db->num_rows($resql);
258 $i = 0;
259 while ($i < $num) {
260 $obj = $db->fetch_object($resql);
261 if ($obj) {
262 $reg = array();
263 preg_match('/([^\/]+)\/[^\/]+$/', DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename, $reg);
264 $level1name = (isset($reg[1]) ? $reg[1] : '');
265 $file_list[] = array(
266 "rowid" => $obj->rowid,
267 "label" => $obj->label, // md5
268 "name" => $obj->filename,
269 "path" => DOL_DATA_ROOT.'/'.$obj->filepath,
270 "level1name" => $level1name,
271 "fullname" => DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,
272 "fullpath_orig" => $obj->fullpath_orig,
273 "date_c" => $db->jdate($obj->date_c),
274 "date_m" => $db->jdate($obj->date_m),
275 "type" => 'file',
276 "keywords" => $obj->keywords,
277 "cover" => $obj->cover,
278 "position" => (int) $obj->position,
279 "acl" => $obj->acl,
280 "share" => $obj->share,
281 "description" => ($mode ? $obj->description : '')
282 );
283 }
284 $i++;
285 }
286
287 // Obtain a list of columns
288 if (!empty($sortcriteria)) {
289 $myarray = array();
290 foreach ($file_list as $key => $row) {
291 $myarray[$key] = (isset($row[$sortcriteria]) ? $row[$sortcriteria] : '');
292 }
293 // Sort the data
294 if ($sortorder) {
295 array_multisort($myarray, $sortorder, SORT_REGULAR, $file_list);
296 }
297 }
298
299 return $file_list;
300 } else {
301 dol_print_error($db);
302 return array();
303 }
304}
305
306
315function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
316{
317 global $conf, $db, $user;
318
319 $filearrayindatabase = dol_dir_list_in_database($relativedir, '', null, 'name', SORT_ASC);
320
321 // TODO Remove this when PRODUCT_USE_OLD_PATH_FOR_PHOTO will be removed
322 global $modulepart;
323 if ($modulepart == 'produit' && getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
324 global $object;
325 if (!empty($object->id)) {
326 if (isModEnabled("product")) {
327 $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";
328 } else {
329 $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";
330 }
331
332 $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dirold);
333 $relativedirold = preg_replace('/^[\\/]/', '', $relativedirold);
334
335 $filearrayindatabase = array_merge($filearrayindatabase, dol_dir_list_in_database($relativedirold, '', null, 'name', SORT_ASC));
336 }
337 }
338
339 //var_dump($relativedir);
340 //var_dump($filearray);
341 //var_dump($filearrayindatabase);
342
343 // Complete filearray with properties found into $filearrayindatabase
344 foreach ($filearray as $key => $val) {
345 $tmpfilename = preg_replace('/\.noexe$/', '', $filearray[$key]['name']);
346 $found = 0;
347 // Search if it exists into $filearrayindatabase
348 foreach ($filearrayindatabase as $key2 => $val2) {
349 if (($filearrayindatabase[$key2]['path'] == $filearray[$key]['path']) && ($filearrayindatabase[$key2]['name'] == $tmpfilename)) {
350 $filearray[$key]['position_name'] = ($filearrayindatabase[$key2]['position'] ? $filearrayindatabase[$key2]['position'] : '0').'_'.$filearrayindatabase[$key2]['name'];
351 $filearray[$key]['position'] = $filearrayindatabase[$key2]['position'];
352 $filearray[$key]['cover'] = $filearrayindatabase[$key2]['cover'];
353 $filearray[$key]['keywords'] = $filearrayindatabase[$key2]['keywords'];
354 $filearray[$key]['acl'] = $filearrayindatabase[$key2]['acl'];
355 $filearray[$key]['rowid'] = $filearrayindatabase[$key2]['rowid'];
356 $filearray[$key]['label'] = $filearrayindatabase[$key2]['label'];
357 $filearray[$key]['share'] = $filearrayindatabase[$key2]['share'];
358 $found = 1;
359 break;
360 }
361 }
362
363 if (!$found) { // This happen in transition toward version 6, or if files were added manually into os dir.
364 $filearray[$key]['position'] = '999999'; // File not indexed are at end. So if we add a file, it will not replace an existing position
365 $filearray[$key]['cover'] = 0;
366 $filearray[$key]['acl'] = '';
367 $filearray[$key]['share'] = 0;
368
369 $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filearray[$key]['fullname']);
370
371 if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filename)) { // If not a tmp file
372 dol_syslog("list_of_documents We found a file called '".$filearray[$key]['name']."' not indexed into database. We add it");
373 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
374 $ecmfile = new EcmFiles($db);
375
376 // Add entry into database
377 $filename = basename($rel_filename);
378 $rel_dir = dirname($rel_filename);
379 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
380 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
381
382 $ecmfile->filepath = $rel_dir;
383 $ecmfile->filename = $filename;
384 $ecmfile->label = md5_file(dol_osencode($filearray[$key]['fullname'])); // $destfile is a full path to file
385 $ecmfile->fullpath_orig = $filearray[$key]['fullname'];
386 $ecmfile->gen_or_uploaded = 'unknown';
387 $ecmfile->description = ''; // indexed content
388 $ecmfile->keywords = ''; // keyword content
389 $result = $ecmfile->create($user);
390 if ($result < 0) {
391 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
392 } else {
393 $filearray[$key]['rowid'] = $result;
394 }
395 } else {
396 $filearray[$key]['rowid'] = 0; // Should not happened
397 }
398 }
399 }
400 //var_dump($filearray); var_dump($relativedir.' - tmpfilename='.$tmpfilename.' - found='.$found);
401}
402
403
411function dol_compare_file($a, $b)
412{
413 global $sortorder, $sortfield;
414
415 $sortorder = strtoupper($sortorder);
416
417 if ($sortorder == 'ASC') {
418 $retup = -1;
419 $retdown = 1;
420 } else {
421 $retup = 1;
422 $retdown = -1;
423 }
424
425 if ($sortfield == 'name') {
426 if ($a->name == $b->name) {
427 return 0;
428 }
429 return ($a->name < $b->name) ? $retup : $retdown;
430 }
431 if ($sortfield == 'date') {
432 if ($a->date == $b->date) {
433 return 0;
434 }
435 return ($a->date < $b->date) ? $retup : $retdown;
436 }
437 if ($sortfield == 'size') {
438 if ($a->size == $b->size) {
439 return 0;
440 }
441 return ($a->size < $b->size) ? $retup : $retdown;
442 }
443
444 return 0;
445}
446
447
454function dol_is_dir($folder)
455{
456 $newfolder = dol_osencode($folder);
457 if (is_dir($newfolder)) {
458 return true;
459 } else {
460 return false;
461 }
462}
463
470function dol_is_dir_empty($dir)
471{
472 if (!is_readable($dir)) {
473 return false;
474 }
475 return (count(scandir($dir)) == 2);
476}
477
484function dol_is_file($pathoffile)
485{
486 $newpathoffile = dol_osencode($pathoffile);
487 return is_file($newpathoffile);
488}
489
496function dol_is_link($pathoffile)
497{
498 $newpathoffile = dol_osencode($pathoffile);
499 return is_link($newpathoffile);
500}
501
508function dol_is_url($url)
509{
510 $tmpprot = array('file', 'http', 'https', 'ftp', 'zlib', 'data', 'ssh', 'ssh2', 'ogg', 'expect');
511 foreach ($tmpprot as $prot) {
512 if (preg_match('/^'.$prot.':/i', $url)) {
513 return true;
514 }
515 }
516 return false;
517}
518
525function dol_dir_is_emtpy($folder)
526{
527 $newfolder = dol_osencode($folder);
528 if (is_dir($newfolder)) {
529 $handle = opendir($newfolder);
530 $folder_content = '';
531 while ((gettype($name = readdir($handle)) != "boolean")) {
532 $name_array[] = $name;
533 }
534 foreach ($name_array as $temp) {
535 $folder_content .= $temp;
536 }
537
538 closedir($handle);
539
540 if ($folder_content == "...") {
541 return true;
542 } else {
543 return false;
544 }
545 } else {
546 return true; // Dir does not exists
547 }
548}
549
557function dol_count_nb_of_line($file)
558{
559 $nb = 0;
560
561 $newfile = dol_osencode($file);
562 //print 'x'.$file;
563 $fp = fopen($newfile, 'r');
564 if ($fp) {
565 while (!feof($fp)) {
566 $line = fgets($fp);
567 // We increase count only if read was success. We need test because feof return true only after fgets so we do n+1 fgets for a file with n lines.
568 if (!$line === false) {
569 $nb++;
570 }
571 }
572 fclose($fp);
573 } else {
574 $nb = -1;
575 }
576
577 return $nb;
578}
579
580
588function dol_filesize($pathoffile)
589{
590 $newpathoffile = dol_osencode($pathoffile);
591 return filesize($newpathoffile);
592}
593
600function dol_filemtime($pathoffile)
601{
602 $newpathoffile = dol_osencode($pathoffile);
603 return @filemtime($newpathoffile); // @Is to avoid errors if files does not exists
604}
605
612function dol_fileperm($pathoffile)
613{
614 $newpathoffile = dol_osencode($pathoffile);
615 return fileperms($newpathoffile);
616}
617
630function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask = 0, $indexdatabase = 0, $arrayreplacementisregex = 0)
631{
632 global $conf;
633
634 dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase." arrayreplacementisregex=".$arrayreplacementisregex);
635
636 if (empty($srcfile)) {
637 return -1;
638 }
639 if (empty($destfile)) {
640 $destfile = $srcfile;
641 }
642
643 $destexists = dol_is_file($destfile);
644 if (($destfile != $srcfile) && $destexists) {
645 return 0;
646 }
647
648 $srcexists = dol_is_file($srcfile);
649 if (!$srcexists) {
650 dol_syslog("files.lib.php::dolReplaceInFile failed to read src file", LOG_WARNING);
651 return -3;
652 }
653
654 $tmpdestfile = $destfile.'.tmp';
655
656 $newpathofsrcfile = dol_osencode($srcfile);
657 $newpathoftmpdestfile = dol_osencode($tmpdestfile);
658 $newpathofdestfile = dol_osencode($destfile);
659 $newdirdestfile = dirname($newpathofdestfile);
660
661 if ($destexists && !is_writable($newpathofdestfile)) {
662 dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to overwrite target file", LOG_WARNING);
663 return -1;
664 }
665 if (!is_writable($newdirdestfile)) {
666 dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
667 return -2;
668 }
669
670 dol_delete_file($tmpdestfile);
671
672 // Create $newpathoftmpdestfile from $newpathofsrcfile
673 $content = file_get_contents($newpathofsrcfile, 'r');
674
675 if (empty($arrayreplacementisregex)) {
676 $content = make_substitutions($content, $arrayreplacement, null);
677 } else {
678 foreach ($arrayreplacement as $key => $value) {
679 $content = preg_replace($key, $value, $content);
680 }
681 }
682
683 file_put_contents($newpathoftmpdestfile, $content);
684 dolChmod($newpathoftmpdestfile, $newmask);
685
686 // Rename
687 $result = dol_move($newpathoftmpdestfile, $newpathofdestfile, $newmask, (($destfile == $srcfile) ? 1 : 0), 0, $indexdatabase);
688 if (!$result) {
689 dol_syslog("files.lib.php::dolReplaceInFile failed to move tmp file to final dest", LOG_WARNING);
690 return -3;
691 }
692 if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
693 $newmask = $conf->global->MAIN_UMASK;
694 }
695 if (empty($newmask)) { // This should no happen
696 dol_syslog("Warning: dolReplaceInFile called with empty value for newmask and no default value defined", LOG_WARNING);
697 $newmask = '0664';
698 }
699
700 dolChmod($newpathofdestfile, $newmask);
701
702 return 1;
703}
704
705
718function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 0)
719{
720 global $conf, $db, $user;
721
722 dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
723
724 if (empty($srcfile) || empty($destfile)) {
725 return -1;
726 }
727
728 $destexists = dol_is_file($destfile);
729 if (!$overwriteifexists && $destexists) {
730 return 0;
731 }
732
733 $newpathofsrcfile = dol_osencode($srcfile);
734 $newpathofdestfile = dol_osencode($destfile);
735 $newdirdestfile = dirname($newpathofdestfile);
736
737 if ($destexists && !is_writable($newpathofdestfile)) {
738 dol_syslog("files.lib.php::dol_copy failed Permission denied to overwrite target file", LOG_WARNING);
739 return -1;
740 }
741 if (!is_writable($newdirdestfile)) {
742 dol_syslog("files.lib.php::dol_copy failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
743 return -2;
744 }
745
746 // Check virus
747 $testvirusarray = array();
748 if ($testvirus) {
749 $testvirusarray = dolCheckVirus($srcfile);
750 if (count($testvirusarray)) {
751 dol_syslog("files.lib.php::dol_copy canceled because a virus was found into source file. we ignore the copy request.", LOG_WARNING);
752 return -3;
753 }
754 }
755
756 // Copy with overwriting if exists
757 $result = @copy($newpathofsrcfile, $newpathofdestfile);
758 //$result=copy($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
759 if (!$result) {
760 dol_syslog("files.lib.php::dol_copy failed to copy", LOG_WARNING);
761 return -3;
762 }
763 if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
764 $newmask = $conf->global->MAIN_UMASK;
765 }
766 if (empty($newmask)) { // This should no happen
767 dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
768 $newmask = '0664';
769 }
770
771 dolChmod($newpathofdestfile, $newmask);
772
773 if ($result && $indexdatabase) {
774 // Add entry into ecm database
775 $rel_filetocopyafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $newpathofdestfile);
776 if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetocopyafter)) { // If not a tmp file
777 $rel_filetocopyafter = preg_replace('/^[\\/]/', '', $rel_filetocopyafter);
778 //var_dump($rel_filetorenamebefore.' - '.$rel_filetocopyafter);exit;
779
780 dol_syslog("Try to copy also entries in database for: ".$rel_filetocopyafter, LOG_DEBUG);
781 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
782
783 $ecmfiletarget = new EcmFiles($db);
784 $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetocopyafter);
785 if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created.
786 dol_syslog("ECM dest file found, remove it", LOG_DEBUG);
787 $ecmfiletarget->delete($user);
788 } else {
789 dol_syslog("ECM dest file not found, create it", LOG_DEBUG);
790 }
791
792 $ecmSrcfile = new EcmFiles($db);
793 $resultecm = $ecmSrcfile->fetch(0, '', $srcfile);
794 if ($resultecm) {
795 dol_syslog("Fetch src file ok", LOG_DEBUG);
796 } else {
797 dol_syslog("Fetch src file error", LOG_DEBUG);
798 }
799
800 $ecmfile = new EcmFiles($db);
801 $filename = basename($rel_filetocopyafter);
802 $rel_dir = dirname($rel_filetocopyafter);
803 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
804 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
805
806 $ecmfile->filepath = $rel_dir;
807 $ecmfile->filename = $filename;
808 $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
809 $ecmfile->fullpath_orig = $srcfile;
810 $ecmfile->gen_or_uploaded = 'copy';
811 $ecmfile->description = $ecmSrcfile->description;
812 $ecmfile->keywords = $ecmSrcfile->keywords;
813 $resultecm = $ecmfile->create($user);
814 if ($resultecm < 0) {
815 dol_syslog("Create ECM file ok", LOG_DEBUG);
816 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
817 } else {
818 dol_syslog("Create ECM file error", LOG_DEBUG);
819 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
820 }
821
822 if ($resultecm > 0) {
823 $result = 1;
824 } else {
825 $result = -1;
826 }
827 }
828 }
829
830 return $result;
831}
832
846function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null, $excludesubdir = 0, $excludefileext = null)
847{
848 global $conf;
849
850 $result = 0;
851
852 dol_syslog("files.lib.php::dolCopyDir srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
853
854 if (empty($srcfile) || empty($destfile)) {
855 return -1;
856 }
857
858 $destexists = dol_is_dir($destfile);
859 //if (! $overwriteifexists && $destexists) return 0; // The overwriteifexists is for files only, so propagated to dol_copy only.
860
861 if (!$destexists) {
862 // We must set mask just before creating dir, becaause it can be set differently by dol_copy
863 umask(0);
864 $dirmaskdec = octdec($newmask);
865 if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
866 $dirmaskdec = octdec($conf->global->MAIN_UMASK);
867 }
868 $dirmaskdec |= octdec('0200'); // Set w bit required to be able to create content for recursive subdirs files
869 dol_mkdir($destfile, '', decoct($dirmaskdec));
870 }
871
872 $ossrcfile = dol_osencode($srcfile);
873 $osdestfile = dol_osencode($destfile);
874
875 // Recursive function to copy all subdirectories and contents:
876 if (is_dir($ossrcfile)) {
877 $dir_handle = opendir($ossrcfile);
878 while ($file = readdir($dir_handle)) {
879 if ($file != "." && $file != ".." && !is_link($ossrcfile."/".$file)) {
880 if (is_dir($ossrcfile."/".$file)) {
881 if (empty($excludesubdir) || ($excludesubdir == 2 && strlen($file) == 2)) {
882 $newfile = $file;
883 // Replace destination filename with a new one
884 if (is_array($arrayreplacement)) {
885 foreach ($arrayreplacement as $key => $val) {
886 $newfile = str_replace($key, $val, $newfile);
887 }
888 }
889 //var_dump("xxx dolCopyDir $srcfile/$file, $destfile/$file, $newmask, $overwriteifexists");
890 $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists, $arrayreplacement, $excludesubdir, $excludefileext);
891 }
892 } else {
893 $newfile = $file;
894
895 if (is_array($excludefileext)) {
896 $extension = pathinfo($file, PATHINFO_EXTENSION);
897 if (in_array($extension, $excludefileext)) {
898 //print "We exclude the file ".$file." because its extension is inside list ".join(', ', $excludefileext); exit;
899 continue;
900 }
901 }
902
903 // Replace destination filename with a new one
904 if (is_array($arrayreplacement)) {
905 foreach ($arrayreplacement as $key => $val) {
906 $newfile = str_replace($key, $val, $newfile);
907 }
908 }
909 $tmpresult = dol_copy($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists);
910 }
911 // Set result
912 if ($result > 0 && $tmpresult >= 0) {
913 // Do nothing, so we don't set result to 0 if tmpresult is 0 and result was success in a previous pass
914 } else {
915 $result = $tmpresult;
916 }
917 if ($result < 0) {
918 break;
919 }
920 }
921 }
922 closedir($dir_handle);
923 } else {
924 // Source directory does not exists
925 $result = -2;
926 }
927
928 return $result;
929}
930
931
949function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1, $moreinfo = array())
950{
951 global $user, $db, $conf;
952 $result = false;
953
954 dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
955 $srcexists = dol_is_file($srcfile);
956 $destexists = dol_is_file($destfile);
957
958 if (!$srcexists) {
959 dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request.");
960 return false;
961 }
962
963 if ($overwriteifexists || !$destexists) {
964 $newpathofsrcfile = dol_osencode($srcfile);
965 $newpathofdestfile = dol_osencode($destfile);
966
967 // Check virus
968 $testvirusarray = array();
969 if ($testvirus) {
970 $testvirusarray = dolCheckVirus($newpathofsrcfile);
971 if (count($testvirusarray)) {
972 dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. we ignore the move request.", LOG_WARNING);
973 return false;
974 }
975 }
976
977 global $dolibarr_main_restrict_os_commands;
978 if (!empty($dolibarr_main_restrict_os_commands)) {
979 $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
980 $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
981 if (in_array(basename($destfile), $arrayofallowedcommand)) {
982 //$langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
983 //setEventMessages($langs->trans("ErrorFilenameReserved", basename($destfile)), null, 'errors');
984 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);
985 return false;
986 }
987 }
988
989 $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
990 if (!$result) {
991 if ($destexists) {
992 dol_syslog("files.lib.php::dol_move Failed. We try to delete target first and move after.", LOG_WARNING);
993 // We force delete and try again. Rename function sometimes fails to replace dest file with some windows NTFS partitions.
994 dol_delete_file($destfile);
995 $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
996 } else {
997 dol_syslog("files.lib.php::dol_move Failed.", LOG_WARNING);
998 }
999 }
1000
1001 // Move ok
1002 if ($result && $indexdatabase) {
1003 // Rename entry into ecm database
1004 $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile);
1005 $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile);
1006 if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) { // If not a tmp file
1007 $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore);
1008 $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter);
1009 //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);exit;
1010
1011 dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG);
1012 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1013
1014 $ecmfiletarget = new EcmFiles($db);
1015 $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetorenameafter);
1016 if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created.
1017 $ecmfiletarget->delete($user);
1018 }
1019
1020 $ecmfile = new EcmFiles($db);
1021 $resultecm = $ecmfile->fetch(0, '', $rel_filetorenamebefore);
1022 if ($resultecm > 0) { // If an entry was found for src file, we use it to move entry
1023 $filename = basename($rel_filetorenameafter);
1024 $rel_dir = dirname($rel_filetorenameafter);
1025 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1026 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1027
1028 $ecmfile->filepath = $rel_dir;
1029 $ecmfile->filename = $filename;
1030
1031 $resultecm = $ecmfile->update($user);
1032 } elseif ($resultecm == 0) { // If no entry were found for src files, create/update target file
1033 $filename = basename($rel_filetorenameafter);
1034 $rel_dir = dirname($rel_filetorenameafter);
1035 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1036 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1037
1038 $ecmfile->filepath = $rel_dir;
1039 $ecmfile->filename = $filename;
1040 $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file
1041 $ecmfile->fullpath_orig = basename($srcfile);
1042 $ecmfile->gen_or_uploaded = 'uploaded';
1043 if (!empty($moreinfo) && !empty($moreinfo['description'])) {
1044 $ecmfile->description = $moreinfo['description']; // indexed content
1045 } else {
1046 $ecmfile->description = ''; // indexed content
1047 }
1048 if (!empty($moreinfo) && !empty($moreinfo['keywords'])) {
1049 $ecmfile->keywords = $moreinfo['keywords']; // indexed content
1050 } else {
1051 $ecmfile->keywords = ''; // keyword content
1052 }
1053 if (!empty($moreinfo) && !empty($moreinfo['note_private'])) {
1054 $ecmfile->note_private = $moreinfo['note_private'];
1055 }
1056 if (!empty($moreinfo) && !empty($moreinfo['note_public'])) {
1057 $ecmfile->note_public = $moreinfo['note_public'];
1058 }
1059 if (!empty($moreinfo) && !empty($moreinfo['src_object_type'])) {
1060 $ecmfile->src_object_type = $moreinfo['src_object_type'];
1061 }
1062 if (!empty($moreinfo) && !empty($moreinfo['src_object_id'])) {
1063 $ecmfile->src_object_id = $moreinfo['src_object_id'];
1064 }
1065
1066 $resultecm = $ecmfile->create($user);
1067 if ($resultecm < 0) {
1068 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1069 }
1070 } elseif ($resultecm < 0) {
1071 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1072 }
1073
1074 if ($resultecm > 0) {
1075 $result = true;
1076 } else {
1077 $result = false;
1078 }
1079 }
1080 }
1081
1082 if (empty($newmask)) {
1083 $newmask = !getDolGlobalString('MAIN_UMASK') ? '0755' : $conf->global->MAIN_UMASK;
1084 }
1085
1086 // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too)
1087 // to allow mask usage for dir, we shoul introduce a new param "isdir" to 1 to complete newmask like this
1088 // if ($isdir) $newmaskdec |= octdec('0111'); // Set x bit required for directories
1089 dolChmod($newpathofdestfile, $newmask);
1090 }
1091
1092 return $result;
1093}
1094
1106function dol_move_dir($srcdir, $destdir, $overwriteifexists = 1, $indexdatabase = 1, $renamedircontent = 1)
1107{
1108 $result = false;
1109
1110 dol_syslog("files.lib.php::dol_move_dir srcdir=".$srcdir." destdir=".$destdir." overwritifexists=".$overwriteifexists." indexdatabase=".$indexdatabase." renamedircontent=".$renamedircontent);
1111 $srcexists = dol_is_dir($srcdir);
1112 $srcbasename = basename($srcdir);
1113 $destexists = dol_is_dir($destdir);
1114
1115 if (!$srcexists) {
1116 dol_syslog("files.lib.php::dol_move_dir srcdir does not exists. we ignore the move request.");
1117 return false;
1118 }
1119
1120 if ($overwriteifexists || !$destexists) {
1121 $newpathofsrcdir = dol_osencode($srcdir);
1122 $newpathofdestdir = dol_osencode($destdir);
1123
1124 $result = @rename($newpathofsrcdir, $newpathofdestdir);
1125
1126 // Now we rename also contents inside dir after the move to match new destination name
1127 if ($result && $renamedircontent) {
1128 if (file_exists($newpathofdestdir)) {
1129 $destbasename = basename($newpathofdestdir);
1130 $files = dol_dir_list($newpathofdestdir);
1131 if (!empty($files) && is_array($files)) {
1132 foreach ($files as $key => $file) {
1133 if (!file_exists($file["fullname"])) {
1134 continue;
1135 }
1136 $filepath = $file["path"];
1137 $oldname = $file["name"];
1138
1139 $newname = str_replace($srcbasename, $destbasename, $oldname);
1140 if (!empty($newname) && $newname !== $oldname) {
1141 if ($file["type"] == "dir") {
1142 $res = dol_move_dir($filepath.'/'.$oldname, $filepath.'/'.$newname, $overwriteifexists, $indexdatabase, $renamedircontent);
1143 } else {
1144 $res = dol_move($filepath.'/'.$oldname, $filepath.'/'.$newname, 0, $overwriteifexists, 0, $indexdatabase);
1145 }
1146 if (!$res) {
1147 return $result;
1148 }
1149 }
1150 }
1151 $result = true;
1152 }
1153 }
1154 }
1155 }
1156 return $result;
1157}
1158
1166function dol_unescapefile($filename)
1167{
1168 // Remove path information and dots around the filename, to prevent uploading
1169 // into different directories or replacing hidden system files.
1170 // Also remove control characters and spaces (\x00..\x20) around the filename:
1171 return trim(basename($filename), ".\x00..\x20");
1172}
1173
1174
1181function dolCheckVirus($src_file)
1182{
1183 global $conf, $db;
1184
1185 if (getDolGlobalString('MAIN_ANTIVIRUS_COMMAND')) {
1186 if (!class_exists('AntiVir')) {
1187 require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
1188 }
1189 $antivir = new AntiVir($db);
1190 $result = $antivir->dol_avscan_file($src_file);
1191 if ($result < 0) { // If virus or error, we stop here
1192 $reterrors = $antivir->errors;
1193 return $reterrors;
1194 }
1195 }
1196 return array();
1197}
1198
1199
1220function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile', $upload_dir = '')
1221{
1222 global $conf, $db, $user, $langs;
1223 global $object, $hookmanager;
1224
1225 $reshook = 0;
1226 $file_name = $dest_file;
1227 $successcode = 1;
1228
1229 if (empty($nohook)) {
1230 $reshook = $hookmanager->initHooks(array('fileslib'));
1231
1232 $parameters = array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
1233 $reshook = $hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
1234 }
1235
1236 if (empty($reshook)) {
1237 // If an upload error has been reported
1238 if ($uploaderrorcode) {
1239 switch ($uploaderrorcode) {
1240 case UPLOAD_ERR_INI_SIZE: // 1
1241 return 'ErrorFileSizeTooLarge';
1242 case UPLOAD_ERR_FORM_SIZE: // 2
1243 return 'ErrorFileSizeTooLarge';
1244 case UPLOAD_ERR_PARTIAL: // 3
1245 return 'ErrorPartialFile';
1246 case UPLOAD_ERR_NO_TMP_DIR: //
1247 return 'ErrorNoTmpDir';
1248 case UPLOAD_ERR_CANT_WRITE:
1249 return 'ErrorFailedToWriteInDir';
1250 case UPLOAD_ERR_EXTENSION:
1251 return 'ErrorUploadBlockedByAddon';
1252 default:
1253 break;
1254 }
1255 }
1256
1257 // Security:
1258 // If we need to make a virus scan
1259 if (empty($disablevirusscan) && file_exists($src_file)) {
1260 $checkvirusarray = dolCheckVirus($src_file);
1261 if (count($checkvirusarray)) {
1262 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
1263 return 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray);
1264 }
1265 }
1266
1267 // Security:
1268 // Disallow file with some extensions. We rename them.
1269 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
1270 if (isAFileWithExecutableContent($dest_file) && !getDolGlobalString('MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED')) {
1271 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
1272 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
1273 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
1274 $publicmediasdirwithslash .= '/';
1275 }
1276
1277 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
1278 $file_name .= '.noexe';
1279 $successcode = 2;
1280 }
1281 }
1282
1283 // Security:
1284 // We refuse cache files/dirs, upload using .. and pipes into filenames.
1285 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
1286 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
1287 return -1;
1288 }
1289
1290 // Security:
1291 // We refuse cache files/dirs, upload using .. and pipes into filenames.
1292 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
1293 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
1294 return -2;
1295 }
1296 }
1297
1298 if ($reshook < 0) { // At least one blocking error returned by one hook
1299 $errmsg = join(',', $hookmanager->errors);
1300 if (empty($errmsg)) {
1301 $errmsg = 'ErrorReturnedBySomeHooks'; // Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
1302 }
1303 return $errmsg;
1304 } elseif (empty($reshook)) {
1305 // The file functions must be in OS filesystem encoding.
1306 $src_file_osencoded = dol_osencode($src_file);
1307 $file_name_osencoded = dol_osencode($file_name);
1308
1309 // Check if destination dir is writable
1310 if (!is_writable(dirname($file_name_osencoded))) {
1311 dol_syslog("Files.lib::dol_move_uploaded_file Dir ".dirname($file_name_osencoded)." is not writable. Return 'ErrorDirNotWritable'", LOG_WARNING);
1312 return 'ErrorDirNotWritable';
1313 }
1314
1315 // Check if destination file already exists
1316 if (!$allowoverwrite) {
1317 if (file_exists($file_name_osencoded)) {
1318 dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
1319 return 'ErrorFileAlreadyExists';
1320 }
1321 } else { // We are allowed to erase
1322 if (is_dir($file_name_osencoded)) { // If there is a directory with name of file to create
1323 dol_syslog("Files.lib::dol_move_uploaded_file A directory with name ".$file_name." already exists. Return 'ErrorDirWithFileNameAlreadyExists'", LOG_WARNING);
1324 return 'ErrorDirWithFileNameAlreadyExists';
1325 }
1326 }
1327
1328 // Move file
1329 $return = move_uploaded_file($src_file_osencoded, $file_name_osencoded);
1330 if ($return) {
1331 dolChmod($file_name_osencoded);
1332 dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=" . getDolGlobalString('MAIN_UMASK'), LOG_DEBUG);
1333 return $successcode; // Success
1334 } else {
1335 dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
1336 return -3; // Unknown error
1337 }
1338 }
1339
1340 return $successcode; // Success
1341}
1342
1358function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1, $nolog = 0)
1359{
1360 global $db, $user, $langs;
1361 global $hookmanager;
1362
1363 // Load translation files required by the page
1364 $langs->loadLangs(array('other', 'errors'));
1365
1366 if (empty($nolog)) {
1367 dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook);
1368 }
1369
1370 // Security:
1371 // We refuse transversal using .. and pipes into filenames.
1372 if ((!$allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file)) {
1373 dol_syslog("Refused to delete file ".$file, LOG_WARNING);
1374 return false;
1375 }
1376
1377 $reshook = 0;
1378 if (empty($nohook) && !empty($hookmanager)) {
1379 $hookmanager->initHooks(array('fileslib'));
1380
1381 $parameters = array(
1382 'file' => $file,
1383 'disableglob'=> $disableglob,
1384 'nophperrors' => $nophperrors
1385 );
1386 $reshook = $hookmanager->executeHooks('deleteFile', $parameters, $object);
1387 }
1388
1389 if (empty($nohook) && $reshook != 0) { // reshook = 0 to do standard actions, 1 = ok and replace, -1 = ko
1390 dol_syslog("reshook=".$reshook);
1391 if ($reshook < 0) {
1392 return false;
1393 }
1394 return true;
1395 } else {
1396 $file_osencoded = dol_osencode($file); // New filename encoded in OS filesystem encoding charset
1397 if (empty($disableglob) && !empty($file_osencoded)) {
1398 $ok = true;
1399 $globencoded = str_replace('[', '\[', $file_osencoded);
1400 $globencoded = str_replace(']', '\]', $globencoded);
1401 $listofdir = glob($globencoded);
1402 if (!empty($listofdir) && is_array($listofdir)) {
1403 foreach ($listofdir as $filename) {
1404 if ($nophperrors) {
1405 $ok = @unlink($filename);
1406 } else {
1407 $ok = unlink($filename);
1408 }
1409
1410 // If it fails and it is because of the missing write permission on parent dir
1411 if (!$ok && file_exists(dirname($filename)) && !(fileperms(dirname($filename)) & 0200)) {
1412 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);
1413 dolChmod(dirname($filename), decoct(fileperms(dirname($filename)) | 0200));
1414 // Now we retry deletion
1415 if ($nophperrors) {
1416 $ok = @unlink($filename);
1417 } else {
1418 $ok = unlink($filename);
1419 }
1420 }
1421
1422 if ($ok) {
1423 if (empty($nolog)) {
1424 dol_syslog("Removed file ".$filename, LOG_DEBUG);
1425 }
1426
1427 // Delete entry into ecm database
1428 $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename);
1429 if (!preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) { // If not a tmp file
1430 if (is_object($db) && $indexdatabase) { // $db may not be defined when lib is in a context with define('NOREQUIREDB',1)
1431 $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete);
1432 $rel_filetodelete = preg_replace('/\.noexe$/', '', $rel_filetodelete);
1433
1434 dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG);
1435 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1436 $ecmfile = new EcmFiles($db);
1437 $result = $ecmfile->fetch(0, '', $rel_filetodelete);
1438 if ($result >= 0 && $ecmfile->id > 0) {
1439 $result = $ecmfile->delete($user);
1440 }
1441 if ($result < 0) {
1442 setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1443 }
1444 }
1445 }
1446 } else {
1447 dol_syslog("Failed to remove file ".$filename, LOG_WARNING);
1448 // TODO Failure to remove can be because file was already removed or because of permission
1449 // If error because it does not exists, we should return true, and we should return false if this is a permission problem
1450 }
1451 }
1452 } else {
1453 $ok = false; // to avoid false positive
1454 dol_syslog("No files to delete found", LOG_DEBUG);
1455 }
1456 } else {
1457 $ok = false;
1458 if ($nophperrors) {
1459 $ok = @unlink($file_osencoded);
1460 } else {
1461 $ok = unlink($file_osencoded);
1462 }
1463 if ($ok) {
1464 if (empty($nolog)) {
1465 dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
1466 }
1467 } else {
1468 dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
1469 }
1470 }
1471
1472 return $ok;
1473 }
1474}
1475
1485function dol_delete_dir($dir, $nophperrors = 0)
1486{
1487 // Security:
1488 // We refuse transversal using .. and pipes into filenames.
1489 if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) {
1490 dol_syslog("Refused to delete dir ".$dir.' (contains invalid char sequence)', LOG_WARNING);
1491 return false;
1492 }
1493
1494 $dir_osencoded = dol_osencode($dir);
1495 return ($nophperrors ? @rmdir($dir_osencoded) : rmdir($dir_osencoded));
1496}
1497
1510function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0, $indexdatabase = 1, $nolog = 0)
1511{
1512 if (empty($nolog)) {
1513 dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG);
1514 }
1515 if (dol_is_dir($dir)) {
1516 $dir_osencoded = dol_osencode($dir);
1517 if ($handle = opendir("$dir_osencoded")) {
1518 while (false !== ($item = readdir($handle))) {
1519 if (!utf8_check($item)) {
1520 $item = mb_convert_encoding($item, 'UTF-8', 'ISO-8859-1'); // should be useless
1521 }
1522
1523 if ($item != "." && $item != "..") {
1524 if (is_dir(dol_osencode("$dir/$item")) && !is_link(dol_osencode("$dir/$item"))) {
1525 $count = dol_delete_dir_recursive("$dir/$item", $count, $nophperrors, 0, $countdeleted, $indexdatabase, $nolog);
1526 } else {
1527 $result = dol_delete_file("$dir/$item", 1, $nophperrors, 0, null, false, $indexdatabase, $nolog);
1528 $count++;
1529 if ($result) {
1530 $countdeleted++;
1531 }
1532 //else print 'Error on '.$item."\n";
1533 }
1534 }
1535 }
1536 closedir($handle);
1537
1538 // Delete also the main directory
1539 if (empty($onlysub)) {
1540 $result = dol_delete_dir($dir, $nophperrors);
1541 $count++;
1542 if ($result) {
1543 $countdeleted++;
1544 }
1545 //else print 'Error on '.$dir."\n";
1546 }
1547 }
1548 }
1549
1550 return $count;
1551}
1552
1553
1562function dol_delete_preview($object)
1563{
1564 global $langs, $conf;
1565
1566 // Define parent dir of elements
1567 $element = $object->element;
1568
1569 if ($object->element == 'order_supplier') {
1570 $dir = $conf->fournisseur->commande->dir_output;
1571 } elseif ($object->element == 'invoice_supplier') {
1572 $dir = $conf->fournisseur->facture->dir_output;
1573 } elseif ($object->element == 'project') {
1574 $dir = $conf->project->dir_output;
1575 } elseif ($object->element == 'shipping') {
1576 $dir = $conf->expedition->dir_output.'/sending';
1577 } elseif ($object->element == 'delivery') {
1578 $dir = $conf->expedition->dir_output.'/receipt';
1579 } elseif ($object->element == 'fichinter') {
1580 $dir = $conf->ficheinter->dir_output;
1581 } else {
1582 $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1583 }
1584
1585 if (empty($dir)) {
1586 $object->error = $langs->trans('ErrorObjectNoSupportedByFunction');
1587 return 0;
1588 }
1589
1590 $refsan = dol_sanitizeFileName($object->ref);
1591 $dir = $dir."/".$refsan;
1592 $filepreviewnew = $dir."/".$refsan.".pdf_preview.png";
1593 $filepreviewnewbis = $dir."/".$refsan.".pdf_preview-0.png";
1594 $filepreviewold = $dir."/".$refsan.".pdf.png";
1595
1596 // For new preview files
1597 if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) {
1598 if (!dol_delete_file($filepreviewnew, 1)) {
1599 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnew);
1600 return 0;
1601 }
1602 }
1603 if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) {
1604 if (!dol_delete_file($filepreviewnewbis, 1)) {
1605 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis);
1606 return 0;
1607 }
1608 }
1609 // For old preview files
1610 if (file_exists($filepreviewold) && is_writable($filepreviewold)) {
1611 if (!dol_delete_file($filepreviewold, 1)) {
1612 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewold);
1613 return 0;
1614 }
1615 } else {
1616 $multiple = $filepreviewold.".";
1617 for ($i = 0; $i < 20; $i++) {
1618 $preview = $multiple.$i;
1619
1620 if (file_exists($preview) && is_writable($preview)) {
1621 if (!dol_delete_file($preview, 1)) {
1622 $object->error = $langs->trans("ErrorFailedToOpenFile", $preview);
1623 return 0;
1624 }
1625 }
1626 }
1627 }
1628
1629 return 1;
1630}
1631
1640function dol_meta_create($object)
1641{
1642 global $conf;
1643
1644 // Create meta file
1645 if (!getDolGlobalString('MAIN_DOC_CREATE_METAFILE')) {
1646 return 0; // By default, no metafile.
1647 }
1648
1649 // Define parent dir of elements
1650 $element = $object->element;
1651
1652 if ($object->element == 'order_supplier') {
1653 $dir = $conf->fournisseur->dir_output.'/commande';
1654 } elseif ($object->element == 'invoice_supplier') {
1655 $dir = $conf->fournisseur->dir_output.'/facture';
1656 } elseif ($object->element == 'project') {
1657 $dir = $conf->project->dir_output;
1658 } elseif ($object->element == 'shipping') {
1659 $dir = $conf->expedition->dir_output.'/sending';
1660 } elseif ($object->element == 'delivery') {
1661 $dir = $conf->expedition->dir_output.'/receipt';
1662 } elseif ($object->element == 'fichinter') {
1663 $dir = $conf->ficheinter->dir_output;
1664 } else {
1665 $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1666 }
1667
1668 if ($dir) {
1669 $object->fetch_thirdparty();
1670
1671 $objectref = dol_sanitizeFileName($object->ref);
1672 $dir = $dir."/".$objectref;
1673 $file = $dir."/".$objectref.".meta";
1674
1675 if (!is_dir($dir)) {
1676 dol_mkdir($dir);
1677 }
1678
1679 if (is_dir($dir)) {
1680 if (is_countable($object->lines) && count($object->lines) > 0) {
1681 $nblines = count($object->lines);
1682 }
1683 $client = $object->thirdparty->name." ".$object->thirdparty->address." ".$object->thirdparty->zip." ".$object->thirdparty->town;
1684 $meta = "REFERENCE=\"".$object->ref."\"
1685 DATE=\"" . dol_print_date($object->date, '')."\"
1686 NB_ITEMS=\"" . $nblines."\"
1687 CLIENT=\"" . $client."\"
1688 AMOUNT_EXCL_TAX=\"" . $object->total_ht."\"
1689 AMOUNT=\"" . $object->total_ttc."\"\n";
1690
1691 for ($i = 0; $i < $nblines; $i++) {
1692 //Pour les articles
1693 $meta .= "ITEM_".$i."_QUANTITY=\"".$object->lines[$i]->qty."\"
1694 ITEM_" . $i."_AMOUNT_WO_TAX=\"".$object->lines[$i]->total_ht."\"
1695 ITEM_" . $i."_VAT=\"".$object->lines[$i]->tva_tx."\"
1696 ITEM_" . $i."_DESCRIPTION=\"".str_replace("\r\n", "", nl2br($object->lines[$i]->desc))."\"
1697 ";
1698 }
1699 }
1700
1701 $fp = fopen($file, "w");
1702 fputs($fp, $meta);
1703 fclose($fp);
1704
1705 dolChmod($file);
1706
1707 return 1;
1708 } else {
1709 dol_syslog('FailedToDetectDirInDolMetaCreateFor'.$object->element, LOG_WARNING);
1710 }
1711
1712 return 0;
1713}
1714
1715
1716
1725function dol_init_file_process($pathtoscan = '', $trackid = '')
1726{
1727 $listofpaths = array();
1728 $listofnames = array();
1729 $listofmimes = array();
1730
1731 if ($pathtoscan) {
1732 $listoffiles = dol_dir_list($pathtoscan, 'files');
1733 foreach ($listoffiles as $key => $val) {
1734 $listofpaths[] = $val['fullname'];
1735 $listofnames[] = $val['name'];
1736 $listofmimes[] = dol_mimetype($val['name']);
1737 }
1738 }
1739 $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1740 $_SESSION["listofpaths".$keytoavoidconflict] = join(';', $listofpaths);
1741 $_SESSION["listofnames".$keytoavoidconflict] = join(';', $listofnames);
1742 $_SESSION["listofmimes".$keytoavoidconflict] = join(';', $listofmimes);
1743}
1744
1745
1763function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null)
1764{
1765 global $db, $user, $conf, $langs;
1766
1767 $res = 0;
1768
1769 if (!empty($_FILES[$varfiles])) { // For view $_FILES[$varfiles]['error']
1770 dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG);
1771 $maxfilesinform = getDolGlobalInt("MAIN_SECURITY_MAX_ATTACHMENT_ON_FORMS", 10);
1772 if (is_array($_FILES[$varfiles]["name"]) && count($_FILES[$varfiles]["name"]) > $maxfilesinform) {
1773 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1774 setEventMessages($langs->trans("ErrorTooMuchFileInForm", $maxfilesinform), null, "errors");
1775 return -1;
1776 }
1777 $result = dol_mkdir($upload_dir);
1778 // var_dump($result);exit;
1779 if ($result >= 0) {
1780 $TFile = $_FILES[$varfiles];
1781 // Convert value of $TFile
1782 if (!is_array($TFile['name'])) {
1783 foreach ($TFile as $key => &$val) {
1784 $val = array($val);
1785 }
1786 }
1787
1788 $nbfile = count($TFile['name']);
1789 $nbok = 0;
1790 for ($i = 0; $i < $nbfile; $i++) {
1791 if (empty($TFile['name'][$i])) {
1792 continue; // For example, when submitting a form with no file name
1793 }
1794
1795 // Define $destfull (path to file including filename) and $destfile (only filename)
1796 $destfile = trim($TFile['name'][$i]);
1797 $destfull = $upload_dir."/".$destfile;
1798 $destfilewithoutext = preg_replace('/\.[^\.]+$/', '', $destfile);
1799
1800 if ($savingdocmask && strpos($savingdocmask, $destfilewithoutext) !== 0) {
1801 $destfile = trim(preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask));
1802 $destfull = $upload_dir."/".$destfile;
1803 }
1804
1805 $filenameto = basename($destfile);
1806 if (preg_match('/^\./', $filenameto)) {
1807 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1808 setEventMessages($langs->trans("ErrorFilenameCantStartWithDot", $filenameto), null, 'errors');
1809 break;
1810 }
1811 // dol_sanitizeFileName the file name and lowercase extension
1812 $info = pathinfo($destfull);
1813 $destfull = $info['dirname'].'/'.dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1814 $info = pathinfo($destfile);
1815 $destfile = dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1816
1817 // We apply dol_string_nohtmltag also to clean file names (this remove duplicate spaces) because
1818 // this function is also applied when we rename and when we make try to download file (by the GETPOST(filename, 'alphanohtml') call).
1819 $destfile = dol_string_nohtmltag($destfile);
1820 $destfull = dol_string_nohtmltag($destfull);
1821
1822 // Check that filename is not the one of a reserved allowed CLI command
1823 global $dolibarr_main_restrict_os_commands;
1824 if (!empty($dolibarr_main_restrict_os_commands)) {
1825 $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
1826 $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
1827 if (in_array($destfile, $arrayofallowedcommand)) {
1828 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1829 setEventMessages($langs->trans("ErrorFilenameReserved", $destfile), null, 'errors');
1830 return -1;
1831 }
1832 }
1833
1834 // Move file from temp directory to final directory. A .noexe may also be appended on file name.
1835 $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir);
1836
1837 if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists'
1838 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
1839
1840 $tmparraysize = getDefaultImageSizes();
1841 $maxwidthsmall = $tmparraysize['maxwidthsmall'];
1842 $maxheightsmall = $tmparraysize['maxheightsmall'];
1843 $maxwidthmini = $tmparraysize['maxwidthmini'];
1844 $maxheightmini = $tmparraysize['maxheightmini'];
1845 //$quality = $tmparraysize['quality'];
1846 $quality = 50; // For thumbs, we force quality to 50
1847
1848 // Generate thumbs.
1849 if ($generatethumbs) {
1850 if (image_format_supported($destfull) == 1) {
1851 // Create thumbs
1852 // We can't use $object->addThumbs here because there is no $object known
1853
1854 // Used on logon for example
1855 $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', $quality, "thumbs");
1856 // Create mini thumbs for image (Ratio is near 16/9)
1857 // Used on menu or for setup page for example
1858 $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', $quality, "thumbs");
1859 }
1860 }
1861
1862 // Update session
1863 if (empty($donotupdatesession)) {
1864 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1865 $formmail = new FormMail($db);
1866 $formmail->trackid = $trackid;
1867 $formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
1868 }
1869
1870 // Update index table of files (llx_ecm_files)
1871 if ($donotupdatesession == 1) {
1872 $sharefile = 0;
1873 if ($TFile['type'][$i] == 'application/pdf' && strpos($_SERVER["REQUEST_URI"], 'product') !== false && getDolGlobalString('PRODUCT_ALLOW_EXTERNAL_DOWNLOAD')) {
1874 $sharefile = 1;
1875 }
1876 $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', $sharefile, $object);
1877 if ($result < 0) {
1878 if ($allowoverwrite) {
1879 // Do not show error message. We can have an error due to DB_ERROR_RECORD_ALREADY_EXISTS
1880 } else {
1881 setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', null, 'warnings');
1882 }
1883 }
1884 }
1885
1886 $nbok++;
1887 } else {
1888 $langs->load("errors");
1889 if ($resupload < 0) { // Unknown error
1890 setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
1891 } elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) { // Files infected by a virus
1892 setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors');
1893 } else { // Known error
1894 setEventMessages($langs->trans($resupload), null, 'errors');
1895 }
1896 }
1897 }
1898 if ($nbok > 0) {
1899 $res = 1;
1900 setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs');
1901 }
1902 } else {
1903 setEventMessages($langs->trans("ErrorFailedToCreateDir", $upload_dir), null, 'errors');
1904 }
1905 } elseif ($link) {
1906 require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
1907 $linkObject = new Link($db);
1908 $linkObject->entity = $conf->entity;
1909 $linkObject->url = $link;
1910 $linkObject->objecttype = GETPOST('objecttype', 'alpha');
1911 $linkObject->objectid = GETPOST('objectid', 'int');
1912 $linkObject->label = GETPOST('label', 'alpha');
1913 $res = $linkObject->create($user);
1914
1915 if ($res > 0) {
1916 setEventMessages($langs->trans("LinkComplete"), null, 'mesgs');
1917 } else {
1918 setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors');
1919 }
1920 } else {
1921 $langs->load("errors");
1922 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
1923 }
1924
1925 return $res;
1926}
1927
1928
1940function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '')
1941{
1942 global $db, $user, $conf, $langs, $_FILES;
1943
1944 $keytodelete = $filenb;
1945 $keytodelete--;
1946
1947 $listofpaths = array();
1948 $listofnames = array();
1949 $listofmimes = array();
1950 $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1951 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
1952 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
1953 }
1954 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
1955 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
1956 }
1957 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
1958 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
1959 }
1960
1961 if ($keytodelete >= 0) {
1962 $pathtodelete = $listofpaths[$keytodelete];
1963 $filetodelete = $listofnames[$keytodelete];
1964 if (empty($donotdeletefile)) {
1965 $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file
1966 } else {
1967 $result = 0;
1968 }
1969 if ($result >= 0) {
1970 if (empty($donotdeletefile)) {
1971 $langs->load("other");
1972 setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs');
1973 }
1974 if (empty($donotupdatesession)) {
1975 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1976 $formmail = new FormMail($db);
1977 $formmail->trackid = $trackid;
1978 $formmail->remove_attached_files($keytodelete);
1979 }
1980 }
1981 }
1982}
1983
1984
1998function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null)
1999{
2000 global $db, $user, $conf;
2001
2002 $result = 0;
2003
2004 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2005
2006 if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir
2007 $filename = basename(preg_replace('/\.noexe$/', '', $file));
2008 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2009 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2010
2011 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
2012 $ecmfile = new EcmFiles($db);
2013 $ecmfile->filepath = $rel_dir;
2014 $ecmfile->filename = $filename;
2015 $ecmfile->label = md5_file(dol_osencode($dir.'/'.$file)); // MD5 of file content
2016 $ecmfile->fullpath_orig = $fullpathorig;
2017 $ecmfile->gen_or_uploaded = $mode;
2018 $ecmfile->description = ''; // indexed content
2019 $ecmfile->keywords = ''; // keyword content
2020
2021 if (is_object($object) && $object->id > 0) {
2022 $ecmfile->src_object_id = $object->id;
2023 if (isset($object->table_element)) {
2024 $ecmfile->src_object_type = $object->table_element;
2025 } else {
2026 dol_syslog('Error: object ' . get_class($object) . ' has no table_element attribute.');
2027 return -1;
2028 }
2029 if (isset($object->src_object_description)) {
2030 $ecmfile->description = $object->src_object_description;
2031 }
2032 if (isset($object->src_object_keywords)) {
2033 $ecmfile->keywords = $object->src_object_keywords;
2034 }
2035 }
2036
2037 if (getDolGlobalString('MAIN_FORCE_SHARING_ON_ANY_UPLOADED_FILE')) {
2038 $setsharekey = 1;
2039 }
2040
2041 if ($setsharekey) {
2042 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
2043 $ecmfile->share = getRandomPassword(true);
2044 }
2045
2046 $result = $ecmfile->create($user);
2047 if ($result < 0) {
2048 dol_syslog($ecmfile->error);
2049 }
2050 }
2051
2052 return $result;
2053}
2054
2063function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded')
2064{
2065 global $conf, $db, $user;
2066
2067 $error = 0;
2068
2069 if (empty($dir)) {
2070 dol_syslog("deleteFilesIntoDatabaseIndex: dir parameter can't be empty", LOG_ERR);
2071 return -1;
2072 }
2073
2074 $db->begin();
2075
2076 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2077
2078 $filename = basename($file);
2079 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2080 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2081
2082 if (!$error) {
2083 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'ecm_files';
2084 $sql .= ' WHERE entity = '.$conf->entity;
2085 $sql .= " AND filepath = '".$db->escape($rel_dir)."'";
2086 if ($file) {
2087 $sql .= " AND filename = '".$db->escape($file)."'";
2088 }
2089 if ($mode) {
2090 $sql .= " AND gen_or_uploaded = '".$db->escape($mode)."'";
2091 }
2092
2093 $resql = $db->query($sql);
2094 if (!$resql) {
2095 $error++;
2096 dol_syslog(__FUNCTION__.' '.$db->lasterror(), LOG_ERR);
2097 }
2098 }
2099
2100 // Commit or rollback
2101 if ($error) {
2102 $db->rollback();
2103 return -1 * $error;
2104 } else {
2105 $db->commit();
2106 return 1;
2107 }
2108}
2109
2110
2122function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '')
2123{
2124 if (class_exists('Imagick')) {
2125 $image = new Imagick();
2126 try {
2127 $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : '');
2128 //var_dump($filetoconvert);
2129 $ret = $image->readImage($filetoconvert);
2130 } catch (Exception $e) {
2131 $ext = pathinfo($fileinput, PATHINFO_EXTENSION);
2132 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." convertion in /etc/ImageMagick*/policy.xml): ".$e->getMessage(), LOG_WARNING);
2133 return 0;
2134 }
2135 if ($ret) {
2136 $ret = $image->setImageFormat($ext);
2137 if ($ret) {
2138 if (empty($fileoutput)) {
2139 $fileoutput = $fileinput.".".$ext;
2140 }
2141
2142 $count = $image->getNumberImages();
2143
2144 if (!dol_is_file($fileoutput) || is_writeable($fileoutput)) {
2145 try {
2146 $ret = $image->writeImages($fileoutput, true);
2147 } catch (Exception $e) {
2148 dol_syslog($e->getMessage(), LOG_WARNING);
2149 }
2150 } else {
2151 dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR);
2152 }
2153 if ($ret) {
2154 return $count;
2155 } else {
2156 return -3;
2157 }
2158 } else {
2159 return -2;
2160 }
2161 } else {
2162 return -1;
2163 }
2164 } else {
2165 return 0;
2166 }
2167}
2168
2169
2181function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring = null)
2182{
2183 global $conf;
2184
2185 $foundhandler = 0;
2186
2187 try {
2188 dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile);
2189
2190 $data = implode("", file(dol_osencode($inputfile)));
2191 if ($mode == 'gz' && function_exists('gzencode')) {
2192 $foundhandler = 1;
2193 $compressdata = gzencode($data, 9);
2194 } elseif ($mode == 'bz' && function_exists('bzcompress')) {
2195 $foundhandler = 1;
2196 $compressdata = bzcompress($data, 9);
2197 } elseif ($mode == 'zstd' && function_exists('zstd_compress')) {
2198 $foundhandler = 1;
2199 $compressdata = zstd_compress($data, 9);
2200 } elseif ($mode == 'zip') {
2201 if (class_exists('ZipArchive') && getDolGlobalString('MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS')) {
2202 $foundhandler = 1;
2203
2204 $rootPath = realpath($inputfile);
2205
2206 dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath);
2207 $zip = new ZipArchive();
2208
2209 if ($zip->open($outputfile, ZipArchive::CREATE) !== true) {
2210 $errorstring = "dol_compress_file failure - Failed to open file ".$outputfile."\n";
2211 dol_syslog($errorstring, LOG_ERR);
2212
2213 global $errormsg;
2214 $errormsg = $errorstring;
2215
2216 return -6;
2217 }
2218
2219 // Create recursive directory iterator
2221 $files = new RecursiveIteratorIterator(
2222 new RecursiveDirectoryIterator($rootPath, FilesystemIterator::UNIX_PATHS),
2223 RecursiveIteratorIterator::LEAVES_ONLY
2224 );
2225
2226 foreach ($files as $name => $file) {
2227 // Skip directories (they would be added automatically)
2228 if (!$file->isDir()) {
2229 // Get real and relative path for current file
2230 $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2231 $fileName = $file->getFilename();
2232 $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2233
2234 //$relativePath = substr($fileFullRealPath, strlen($rootPath) + 1);
2235 $relativePath = substr(($filePath ? $filePath.'/' : '').$fileName, strlen($rootPath) + 1);
2236
2237 // Add current file to archive
2238 $zip->addFile($fileFullRealPath, $relativePath);
2239 }
2240 }
2241
2242 // Zip archive will be created only after closing object
2243 $zip->close();
2244
2245 dol_syslog("dol_compress_file success - ".count($zip->numFiles)." files");
2246 return 1;
2247 }
2248
2249 if (defined('ODTPHP_PATHTOPCLZIP')) {
2250 $foundhandler = 1;
2251
2252 include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2253 $archive = new PclZip($outputfile);
2254 $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2255
2256 if ($result === 0) {
2257 global $errormsg;
2258 $errormsg = $archive->errorInfo(true);
2259
2260 if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) {
2261 $errorstring = "PCLZIP_ERR_WRITE_OPEN_FAIL";
2262 dol_syslog("dol_compress_file error - archive->errorCode() = PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR);
2263 return -4;
2264 }
2265
2266 $errorstring = "dol_compress_file error archive->errorCode = ".$archive->errorCode()." errormsg=".$errormsg;
2267 dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR);
2268 return -3;
2269 } else {
2270 dol_syslog("dol_compress_file success - ".count($result)." files");
2271 return 1;
2272 }
2273 }
2274 }
2275
2276 if ($foundhandler) {
2277 $fp = fopen($outputfile, "w");
2278 fwrite($fp, $compressdata);
2279 fclose($fp);
2280 return 1;
2281 } else {
2282 $errorstring = "Try to zip with format ".$mode." with no handler for this format";
2283 dol_syslog($errorstring, LOG_ERR);
2284
2285 global $errormsg;
2286 $errormsg = $errorstring;
2287 return -2;
2288 }
2289 } catch (Exception $e) {
2290 global $langs, $errormsg;
2291 $langs->load("errors");
2292 $errormsg = $langs->trans("ErrorFailedToWriteInDir");
2293
2294 $errorstring = "Failed to open file ".$outputfile;
2295 dol_syslog($errorstring, LOG_ERR);
2296 return -1;
2297 }
2298}
2299
2308function dol_uncompress($inputfile, $outputdir)
2309{
2310 global $conf, $langs, $db;
2311
2312 $fileinfo = pathinfo($inputfile);
2313 $fileinfo["extension"] = strtolower($fileinfo["extension"]);
2314
2315 if ($fileinfo["extension"] == "zip") {
2316 if (defined('ODTPHP_PATHTOPCLZIP') && !getDolGlobalString('MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS')) {
2317 dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
2318 include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2319 $archive = new PclZip($inputfile);
2320
2321 // We create output dir manually, so it uses the correct permission (When created by the archive->extract, dir is rwx for everybody).
2322 dol_mkdir(dol_sanitizePathName($outputdir));
2323
2324 // Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
2325 $result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
2326
2327 if (!is_array($result) && $result <= 0) {
2328 return array('error'=>$archive->errorInfo(true));
2329 } else {
2330 $ok = 1;
2331 $errmsg = '';
2332 // Loop on each file to check result for unzipping file
2333 foreach ($result as $key => $val) {
2334 if ($val['status'] == 'path_creation_fail') {
2335 $langs->load("errors");
2336 $ok = 0;
2337 $errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
2338 break;
2339 }
2340 }
2341
2342 if ($ok) {
2343 return array();
2344 } else {
2345 return array('error'=>$errmsg);
2346 }
2347 }
2348 }
2349
2350 if (class_exists('ZipArchive')) { // Must install php-zip to have it
2351 dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
2352 $zip = new ZipArchive();
2353 $res = $zip->open($inputfile);
2354 if ($res === true) {
2355 //$zip->extractTo($outputdir.'/');
2356 // 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
2357 // python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
2358 // with -l is the range of dot to go back in path.
2359 // and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
2360 for ($i = 0; $i < $zip->numFiles; $i++) {
2361 if (preg_match('/\.\./', $zip->getNameIndex($i))) {
2362 dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
2363 continue; // Discard the file
2364 }
2365 $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
2366 }
2367
2368 $zip->close();
2369 return array();
2370 } else {
2371 return array('error'=>'ErrUnzipFails');
2372 }
2373 }
2374
2375 return array('error'=>'ErrNoZipEngine');
2376 } elseif (in_array($fileinfo["extension"], array('gz', 'bz2', 'zst'))) {
2377 include_once DOL_DOCUMENT_ROOT."/core/class/utils.class.php";
2378 $utils = new Utils($db);
2379
2380 dol_mkdir(dol_sanitizePathName($outputdir));
2381 $outputfilename = escapeshellcmd(dol_sanitizePathName($outputdir).'/'.dol_sanitizeFileName($fileinfo["filename"]));
2382 dol_delete_file($outputfilename.'.tmp');
2383 dol_delete_file($outputfilename.'.err');
2384
2385 $extension = strtolower(pathinfo($fileinfo["filename"], PATHINFO_EXTENSION));
2386 if ($extension == "tar") {
2387 $cmd = 'tar -C '.escapeshellcmd(dol_sanitizePathName($outputdir)).' -xvf '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2388
2389 $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, $outputfilename.'.err', 0);
2390 if ($resarray["result"] != 0) {
2391 $resarray["error"] .= file_get_contents($outputfilename.'.err');
2392 }
2393 } else {
2394 $program = "";
2395 if ($fileinfo["extension"] == "gz") {
2396 $program = 'gzip';
2397 } elseif ($fileinfo["extension"] == "bz2") {
2398 $program = 'bzip2';
2399 } elseif ($fileinfo["extension"] == "zst") {
2400 $program = 'zstd';
2401 } else {
2402 return array('error'=>'ErrorBadFileExtension');
2403 }
2404 $cmd = $program.' -dc '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2405 $cmd .= ' > '.$outputfilename;
2406
2407 $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, null, 1, $outputfilename.'.err');
2408 if ($resarray["result"] != 0) {
2409 $errfilecontent = @file_get_contents($outputfilename.'.err');
2410 if ($errfilecontent) {
2411 $resarray["error"] .= " - ".$errfilecontent;
2412 }
2413 }
2414 }
2415 return $resarray["result"] != 0 ? array('error' => $resarray["error"]) : array();
2416 }
2417
2418 return array('error'=>'ErrorBadFileExtension');
2419}
2420
2421
2434function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '', $rootdirinzip = '', $newmask = 0)
2435{
2436 global $conf;
2437
2438 $foundhandler = 0;
2439
2440 dol_syslog("Try to zip dir ".$inputdir." into ".$outputfile." mode=".$mode);
2441
2442 if (!dol_is_dir(dirname($outputfile)) || !is_writable(dirname($outputfile))) {
2443 global $langs, $errormsg;
2444 $langs->load("errors");
2445 $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile);
2446 return -3;
2447 }
2448
2449 try {
2450 if ($mode == 'gz') {
2451 $foundhandler = 0;
2452 } elseif ($mode == 'bz') {
2453 $foundhandler = 0;
2454 } elseif ($mode == 'zip') {
2455 /*if (defined('ODTPHP_PATHTOPCLZIP'))
2456 {
2457 $foundhandler=0; // TODO implement this
2458
2459 include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2460 $archive = new PclZip($outputfile);
2461 $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2462 //$archive->add($inputfile);
2463 return 1;
2464 }
2465 else*/
2466 //if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS))
2467
2468 if (class_exists('ZipArchive')) {
2469 $foundhandler = 1;
2470
2471 // Initialize archive object
2472 $zip = new ZipArchive();
2473 $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
2474 if ($result !== true) {
2475 global $langs, $errormsg;
2476 $langs->load("errors");
2477 $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile);
2478 return -4;
2479 }
2480
2481 // Create recursive directory iterator
2482 // This does not return symbolic links
2484 $files = new RecursiveIteratorIterator(
2485 new RecursiveDirectoryIterator($inputdir, FilesystemIterator::UNIX_PATHS),
2486 RecursiveIteratorIterator::LEAVES_ONLY
2487 );
2488
2489 //var_dump($inputdir);
2490 foreach ($files as $name => $file) {
2491 // Skip directories (they would be added automatically)
2492 if (!$file->isDir()) {
2493 // Get real and relative path for current file
2494 $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2495 $fileName = $file->getFilename();
2496 $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2497
2498 //$relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($fileFullRealPath, strlen($inputdir) + 1);
2499 $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr(($filePath ? $filePath.'/' : '').$fileName, strlen($inputdir) + 1);
2500
2501 //var_dump($filePath);var_dump($fileFullRealPath);var_dump($relativePath);
2502 if (empty($excludefiles) || !preg_match($excludefiles, $fileFullRealPath)) {
2503 // Add current file to archive
2504 $zip->addFile($fileFullRealPath, $relativePath);
2505 }
2506 }
2507 }
2508
2509 // Zip archive will be created only after closing object
2510 $zip->close();
2511
2512 if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
2513 $newmask = $conf->global->MAIN_UMASK;
2514 }
2515 if (empty($newmask)) { // This should no happen
2516 dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
2517 $newmask = '0664';
2518 }
2519
2520 dolChmod($outputfile, $newmask);
2521
2522 return 1;
2523 }
2524 }
2525
2526 if (!$foundhandler) {
2527 dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR);
2528 return -2;
2529 } else {
2530 return 0;
2531 }
2532 } catch (Exception $e) {
2533 global $langs, $errormsg;
2534 $langs->load("errors");
2535 dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
2536 dol_syslog($e->getMessage(), LOG_ERR);
2537 $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile).' - '.$e->getMessage();
2538 return -1;
2539 }
2540}
2541
2542
2543
2554function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$', '^\.'), $nohook = false, $mode = '')
2555{
2556 $tmparray = dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook);
2557 return isset($tmparray[0]) ? $tmparray[0] : null;
2558}
2559
2573function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = '', $refname = '', $mode = 'read')
2574{
2575 global $conf, $db, $user, $hookmanager;
2576 global $dolibarr_main_data_root, $dolibarr_main_document_root_alt;
2577 global $object;
2578
2579 if (!is_object($fuser)) {
2580 $fuser = $user;
2581 }
2582
2583 if (empty($modulepart)) {
2584 return 'ErrorBadParameter';
2585 }
2586 if (empty($entity)) {
2587 if (!isModEnabled('multicompany')) {
2588 $entity = 1;
2589 } else {
2590 $entity = 0;
2591 }
2592 }
2593 // Fix modulepart for backward compatibility
2594 if ($modulepart == 'users') {
2595 $modulepart = 'user';
2596 }
2597 if ($modulepart == 'tva') {
2598 $modulepart = 'tax-vat';
2599 }
2600 // Fix modulepart delivery
2601 if ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) {
2602 $modulepart = 'delivery';
2603 }
2604
2605 //print 'dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity;
2606 dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
2607
2608 // We define $accessallowed and $sqlprotectagainstexternals
2609 $accessallowed = 0;
2610 $sqlprotectagainstexternals = '';
2611 $ret = array();
2612
2613 // Find the subdirectory name as the reference. For example original_file='10/myfile.pdf' -> refname='10'
2614 if (empty($refname)) {
2615 $refname = basename(dirname($original_file)."/");
2616 if ($refname == 'thumbs' || $refname == 'temp') {
2617 // If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10'
2618 $refname = basename(dirname(dirname($original_file))."/");
2619 }
2620 }
2621
2622 // Define possible keys to use for permission check
2623 $lire = 'lire';
2624 $read = 'read';
2625 $download = 'download';
2626 if ($mode == 'write') {
2627 $lire = 'creer';
2628 $read = 'write';
2629 $download = 'upload';
2630 }
2631
2632 // Wrapping for miscellaneous medias files
2633 if ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) {
2634 if (empty($entity) || empty($conf->medias->multidir_output[$entity])) {
2635 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2636 }
2637 $accessallowed = 1;
2638 $original_file = $conf->medias->multidir_output[$entity].'/'.$original_file;
2639 } elseif ($modulepart == 'logs' && !empty($dolibarr_main_data_root)) {
2640 // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
2641 $accessallowed = ($user->admin && basename($original_file) == $original_file && preg_match('/^dolibarr.*\.(log|json)$/', basename($original_file)));
2642 $original_file = $dolibarr_main_data_root.'/'.$original_file;
2643 } elseif ($modulepart == 'doctemplates' && !empty($dolibarr_main_data_root)) {
2644 // Wrapping for doctemplates
2645 $accessallowed = $user->admin;
2646 $original_file = $dolibarr_main_data_root.'/doctemplates/'.$original_file;
2647 } elseif ($modulepart == 'doctemplateswebsite' && !empty($dolibarr_main_data_root)) {
2648 // Wrapping for doctemplates of websites
2649 $accessallowed = ($fuser->rights->website->write && preg_match('/\.jpg$/i', basename($original_file)));
2650 $original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file;
2651 } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) {
2652 // Wrapping for *.zip package files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
2653 // Dir for custom dirs
2654 $tmp = explode(',', $dolibarr_main_document_root_alt);
2655 $dirins = $tmp[0];
2656
2657 $accessallowed = ($user->admin && preg_match('/^module_.*\.zip$/', basename($original_file)));
2658 $original_file = $dirins.'/'.$original_file;
2659 } elseif ($modulepart == 'mycompany' && !empty($conf->mycompany->dir_output)) {
2660 // Wrapping for some images
2661 $accessallowed = 1;
2662 $original_file = $conf->mycompany->dir_output.'/'.$original_file;
2663 } elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output)) {
2664 // Wrapping for users photos (user photos are allowed to any connected users)
2665 $accessallowed = 0;
2666 if (preg_match('/^\d+\/photos\//', $original_file)) {
2667 $accessallowed = 1;
2668 }
2669 $original_file = $conf->user->dir_output.'/'.$original_file;
2670 } elseif ($modulepart == 'userphotopublic' && !empty($conf->user->dir_output)) {
2671 // Wrapping for users photos that were set to public (for virtual credit card) by their owner (public user photos can be read
2672 // with the public link and securekey)
2673 $accessok = false;
2674 $reg = array();
2675 if (preg_match('/^(\d+)\/photos\//', $original_file, $reg)) {
2676 if ($reg[1]) {
2677 $tmpobject = new User($db);
2678 $tmpobject->fetch($reg[1], '', '', 1);
2679 if (getDolUserInt('USER_ENABLE_PUBLIC', 0, $tmpobject)) {
2680 $securekey = GETPOST('securekey', 'alpha', 1);
2681 // Security check
2682 global $dolibarr_main_cookie_cryptkey, $dolibarr_main_instance_unique_id;
2683 $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
2684 $encodedsecurekey = dol_hash($valuetouse.'uservirtualcard'.$tmpobject->id.'-'.$tmpobject->login, 'md5');
2685 if ($encodedsecurekey == $securekey) {
2686 $accessok = true;
2687 }
2688 }
2689 }
2690 }
2691 if ($accessok) {
2692 $accessallowed = 1;
2693 }
2694 $original_file = $conf->user->dir_output.'/'.$original_file;
2695 } elseif (($modulepart == 'companylogo') && !empty($conf->mycompany->dir_output)) {
2696 // Wrapping for company logos (company logos are allowed to anyboby, they are public)
2697 $accessallowed = 1;
2698 $original_file = $conf->mycompany->dir_output.'/logos/'.$original_file;
2699 } elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output)) {
2700 // Wrapping for members photos
2701 $accessallowed = 0;
2702 if (preg_match('/^\d+\/photos\//', $original_file)) {
2703 $accessallowed = 1;
2704 }
2705 $original_file = $conf->adherent->dir_output.'/'.$original_file;
2706 } elseif ($modulepart == 'apercufacture' && !empty($conf->facture->multidir_output[$entity])) {
2707 // Wrapping for invoices (user need permission to read invoices)
2708 if ($fuser->hasRight('facture', $lire)) {
2709 $accessallowed = 1;
2710 }
2711 $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2712 } elseif ($modulepart == 'apercupropal' && !empty($conf->propal->multidir_output[$entity])) {
2713 // Wrapping pour les apercu propal
2714 if ($fuser->hasRight('propal', $lire)) {
2715 $accessallowed = 1;
2716 }
2717 $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
2718 } elseif ($modulepart == 'apercucommande' && !empty($conf->commande->multidir_output[$entity])) {
2719 // Wrapping pour les apercu commande
2720 if ($fuser->hasRight('commande', $lire)) {
2721 $accessallowed = 1;
2722 }
2723 $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
2724 } elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output)) {
2725 // Wrapping pour les apercu intervention
2726 if ($fuser->hasRight('ficheinter', $lire)) {
2727 $accessallowed = 1;
2728 }
2729 $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2730 } elseif (($modulepart == 'apercucontract') && !empty($conf->contrat->multidir_output[$entity])) {
2731 // Wrapping pour les apercu contrat
2732 if ($fuser->hasRight('contrat', $lire)) {
2733 $accessallowed = 1;
2734 }
2735 $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
2736 } elseif (($modulepart == 'apercusupplier_proposal' || $modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output)) {
2737 // Wrapping pour les apercu supplier proposal
2738 if ($fuser->hasRight('supplier_proposal', $lire)) {
2739 $accessallowed = 1;
2740 }
2741 $original_file = $conf->supplier_proposal->dir_output.'/'.$original_file;
2742 } elseif (($modulepart == 'apercusupplier_order' || $modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output)) {
2743 // Wrapping pour les apercu supplier order
2744 if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2745 $accessallowed = 1;
2746 }
2747 $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
2748 } elseif (($modulepart == 'apercusupplier_invoice' || $modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output)) {
2749 // Wrapping pour les apercu supplier invoice
2750 if ($fuser->hasRight('fournisseur', $lire)) {
2751 $accessallowed = 1;
2752 }
2753 $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
2754 } elseif (($modulepart == 'holiday') && !empty($conf->holiday->dir_output)) {
2755 if ($fuser->hasRight('holiday', $read) || $fuser->hasRight('holiday', 'readall') || preg_match('/^specimen/i', $original_file)) {
2756 $accessallowed = 1;
2757 // If we known $id of holiday, call checkUserAccessToObject to check permission on properties and hierarchy of leave request
2758 if ($refname && !$fuser->hasRight('holiday', 'readall') && !preg_match('/^specimen/i', $original_file)) {
2759 include_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
2760 $tmpholiday = new Holiday($db);
2761 $tmpholiday->fetch('', $refname);
2762 $accessallowed = checkUserAccessToObject($user, array('holiday'), $tmpholiday, 'holiday', '', '', 'rowid', '');
2763 }
2764 }
2765 $original_file = $conf->holiday->dir_output.'/'.$original_file;
2766 } elseif (($modulepart == 'expensereport') && !empty($conf->expensereport->dir_output)) {
2767 if ($fuser->hasRight('expensereport', $lire) || $fuser->hasRight('expensereport', 'readall') || preg_match('/^specimen/i', $original_file)) {
2768 $accessallowed = 1;
2769 // If we known $id of expensereport, call checkUserAccessToObject to check permission on properties and hierarchy of expense report
2770 if ($refname && !$fuser->hasRight('expensereport', 'readall') && !preg_match('/^specimen/i', $original_file)) {
2771 include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
2772 $tmpexpensereport = new ExpenseReport($db);
2773 $tmpexpensereport->fetch('', $refname);
2774 $accessallowed = checkUserAccessToObject($user, array('expensereport'), $tmpexpensereport, 'expensereport', '', '', 'rowid', '');
2775 }
2776 }
2777 $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2778 } elseif (($modulepart == 'apercuexpensereport') && !empty($conf->expensereport->dir_output)) {
2779 // Wrapping pour les apercu expense report
2780 if ($fuser->hasRight('expensereport', $lire)) {
2781 $accessallowed = 1;
2782 }
2783 $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2784 } elseif ($modulepart == 'propalstats' && !empty($conf->propal->multidir_temp[$entity])) {
2785 // Wrapping pour les images des stats propales
2786 if ($fuser->hasRight('propal', $lire)) {
2787 $accessallowed = 1;
2788 }
2789 $original_file = $conf->propal->multidir_temp[$entity].'/'.$original_file;
2790 } elseif ($modulepart == 'orderstats' && !empty($conf->commande->dir_temp)) {
2791 // Wrapping pour les images des stats commandes
2792 if ($fuser->hasRight('commande', $lire)) {
2793 $accessallowed = 1;
2794 }
2795 $original_file = $conf->commande->dir_temp.'/'.$original_file;
2796 } elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2797 if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2798 $accessallowed = 1;
2799 }
2800 $original_file = $conf->fournisseur->commande->dir_temp.'/'.$original_file;
2801 } elseif ($modulepart == 'billstats' && !empty($conf->facture->dir_temp)) {
2802 // Wrapping pour les images des stats factures
2803 if ($fuser->hasRight('facture', $lire)) {
2804 $accessallowed = 1;
2805 }
2806 $original_file = $conf->facture->dir_temp.'/'.$original_file;
2807 } elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2808 if ($fuser->hasRight('fournisseur', 'facture', $lire)) {
2809 $accessallowed = 1;
2810 }
2811 $original_file = $conf->fournisseur->facture->dir_temp.'/'.$original_file;
2812 } elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp)) {
2813 // Wrapping pour les images des stats expeditions
2814 if ($fuser->hasRight('expedition', $lire)) {
2815 $accessallowed = 1;
2816 }
2817 $original_file = $conf->expedition->dir_temp.'/'.$original_file;
2818 } elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp)) {
2819 // Wrapping pour les images des stats expeditions
2820 if ($fuser->hasRight('deplacement', $lire)) {
2821 $accessallowed = 1;
2822 }
2823 $original_file = $conf->deplacement->dir_temp.'/'.$original_file;
2824 } elseif ($modulepart == 'memberstats' && !empty($conf->adherent->dir_temp)) {
2825 // Wrapping pour les images des stats expeditions
2826 if ($fuser->hasRight('adherent', $lire)) {
2827 $accessallowed = 1;
2828 }
2829 $original_file = $conf->adherent->dir_temp.'/'.$original_file;
2830 } elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) {
2831 // Wrapping pour les images des stats produits
2832 if ($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) {
2833 $accessallowed = 1;
2834 }
2835 $original_file = (!empty($conf->product->multidir_temp[$entity]) ? $conf->product->multidir_temp[$entity] : $conf->service->multidir_temp[$entity]).'/'.$original_file;
2836 } elseif (in_array($modulepart, array('tax', 'tax-vat', 'tva')) && !empty($conf->tax->dir_output)) {
2837 // Wrapping for taxes
2838 if ($fuser->hasRight('tax', 'charges', $lire)) {
2839 $accessallowed = 1;
2840 }
2841 $modulepartsuffix = str_replace('tax-', '', $modulepart);
2842 $original_file = $conf->tax->dir_output.'/'.($modulepartsuffix != 'tax' ? $modulepartsuffix.'/' : '').$original_file;
2843 } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
2844 // Wrapping for events
2845 if ($fuser->hasRight('agenda', 'myactions', $read)) {
2846 $accessallowed = 1;
2847 // If we known $id of project, call checkUserAccessToObject to check permission on the given agenda event on properties and assigned users
2848 if ($refname && !preg_match('/^specimen/i', $original_file)) {
2849 include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
2850 $tmpobject = new ActionComm($db);
2851 $tmpobject->fetch((int) $refname);
2852 $accessallowed = checkUserAccessToObject($user, array('agenda'), $tmpobject->id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id', '');
2853 if ($user->socid && $tmpobject->socid) {
2854 $accessallowed = checkUserAccessToObject($user, array('societe'), $tmpobject->socid);
2855 }
2856 }
2857 }
2858 $original_file = $conf->agenda->dir_output.'/'.$original_file;
2859 } elseif ($modulepart == 'category' && !empty($conf->categorie->multidir_output[$entity])) {
2860 // Wrapping for categories (categories are allowed if user has permission to read categories or to work on TakePos)
2861 if (empty($entity) || empty($conf->categorie->multidir_output[$entity])) {
2862 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2863 }
2864 if ($fuser->hasRight("categorie", $lire) || $fuser->hasRight("takepos", "run")) {
2865 $accessallowed = 1;
2866 }
2867 $original_file = $conf->categorie->multidir_output[$entity].'/'.$original_file;
2868 } elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) {
2869 // Wrapping pour les prelevements
2870 if ($fuser->hasRight('prelevement', 'bons', $lire) || preg_match('/^specimen/i', $original_file)) {
2871 $accessallowed = 1;
2872 }
2873 $original_file = $conf->prelevement->dir_output.'/'.$original_file;
2874 } elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp)) {
2875 // Wrapping pour les graph energie
2876 $accessallowed = 1;
2877 $original_file = $conf->stock->dir_temp.'/'.$original_file;
2878 } elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp)) {
2879 // Wrapping pour les graph fournisseurs
2880 $accessallowed = 1;
2881 $original_file = $conf->fournisseur->dir_temp.'/'.$original_file;
2882 } elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp)) {
2883 // Wrapping pour les graph des produits
2884 $accessallowed = 1;
2885 $original_file = $conf->product->multidir_temp[$entity].'/'.$original_file;
2886 } elseif ($modulepart == 'barcode') {
2887 // Wrapping pour les code barre
2888 $accessallowed = 1;
2889 // If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
2890 //$original_file=$conf->barcode->dir_temp.'/'.$original_file;
2891 $original_file = '';
2892 } elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp)) {
2893 // Wrapping for icon of background of mailings
2894 $accessallowed = 1;
2895 $original_file = $conf->mailing->dir_temp.'/'.$original_file;
2896 } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
2897 // Wrapping pour le scanner
2898 $accessallowed = 1;
2899 $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
2900 } elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output)) {
2901 // Wrapping pour les images fckeditor
2902 $accessallowed = 1;
2903 $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
2904 } elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) {
2905 // Wrapping for users
2906 $canreaduser = (!empty($fuser->admin) || $fuser->rights->user->user->{$lire});
2907 if ($fuser->id == (int) $refname) {
2908 $canreaduser = 1;
2909 } // A user can always read its own card
2910 if ($canreaduser || preg_match('/^specimen/i', $original_file)) {
2911 $accessallowed = 1;
2912 }
2913 $original_file = $conf->user->dir_output.'/'.$original_file;
2914 } elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->multidir_output[$entity])) {
2915 // Wrapping for third parties
2916 if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
2917 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2918 }
2919 if ($fuser->hasRight('societe', $lire) || preg_match('/^specimen/i', $original_file)) {
2920 $accessallowed = 1;
2921 }
2922 $original_file = $conf->societe->multidir_output[$entity].'/'.$original_file;
2923 $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe').")";
2924 } elseif ($modulepart == 'contact' && !empty($conf->societe->multidir_output[$entity])) {
2925 // Wrapping for contact
2926 if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
2927 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2928 }
2929 if ($fuser->hasRight('societe', $lire)) {
2930 $accessallowed = 1;
2931 }
2932 $original_file = $conf->societe->multidir_output[$entity].'/contact/'.$original_file;
2933 } elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->multidir_output[$entity])) {
2934 // Wrapping for invoices
2935 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2936 $accessallowed = 1;
2937 }
2938 $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2939 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('invoice').")";
2940 } elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) {
2941 // Wrapping for mass actions
2942 if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
2943 $accessallowed = 1;
2944 }
2945 $original_file = $conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2946 } elseif ($modulepart == 'massfilesarea_orders') {
2947 if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
2948 $accessallowed = 1;
2949 }
2950 $original_file = $conf->commande->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2951 } elseif ($modulepart == 'massfilesarea_sendings') {
2952 if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
2953 $accessallowed = 1;
2954 }
2955 $original_file = $conf->expedition->dir_output.'/sending/temp/massgeneration/'.$user->id.'/'.$original_file;
2956 } elseif ($modulepart == 'massfilesarea_invoices') {
2957 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2958 $accessallowed = 1;
2959 }
2960 $original_file = $conf->facture->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2961 } elseif ($modulepart == 'massfilesarea_expensereport') {
2962 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2963 $accessallowed = 1;
2964 }
2965 $original_file = $conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2966 } elseif ($modulepart == 'massfilesarea_interventions') {
2967 if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
2968 $accessallowed = 1;
2969 }
2970 $original_file = $conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2971 } elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) {
2972 if ($fuser->hasRight('supplier_proposal', $lire) || preg_match('/^specimen/i', $original_file)) {
2973 $accessallowed = 1;
2974 }
2975 $original_file = $conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2976 } elseif ($modulepart == 'massfilesarea_supplier_order') {
2977 if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
2978 $accessallowed = 1;
2979 }
2980 $original_file = $conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2981 } elseif ($modulepart == 'massfilesarea_supplier_invoice') {
2982 if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2983 $accessallowed = 1;
2984 }
2985 $original_file = $conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2986 } elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) {
2987 if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
2988 $accessallowed = 1;
2989 }
2990 $original_file = $conf->contrat->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2991 } elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) {
2992 // Wrapping for interventions
2993 if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
2994 $accessallowed = 1;
2995 }
2996 $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2997 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2998 } elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) {
2999 // Wrapping pour les deplacements et notes de frais
3000 if ($fuser->hasRight('deplacement', $lire) || preg_match('/^specimen/i', $original_file)) {
3001 $accessallowed = 1;
3002 }
3003 $original_file = $conf->deplacement->dir_output.'/'.$original_file;
3004 //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3005 } elseif (($modulepart == 'propal' || $modulepart == 'propale') && isset($conf->propal->multidir_output[$entity])) {
3006 // Wrapping pour les propales
3007 if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
3008 $accessallowed = 1;
3009 }
3010 $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
3011 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('propal').")";
3012 } elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->multidir_output[$entity])) {
3013 // Wrapping pour les commandes
3014 if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3015 $accessallowed = 1;
3016 }
3017 $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
3018 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")";
3019 } elseif ($modulepart == 'project' && !empty($conf->project->multidir_output[$entity])) {
3020 // Wrapping pour les projets
3021 if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3022 $accessallowed = 1;
3023 // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3024 if ($refname && !preg_match('/^specimen/i', $original_file)) {
3025 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
3026 $tmpproject = new Project($db);
3027 $tmpproject->fetch('', $refname);
3028 $accessallowed = checkUserAccessToObject($user, array('projet'), $tmpproject->id, 'projet&project', '', '', 'rowid', '');
3029 }
3030 }
3031 $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3032 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3033 } elseif ($modulepart == 'project_task' && !empty($conf->project->multidir_output[$entity])) {
3034 if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3035 $accessallowed = 1;
3036 // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3037 if ($refname && !preg_match('/^specimen/i', $original_file)) {
3038 include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
3039 $tmptask = new Task($db);
3040 $tmptask->fetch('', $refname);
3041 $accessallowed = checkUserAccessToObject($user, array('projet_task'), $tmptask->id, 'projet_task&project', '', '', 'rowid', '');
3042 }
3043 }
3044 $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3045 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3046 } elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) {
3047 // Wrapping pour les commandes fournisseurs
3048 if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
3049 $accessallowed = 1;
3050 }
3051 $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
3052 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3053 } elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) {
3054 // Wrapping pour les factures fournisseurs
3055 if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3056 $accessallowed = 1;
3057 }
3058 $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
3059 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3060 } elseif ($modulepart == 'supplier_payment') {
3061 // Wrapping pour les rapport de paiements
3062 if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3063 $accessallowed = 1;
3064 }
3065 $original_file = $conf->fournisseur->payment->dir_output.'/'.$original_file;
3066 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3067 } elseif ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) {
3068 // Wrapping pour les rapport de paiements
3069 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3070 $accessallowed = 1;
3071 }
3072 if ($fuser->socid > 0) {
3073 $original_file = $conf->facture->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file;
3074 } else {
3075 $original_file = $conf->facture->dir_output.'/payments/'.$original_file;
3076 }
3077 } elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) {
3078 // Wrapping for accounting exports
3079 if ($fuser->hasRight('accounting', 'bind', 'write') || preg_match('/^specimen/i', $original_file)) {
3080 $accessallowed = 1;
3081 }
3082 $original_file = $conf->accounting->dir_output.'/'.$original_file;
3083 } elseif (($modulepart == 'expedition' || $modulepart == 'shipment') && !empty($conf->expedition->dir_output)) {
3084 // Wrapping pour les expedition
3085 if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
3086 $accessallowed = 1;
3087 }
3088 $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'sending/') === 0 ? '' : 'sending/').$original_file;
3089 //$original_file = $conf->expedition->dir_output."/".$original_file;
3090 } elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output)) {
3091 // Delivery Note Wrapping
3092 if ($fuser->hasRight('expedition', 'delivery', $lire) || preg_match('/^specimen/i', $original_file)) {
3093 $accessallowed = 1;
3094 }
3095 $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'receipt/') === 0 ? '' : 'receipt/').$original_file;
3096 } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
3097 // Wrapping pour les actions
3098 if ($fuser->hasRight('agenda', 'myactions', $read) || preg_match('/^specimen/i', $original_file)) {
3099 $accessallowed = 1;
3100 }
3101 $original_file = $conf->agenda->dir_output.'/'.$original_file;
3102 } elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) {
3103 // Wrapping pour les actions
3104 if ($fuser->hasRight('agenda', 'allactions', $read) || preg_match('/^specimen/i', $original_file)) {
3105 $accessallowed = 1;
3106 }
3107 $original_file = $conf->agenda->dir_temp."/".$original_file;
3108 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
3109 // Wrapping pour les produits et services
3110 if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) {
3111 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3112 }
3113 if (($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) || preg_match('/^specimen/i', $original_file)) {
3114 $accessallowed = 1;
3115 }
3116 if (isModEnabled("product")) {
3117 $original_file = $conf->product->multidir_output[$entity].'/'.$original_file;
3118 } elseif (isModEnabled("service")) {
3119 $original_file = $conf->service->multidir_output[$entity].'/'.$original_file;
3120 }
3121 } elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') {
3122 // Wrapping pour les lots produits
3123 if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) {
3124 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3125 }
3126 if (($fuser->hasRight('produit', $lire)) || preg_match('/^specimen/i', $original_file)) {
3127 $accessallowed = 1;
3128 }
3129 if (isModEnabled('productbatch')) {
3130 $original_file = $conf->productbatch->multidir_output[$entity].'/'.$original_file;
3131 }
3132 } elseif ($modulepart == 'movement' || $modulepart == 'mouvement') {
3133 // Wrapping for stock movements
3134 if (empty($entity) || empty($conf->stock->multidir_output[$entity])) {
3135 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3136 }
3137 if (($fuser->hasRight('stock', $lire) || $fuser->hasRight('stock', 'movement', $lire) || $fuser->hasRight('stock', 'mouvement', $lire)) || preg_match('/^specimen/i', $original_file)) {
3138 $accessallowed = 1;
3139 }
3140 if (isModEnabled('stock')) {
3141 $original_file = $conf->stock->multidir_output[$entity].'/movement/'.$original_file;
3142 }
3143 } elseif ($modulepart == 'contract' && !empty($conf->contrat->multidir_output[$entity])) {
3144 // Wrapping pour les contrats
3145 if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
3146 $accessallowed = 1;
3147 }
3148 $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
3149 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract').")";
3150 } elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) {
3151 // Wrapping pour les dons
3152 if ($fuser->hasRight('don', $lire) || preg_match('/^specimen/i', $original_file)) {
3153 $accessallowed = 1;
3154 }
3155 $original_file = $conf->don->dir_output.'/'.$original_file;
3156 } elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) {
3157 // Wrapping pour les dons
3158 if ($fuser->hasRight('resource', $read) || preg_match('/^specimen/i', $original_file)) {
3159 $accessallowed = 1;
3160 }
3161 $original_file = $conf->resource->dir_output.'/'.$original_file;
3162 } elseif (($modulepart == 'remisecheque' || $modulepart == 'chequereceipt') && !empty($conf->bank->dir_output)) {
3163 // Wrapping pour les remises de cheques
3164 if ($fuser->hasRight('banque', $lire) || preg_match('/^specimen/i', $original_file)) {
3165 $accessallowed = 1;
3166 }
3167
3168 $original_file = $conf->bank->dir_output.'/checkdeposits/'.$original_file; // original_file should contains relative path so include the get_exdir result
3169 } elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) {
3170 // Wrapping for bank
3171 if ($fuser->hasRight('banque', $lire)) {
3172 $accessallowed = 1;
3173 }
3174 $original_file = $conf->bank->dir_output.'/'.$original_file;
3175 } elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) {
3176 // Wrapping for export module
3177 // Note that a test may not be required because we force the dir of download on the directory of the user that export
3178 $accessallowed = $user->rights->export->lire;
3179 $original_file = $conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file;
3180 } elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) {
3181 // Wrapping for import module
3182 $accessallowed = $user->rights->import->run;
3183 $original_file = $conf->import->dir_temp.'/'.$original_file;
3184 } elseif ($modulepart == 'recruitment' && !empty($conf->recruitment->dir_output)) {
3185 // Wrapping for recruitment module
3186 $accessallowed = $user->hasRight('recruitment', 'recruitmentjobposition', 'read');
3187 $original_file = $conf->recruitment->dir_output.'/'.$original_file;
3188 } elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) {
3189 // Wrapping for wysiwyg editor
3190 $accessallowed = 1;
3191 $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
3192 } elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) {
3193 // Wrapping for backups
3194 if ($fuser->admin) {
3195 $accessallowed = 1;
3196 }
3197 $original_file = $conf->admin->dir_output.'/'.$original_file;
3198 } elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) {
3199 // Wrapping for upload file test
3200 if ($fuser->admin) {
3201 $accessallowed = 1;
3202 }
3203 $original_file = $conf->admin->dir_temp.'/'.$original_file;
3204 } elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) {
3205 // Wrapping pour BitTorrent
3206 $accessallowed = 1;
3207 $dir = 'files';
3208 if (dol_mimetype($original_file) == 'application/x-bittorrent') {
3209 $dir = 'torrents';
3210 }
3211 $original_file = $conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
3212 } elseif ($modulepart == 'member' && !empty($conf->adherent->dir_output)) {
3213 // Wrapping pour Foundation module
3214 if ($fuser->hasRight('adherent', $lire) || preg_match('/^specimen/i', $original_file)) {
3215 $accessallowed = 1;
3216 }
3217 $original_file = $conf->adherent->dir_output.'/'.$original_file;
3218 } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
3219 // Wrapping for Scanner
3220 $accessallowed = 1;
3221 $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
3222 // If modulepart=module_user_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser
3223 // If modulepart=module_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp
3224 // If modulepart=module_user Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser
3225 // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3226 // If modulepart=module-abc Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3227 } else {
3228 // GENERIC Wrapping
3229 //var_dump($modulepart);
3230 //var_dump($original_file);
3231 if (preg_match('/^specimen/i', $original_file)) {
3232 $accessallowed = 1; // If link to a file called specimen. Test must be done before changing $original_file int full path.
3233 }
3234 if ($fuser->admin) {
3235 $accessallowed = 1; // If user is admin
3236 }
3237
3238 $tmpmodulepart = explode('-', $modulepart);
3239 if (!empty($tmpmodulepart[1])) {
3240 $modulepart = $tmpmodulepart[0];
3241 $original_file = $tmpmodulepart[1].'/'.$original_file;
3242 }
3243
3244 // Define $accessallowed
3245 $reg = array();
3246 if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) {
3247 $tmpmodule = $reg[1];
3248 if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3249 dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3250 exit;
3251 }
3252 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3253 $accessallowed = 1;
3254 }
3255 $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
3256 } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) {
3257 $tmpmodule = $reg[1];
3258 if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3259 dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3260 exit;
3261 }
3262 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3263 $accessallowed = 1;
3264 }
3265 $original_file = $conf->$tmpmodule->dir_temp.'/'.$original_file;
3266 } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) {
3267 $tmpmodule = $reg[1];
3268 if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3269 dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3270 exit;
3271 }
3272 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3273 $accessallowed = 1;
3274 }
3275 $original_file = $conf->$tmpmodule->dir_output.'/'.$fuser->id.'/'.$original_file;
3276 } elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) {
3277 $tmpmodule = $reg[1];
3278 if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3279 dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3280 exit;
3281 }
3282 if ($fuser->hasRight($tmpmodule, $lire) || preg_match('/^specimen/i', $original_file)) {
3283 $accessallowed = 1;
3284 }
3285 $original_file = $conf->$tmpmodule->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3286 } else {
3287 if (empty($conf->$modulepart->dir_output)) { // modulepart not supported
3288 dol_print_error('', '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.');
3289 exit;
3290 }
3291
3292 // Check fuser->rights->modulepart->myobject->read and fuser->rights->modulepart->read
3293 $partsofdirinoriginalfile = explode('/', $original_file);
3294 if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use)
3295 $partofdirinoriginalfile = $partsofdirinoriginalfile[0];
3296 if ($partofdirinoriginalfile && ($fuser->hasRight($modulepart, $partofdirinoriginalfile, 'lire') || $fuser->hasRight($modulepart, $partofdirinoriginalfile, 'read'))) {
3297 $accessallowed = 1;
3298 }
3299 }
3300 if ($fuser->hasRight($modulepart, $lire) || $fuser->hasRight($modulepart, $read)) {
3301 $accessallowed = 1;
3302 }
3303
3304 if (is_array($conf->$modulepart->multidir_output) && !empty($conf->$modulepart->multidir_output[$entity])) {
3305 $original_file = $conf->$modulepart->multidir_output[$entity].'/'.$original_file;
3306 } else {
3307 $original_file = $conf->$modulepart->dir_output.'/'.$original_file;
3308 }
3309 }
3310
3311 $parameters = array(
3312 'modulepart' => $modulepart,
3313 'original_file' => $original_file,
3314 'entity' => $entity,
3315 'fuser' => $fuser,
3316 'refname' => '',
3317 'mode' => $mode
3318 );
3319 $reshook = $hookmanager->executeHooks('checkSecureAccess', $parameters, $object);
3320 if ($reshook > 0) {
3321 if (!empty($hookmanager->resArray['original_file'])) {
3322 $original_file = $hookmanager->resArray['original_file'];
3323 }
3324 if (!empty($hookmanager->resArray['accessallowed'])) {
3325 $accessallowed = $hookmanager->resArray['accessallowed'];
3326 }
3327 if (!empty($hookmanager->resArray['sqlprotectagainstexternals'])) {
3328 $sqlprotectagainstexternals = $hookmanager->resArray['sqlprotectagainstexternals'];
3329 }
3330 }
3331 }
3332
3333 $ret = array(
3334 'accessallowed' => ($accessallowed ? 1 : 0),
3335 'sqlprotectagainstexternals' => $sqlprotectagainstexternals,
3336 'original_file' => $original_file
3337 );
3338
3339 return $ret;
3340}
3341
3350function dol_filecache($directory, $filename, $object)
3351{
3352 if (!dol_is_dir($directory)) {
3353 dol_mkdir($directory);
3354 }
3355 $cachefile = $directory.$filename;
3356 file_put_contents($cachefile, serialize($object), LOCK_EX);
3357 dolChmod($cachefile, '0644');
3358}
3359
3368function dol_cache_refresh($directory, $filename, $cachetime)
3369{
3370 $now = dol_now();
3371 $cachefile = $directory.$filename;
3372 $refresh = !file_exists($cachefile) || ($now - $cachetime) > dol_filemtime($cachefile);
3373 return $refresh;
3374}
3375
3383function dol_readcachefile($directory, $filename)
3384{
3385 $cachefile = $directory.$filename;
3386 $object = unserialize(file_get_contents($cachefile));
3387 return $object;
3388}
3389
3396function dirbasename($pathfile)
3397{
3398 return preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'\//', '', $pathfile);
3399}
3400
3401
3413function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
3414{
3415 global $conffile;
3416
3417 $exclude = 'install';
3418
3419 foreach ($dir->md5file as $file) { // $file is a simpleXMLElement
3420 $filename = $path.$file['name'];
3421 $file_list['insignature'][] = $filename;
3422 $expectedsize = (empty($file['size']) ? '' : $file['size']);
3423 $expectedmd5 = (string) $file;
3424
3425 //if (preg_match('#'.$exclude.'#', $filename)) continue;
3426
3427 if (!file_exists($pathref.'/'.$filename)) {
3428 $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize);
3429 } else {
3430 $md5_local = md5_file($pathref.'/'.$filename);
3431
3432 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
3433 $checksumconcat[] = $expectedmd5;
3434 } else {
3435 if ($md5_local != $expectedmd5) {
3436 $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize, 'md5'=>(string) $md5_local);
3437 }
3438 $checksumconcat[] = $md5_local;
3439 }
3440 }
3441 }
3442
3443 foreach ($dir->dir as $subdir) { // $subdir['name'] is '' or '/accountancy/admin' for example
3444 getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat);
3445 }
3446
3447 return $file_list;
3448}
3449
3457function dragAndDropFileUpload($htmlname)
3458{
3459 global $object, $langs;
3460
3461 $out = "";
3462 $out .= '<div id="'.$htmlname.'Message" class="dragDropAreaMessage hidden"><span>'.img_picto("", 'download').'<br>'.$langs->trans("DropFileToAddItToObject").'</span></div>';
3463 $out .= "\n<!-- JS CODE TO ENABLE DRAG AND DROP OF FILE -->\n";
3464 $out .= "<script>";
3465 $out .= '
3466 jQuery(document).ready(function() {
3467 var enterTargetDragDrop = null;
3468
3469 $("#'.$htmlname.'").addClass("cssDragDropArea");
3470
3471 $(".cssDragDropArea").on("dragenter", function(ev, ui) {
3472 var dataTransfer = ev.originalEvent.dataTransfer;
3473 var dataTypes = dataTransfer.types;
3474 //console.log(dataTransfer);
3475 //console.log(dataTypes);
3476
3477 if (!dataTypes || ($.inArray(\'Files\', dataTypes) === -1)) {
3478 // The element dragged is not a file, so we avoid the "dragenter"
3479 ev.preventDefault();
3480 return false;
3481 }
3482
3483 // Entering drop area. Highlight area
3484 console.log("dragAndDropFileUpload: We add class highlightDragDropArea")
3485 enterTargetDragDrop = ev.target;
3486 $(this).addClass("highlightDragDropArea");
3487 $("#'.$htmlname.'Message").removeClass("hidden");
3488 ev.preventDefault();
3489 });
3490
3491 $(".cssDragDropArea").on("dragleave", function(ev) {
3492 // Going out of drop area. Remove Highlight
3493 if (enterTargetDragDrop == ev.target){
3494 console.log("dragAndDropFileUpload: We remove class highlightDragDropArea")
3495 $("#'.$htmlname.'Message").addClass("hidden");
3496 $(this).removeClass("highlightDragDropArea");
3497 }
3498 });
3499
3500 $(".cssDragDropArea").on("dragover", function(ev) {
3501 ev.preventDefault();
3502 return false;
3503 });
3504
3505 $(".cssDragDropArea").on("drop", function(e) {
3506 console.log("Trigger event file dropped. fk_element='.dol_escape_js($object->id).' element='.dol_escape_js($object->element).'");
3507 e.preventDefault();
3508 fd = new FormData();
3509 fd.append("fk_element", "'.dol_escape_js($object->id).'");
3510 fd.append("element", "'.dol_escape_js($object->element).'");
3511 fd.append("token", "'.currentToken().'");
3512 fd.append("action", "linkit");
3513
3514 var dataTransfer = e.originalEvent.dataTransfer;
3515
3516 if (dataTransfer.files && dataTransfer.files.length){
3517 var droppedFiles = e.originalEvent.dataTransfer.files;
3518 $.each(droppedFiles, function(index,file){
3519 fd.append("files[]", file,file.name)
3520 });
3521 }
3522 $(".cssDragDropArea").removeClass("highlightDragDropArea");
3523 counterdragdrop = 0;
3524 $.ajax({
3525 url: "'.DOL_URL_ROOT.'/core/ajax/fileupload.php",
3526 type: "POST",
3527 processData: false,
3528 contentType: false,
3529 data: fd,
3530 success:function() {
3531 console.log("Uploaded.", arguments);
3532 /* arguments[0] is the json string of files */
3533 /* arguments[1] is the value for variable "success", can be 0 or 1 */
3534 let listoffiles = JSON.parse(arguments[0]);
3535 console.log(listoffiles);
3536 let nboferror = 0;
3537 for (let i = 0; i < listoffiles.length; i++) {
3538 console.log(listoffiles[i].error);
3539 if (listoffiles[i].error) {
3540 nboferror++;
3541 }
3542 }
3543 console.log(nboferror);
3544 if (nboferror > 0) {
3545 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorOnAtLeastOneFileUpload:warnings";
3546 } else {
3547 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=UploadFileDragDropSuccess:mesgs";
3548 }
3549 },
3550 error:function() {
3551 console.log("Error Uploading.", arguments)
3552 if (arguments[0].status == 403) {
3553 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadPermissionDenied:errors";
3554 }
3555 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadFileDragDropPermissionDenied:errors";
3556 },
3557 })
3558 });
3559 });
3560 ';
3561 $out .= "</script>\n";
3562 return $out;
3563}
Class to manage agenda events (actions)
Class to scan for virus.
Class to manage ECM files.
Class to manage Trips and Expenses.
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Class of the module paid holiday.
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_most_recent_file($dir, $regexfilter='', $excludefilter=array('(\.meta|_preview.*\.png) $', '^\.'), $nohook=false, $mode='')
Return file(s) into a directory (by default most recent)
dol_is_link($pathoffile)
Return if path is a symbolic link.
dol_compare_file($a, $b)
Fast compare of 2 files identified by their properties ->name, ->date and ->size.
dol_meta_create($object)
Create a meta file with document file into same directory.
dolCheckVirus($src_file)
Check virus into a file.
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition files.lib.php:37
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
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_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='')
Make control on an uploaded file from an GUI page and move it to final destination.
dol_move_dir($srcdir, $destdir, $overwriteifexists=1, $indexdatabase=1, $renamedircontent=1)
Move a directory into another name.
dol_fileperm($pathoffile)
Return permissions of a file.
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser='', $refname='', $mode='read')
Security check when accessing to a document (used by document.php, viewimage.php and webservices to g...
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
dol_init_file_process($pathtoscan='', $trackid='')
Scan a directory and init $_SESSION to manage uploaded files with list of all found files.
addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded', $setsharekey=0, $object=null)
Add a file into database index.
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
dol_is_url($url)
Return if path is an URL.
dol_filecache($directory, $filename, $object)
Store object in file.
dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0)
Scan a directory and return a list of files/directories.
dragAndDropFileUpload($htmlname)
Function to manage the drag and drop of a file.
dol_is_file($pathoffile)
Return if path is a file.
dol_count_nb_of_line($file)
Count number of lines in a file.
dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
dol_unescapefile($filename)
Unescape a file submitted by upload.
dol_dir_list($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:62
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).
dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null, $excludesubdir=0, $excludefileext=null)
Copy a dir to another dir.
deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded')
Delete files into database index using search criterias.
dol_readcachefile($directory, $filename)
Read object from cachefile.
dol_is_dir($folder)
Test if filename is a directory.
completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
Complete $filearray with data from database.
dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesession=0, $varfiles='addedfile', $savingdocmask='', $link=null, $trackid='', $generatethumbs=1, $object=null)
Get and save an upload file (for example after submitting a new file a mail form).
dol_cache_refresh($directory, $filename, $cachetime)
Test if Refresh needed.
dol_delete_preview($object)
Delete all preview files linked to object instance.
dol_is_dir_empty($dir)
Return if path is empty.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
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.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
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.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
utf8_check($str)
Check if a string is in UTF8.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
vignette($file, $maxWidth=160, $maxHeight=120, $extName='_small', $quality=50, $outdir='thumbs', $targetformat=0)
Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
if(!defined( 'IMAGETYPE_WEBP')) getDefaultImageSizes()
Return default values for image sizes.
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
checkUserAccessToObject($user, array $featuresarray, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='', $dbt_select='rowid', $parenttableforentity='')
Check that access by a given user to an object is ok.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.