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