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 dol_syslog("No files to delete found", LOG_DEBUG);
1452 }
1453 } else {
1454 $ok = false;
1455 if ($nophperrors) {
1456 $ok = @unlink($file_osencoded);
1457 } else {
1458 $ok = unlink($file_osencoded);
1459 }
1460 if ($ok) {
1461 if (empty($nolog)) {
1462 dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
1463 }
1464 } else {
1465 dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
1466 }
1467 }
1468
1469 return $ok;
1470 }
1471}
1472
1482function dol_delete_dir($dir, $nophperrors = 0)
1483{
1484 // Security:
1485 // We refuse transversal using .. and pipes into filenames.
1486 if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) {
1487 dol_syslog("Refused to delete dir ".$dir.' (contains invalid char sequence)', LOG_WARNING);
1488 return false;
1489 }
1490
1491 $dir_osencoded = dol_osencode($dir);
1492 return ($nophperrors ? @rmdir($dir_osencoded) : rmdir($dir_osencoded));
1493}
1494
1507function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0, $indexdatabase = 1, $nolog = 0)
1508{
1509 if (empty($nolog)) {
1510 dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG);
1511 }
1512 if (dol_is_dir($dir)) {
1513 $dir_osencoded = dol_osencode($dir);
1514 if ($handle = opendir("$dir_osencoded")) {
1515 while (false !== ($item = readdir($handle))) {
1516 if (!utf8_check($item)) {
1517 $item = utf8_encode($item); // should be useless
1518 }
1519
1520 if ($item != "." && $item != "..") {
1521 if (is_dir(dol_osencode("$dir/$item")) && !is_link(dol_osencode("$dir/$item"))) {
1522 $count = dol_delete_dir_recursive("$dir/$item", $count, $nophperrors, 0, $countdeleted, $indexdatabase, $nolog);
1523 } else {
1524 $result = dol_delete_file("$dir/$item", 1, $nophperrors, 0, null, false, $indexdatabase, $nolog);
1525 $count++;
1526 if ($result) {
1527 $countdeleted++;
1528 }
1529 //else print 'Error on '.$item."\n";
1530 }
1531 }
1532 }
1533 closedir($handle);
1534
1535 // Delete also the main directory
1536 if (empty($onlysub)) {
1537 $result = dol_delete_dir($dir, $nophperrors);
1538 $count++;
1539 if ($result) {
1540 $countdeleted++;
1541 }
1542 //else print 'Error on '.$dir."\n";
1543 }
1544 }
1545 }
1546
1547 return $count;
1548}
1549
1550
1559function dol_delete_preview($object)
1560{
1561 global $langs, $conf;
1562
1563 // Define parent dir of elements
1564 $element = $object->element;
1565
1566 if ($object->element == 'order_supplier') {
1567 $dir = $conf->fournisseur->commande->dir_output;
1568 } elseif ($object->element == 'invoice_supplier') {
1569 $dir = $conf->fournisseur->facture->dir_output;
1570 } elseif ($object->element == 'project') {
1571 $dir = $conf->project->dir_output;
1572 } elseif ($object->element == 'shipping') {
1573 $dir = $conf->expedition->dir_output.'/sending';
1574 } elseif ($object->element == 'delivery') {
1575 $dir = $conf->expedition->dir_output.'/receipt';
1576 } elseif ($object->element == 'fichinter') {
1577 $dir = $conf->ficheinter->dir_output;
1578 } else {
1579 $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1580 }
1581
1582 if (empty($dir)) {
1583 return 'ErrorObjectNoSupportedByFunction';
1584 }
1585
1586 $refsan = dol_sanitizeFileName($object->ref);
1587 $dir = $dir."/".$refsan;
1588 $filepreviewnew = $dir."/".$refsan.".pdf_preview.png";
1589 $filepreviewnewbis = $dir."/".$refsan.".pdf_preview-0.png";
1590 $filepreviewold = $dir."/".$refsan.".pdf.png";
1591
1592 // For new preview files
1593 if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) {
1594 if (!dol_delete_file($filepreviewnew, 1)) {
1595 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnew);
1596 return 0;
1597 }
1598 }
1599 if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) {
1600 if (!dol_delete_file($filepreviewnewbis, 1)) {
1601 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis);
1602 return 0;
1603 }
1604 }
1605 // For old preview files
1606 if (file_exists($filepreviewold) && is_writable($filepreviewold)) {
1607 if (!dol_delete_file($filepreviewold, 1)) {
1608 $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewold);
1609 return 0;
1610 }
1611 } else {
1612 $multiple = $filepreviewold.".";
1613 for ($i = 0; $i < 20; $i++) {
1614 $preview = $multiple.$i;
1615
1616 if (file_exists($preview) && is_writable($preview)) {
1617 if (!dol_delete_file($preview, 1)) {
1618 $object->error = $langs->trans("ErrorFailedToOpenFile", $preview);
1619 return 0;
1620 }
1621 }
1622 }
1623 }
1624
1625 return 1;
1626}
1627
1636function dol_meta_create($object)
1637{
1638 global $conf;
1639
1640 // Create meta file
1641 if (empty($conf->global->MAIN_DOC_CREATE_METAFILE)) {
1642 return 0; // By default, no metafile.
1643 }
1644
1645 // Define parent dir of elements
1646 $element = $object->element;
1647
1648 if ($object->element == 'order_supplier') {
1649 $dir = $conf->fournisseur->dir_output.'/commande';
1650 } elseif ($object->element == 'invoice_supplier') {
1651 $dir = $conf->fournisseur->dir_output.'/facture';
1652 } elseif ($object->element == 'project') {
1653 $dir = $conf->project->dir_output;
1654 } elseif ($object->element == 'shipping') {
1655 $dir = $conf->expedition->dir_output.'/sending';
1656 } elseif ($object->element == 'delivery') {
1657 $dir = $conf->expedition->dir_output.'/receipt';
1658 } elseif ($object->element == 'fichinter') {
1659 $dir = $conf->ficheinter->dir_output;
1660 } else {
1661 $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output;
1662 }
1663
1664 if ($dir) {
1665 $object->fetch_thirdparty();
1666
1667 $objectref = dol_sanitizeFileName($object->ref);
1668 $dir = $dir."/".$objectref;
1669 $file = $dir."/".$objectref.".meta";
1670
1671 if (!is_dir($dir)) {
1672 dol_mkdir($dir);
1673 }
1674
1675 if (is_dir($dir)) {
1676 if (is_countable($object->lines) && count($object->lines) > 0) {
1677 $nblines = count($object->lines);
1678 }
1679 $client = $object->thirdparty->name." ".$object->thirdparty->address." ".$object->thirdparty->zip." ".$object->thirdparty->town;
1680 $meta = "REFERENCE=\"".$object->ref."\"
1681 DATE=\"" . dol_print_date($object->date, '')."\"
1682 NB_ITEMS=\"" . $nblines."\"
1683 CLIENT=\"" . $client."\"
1684 AMOUNT_EXCL_TAX=\"" . $object->total_ht."\"
1685 AMOUNT=\"" . $object->total_ttc."\"\n";
1686
1687 for ($i = 0; $i < $nblines; $i++) {
1688 //Pour les articles
1689 $meta .= "ITEM_".$i."_QUANTITY=\"".$object->lines[$i]->qty."\"
1690 ITEM_" . $i."_AMOUNT_WO_TAX=\"".$object->lines[$i]->total_ht."\"
1691 ITEM_" . $i."_VAT=\"".$object->lines[$i]->tva_tx."\"
1692 ITEM_" . $i."_DESCRIPTION=\"".str_replace("\r\n", "", nl2br($object->lines[$i]->desc))."\"
1693 ";
1694 }
1695 }
1696
1697 $fp = fopen($file, "w");
1698 fputs($fp, $meta);
1699 fclose($fp);
1700
1701 dolChmod($file);
1702
1703 return 1;
1704 } else {
1705 dol_syslog('FailedToDetectDirInDolMetaCreateFor'.$object->element, LOG_WARNING);
1706 }
1707
1708 return 0;
1709}
1710
1711
1712
1721function dol_init_file_process($pathtoscan = '', $trackid = '')
1722{
1723 $listofpaths = array();
1724 $listofnames = array();
1725 $listofmimes = array();
1726
1727 if ($pathtoscan) {
1728 $listoffiles = dol_dir_list($pathtoscan, 'files');
1729 foreach ($listoffiles as $key => $val) {
1730 $listofpaths[] = $val['fullname'];
1731 $listofnames[] = $val['name'];
1732 $listofmimes[] = dol_mimetype($val['name']);
1733 }
1734 }
1735 $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1736 $_SESSION["listofpaths".$keytoavoidconflict] = join(';', $listofpaths);
1737 $_SESSION["listofnames".$keytoavoidconflict] = join(';', $listofnames);
1738 $_SESSION["listofmimes".$keytoavoidconflict] = join(';', $listofmimes);
1739}
1740
1741
1759function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null)
1760{
1761
1762 global $db, $user, $conf, $langs;
1763
1764 $res = 0;
1765
1766 if (!empty($_FILES[$varfiles])) { // For view $_FILES[$varfiles]['error']
1767 dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG);
1768 $maxfilesinform = getDolGlobalInt("MAIN_SECURITY_MAX_ATTACHMENT_ON_FORMS", 10);
1769 if (is_array($_FILES[$varfiles]["name"]) && count($_FILES[$varfiles]["name"]) > $maxfilesinform) {
1770 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1771 setEventMessages($langs->trans("ErrorTooMuchFileInForm", $maxfilesinform), null, "errors");
1772 return -1;
1773 }
1774 $result = dol_mkdir($upload_dir);
1775 // var_dump($result);exit;
1776 if ($result >= 0) {
1777 $TFile = $_FILES[$varfiles];
1778 if (!is_array($TFile['name'])) {
1779 foreach ($TFile as $key => &$val) {
1780 $val = array($val);
1781 }
1782 }
1783
1784 $nbfile = count($TFile['name']);
1785 $nbok = 0;
1786 for ($i = 0; $i < $nbfile; $i++) {
1787 if (empty($TFile['name'][$i])) {
1788 continue; // For example, when submitting a form with no file name
1789 }
1790
1791 // Define $destfull (path to file including filename) and $destfile (only filename)
1792 $destfull = $upload_dir."/".$TFile['name'][$i];
1793 $destfile = $TFile['name'][$i];
1794 $destfilewithoutext = preg_replace('/\.[^\.]+$/', '', $destfile);
1795
1796 if ($savingdocmask && strpos($savingdocmask, $destfilewithoutext) !== 0) {
1797 $destfull = $upload_dir."/".preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask);
1798 $destfile = preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask);
1799 }
1800
1801 $filenameto = basename($destfile);
1802 if (preg_match('/^\./', $filenameto)) {
1803 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1804 setEventMessages($langs->trans("ErrorFilenameCantStartWithDot", $filenameto), null, 'errors');
1805 break;
1806 }
1807
1808 // dol_sanitizeFileName the file name and lowercase extension
1809 $info = pathinfo($destfull);
1810 $destfull = $info['dirname'].'/'.dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1811 $info = pathinfo($destfile);
1812 $destfile = dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : ''));
1813
1814 // We apply dol_string_nohtmltag also to clean file names (this remove duplicate spaces) because
1815 // this function is also applied when we rename and when we make try to download file (by the GETPOST(filename, 'alphanohtml') call).
1816 $destfile = dol_string_nohtmltag($destfile);
1817 $destfull = dol_string_nohtmltag($destfull);
1818
1819 // Check that filename is not the one of a reserved allowed CLI command
1820 global $dolibarr_main_restrict_os_commands;
1821 if (!empty($dolibarr_main_restrict_os_commands)) {
1822 $arrayofallowedcommand = explode(',', $dolibarr_main_restrict_os_commands);
1823 $arrayofallowedcommand = array_map('trim', $arrayofallowedcommand);
1824 if (in_array($destfile, $arrayofallowedcommand)) {
1825 $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
1826 setEventMessages($langs->trans("ErrorFilenameReserved", $destfile), null, 'errors');
1827 return -1;
1828 }
1829 }
1830
1831 // Move file from temp directory to final directory. A .noexe may also be appended on file name.
1832 $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir);
1833
1834 if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists'
1835 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
1836
1837 $tmparraysize = getDefaultImageSizes();
1838 $maxwidthsmall = $tmparraysize['maxwidthsmall'];
1839 $maxheightsmall = $tmparraysize['maxheightsmall'];
1840 $maxwidthmini = $tmparraysize['maxwidthmini'];
1841 $maxheightmini = $tmparraysize['maxheightmini'];
1842 //$quality = $tmparraysize['quality'];
1843 $quality = 50; // For thumbs, we force quality to 50
1844
1845 // Generate thumbs.
1846 if ($generatethumbs) {
1847 if (image_format_supported($destfull) == 1) {
1848 // Create thumbs
1849 // We can't use $object->addThumbs here because there is no $object known
1850
1851 // Used on logon for example
1852 $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', $quality, "thumbs");
1853 // Create mini thumbs for image (Ratio is near 16/9)
1854 // Used on menu or for setup page for example
1855 $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', $quality, "thumbs");
1856 }
1857 }
1858
1859 // Update session
1860 if (empty($donotupdatesession)) {
1861 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1862 $formmail = new FormMail($db);
1863 $formmail->trackid = $trackid;
1864 $formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
1865 }
1866
1867 // Update index table of files (llx_ecm_files)
1868 if ($donotupdatesession == 1) {
1869 $sharefile = 0;
1870 if ($TFile['type'][$i] == 'application/pdf' && strpos($_SERVER["REQUEST_URI"], 'product') !== false && !empty($conf->global->PRODUCT_ALLOW_EXTERNAL_DOWNLOAD)) $sharefile = 1;
1871 $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', $sharefile, $object);
1872 if ($result < 0) {
1873 if ($allowoverwrite) {
1874 // Do not show error message. We can have an error due to DB_ERROR_RECORD_ALREADY_EXISTS
1875 } else {
1876 setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', null, 'warnings');
1877 }
1878 }
1879 }
1880
1881 $nbok++;
1882 } else {
1883 $langs->load("errors");
1884 if ($resupload < 0) { // Unknown error
1885 setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
1886 } elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) { // Files infected by a virus
1887 setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors');
1888 } else // Known error
1889 {
1890 setEventMessages($langs->trans($resupload), null, 'errors');
1891 }
1892 }
1893 }
1894 if ($nbok > 0) {
1895 $res = 1;
1896 setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs');
1897 }
1898 } else {
1899 setEventMessages($langs->trans("ErrorFailedToCreateDir", $upload_dir), null, 'errors');
1900 }
1901 } elseif ($link) {
1902 require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
1903 $linkObject = new Link($db);
1904 $linkObject->entity = $conf->entity;
1905 $linkObject->url = $link;
1906 $linkObject->objecttype = GETPOST('objecttype', 'alpha');
1907 $linkObject->objectid = GETPOST('objectid', 'int');
1908 $linkObject->label = GETPOST('label', 'alpha');
1909 $res = $linkObject->create($user);
1910 $langs->load('link');
1911 if ($res > 0) {
1912 setEventMessages($langs->trans("LinkComplete"), null, 'mesgs');
1913 } else {
1914 setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors');
1915 }
1916 } else {
1917 $langs->load("errors");
1918 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
1919 }
1920
1921 return $res;
1922}
1923
1924
1936function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '')
1937{
1938 global $db, $user, $conf, $langs, $_FILES;
1939
1940 $keytodelete = $filenb;
1941 $keytodelete--;
1942
1943 $listofpaths = array();
1944 $listofnames = array();
1945 $listofmimes = array();
1946 $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid;
1947 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
1948 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
1949 }
1950 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
1951 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
1952 }
1953 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
1954 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
1955 }
1956
1957 if ($keytodelete >= 0) {
1958 $pathtodelete = $listofpaths[$keytodelete];
1959 $filetodelete = $listofnames[$keytodelete];
1960 if (empty($donotdeletefile)) {
1961 $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file
1962 } else {
1963 $result = 0;
1964 }
1965 if ($result >= 0) {
1966 if (empty($donotdeletefile)) {
1967 $langs->load("other");
1968 setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs');
1969 }
1970 if (empty($donotupdatesession)) {
1971 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1972 $formmail = new FormMail($db);
1973 $formmail->trackid = $trackid;
1974 $formmail->remove_attached_files($keytodelete);
1975 }
1976 }
1977 }
1978}
1979
1980
1994function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null)
1995{
1996 global $db, $user, $conf;
1997
1998 $result = 0;
1999
2000 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2001
2002 if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir
2003 $filename = basename(preg_replace('/\.noexe$/', '', $file));
2004 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2005 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2006
2007 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
2008 $ecmfile = new EcmFiles($db);
2009 $ecmfile->filepath = $rel_dir;
2010 $ecmfile->filename = $filename;
2011 $ecmfile->label = md5_file(dol_osencode($dir.'/'.$file)); // MD5 of file content
2012 $ecmfile->fullpath_orig = $fullpathorig;
2013 $ecmfile->gen_or_uploaded = $mode;
2014 $ecmfile->description = ''; // indexed content
2015 $ecmfile->keywords = ''; // keyword content
2016
2017 if (is_object($object) && $object->id > 0) {
2018 $ecmfile->src_object_id = $object->id;
2019 if (isset($object->table_element)) {
2020 $ecmfile->src_object_type = $object->table_element;
2021 } else {
2022 dol_syslog('Error: object ' . get_class($object) . ' has no table_element attribute.');
2023 return -1;
2024 }
2025 if (isset($object->src_object_description)) $ecmfile->description = $object->src_object_description;
2026 if (isset($object->src_object_keywords)) $ecmfile->keywords = $object->src_object_keywords;
2027 }
2028
2029 if (!empty($conf->global->MAIN_FORCE_SHARING_ON_ANY_UPLOADED_FILE)) {
2030 $setsharekey = 1;
2031 }
2032
2033 if ($setsharekey) {
2034 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
2035 $ecmfile->share = getRandomPassword(true);
2036 }
2037
2038 $result = $ecmfile->create($user);
2039 if ($result < 0) {
2040 dol_syslog($ecmfile->error);
2041 }
2042 }
2043
2044 return $result;
2045}
2046
2055function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded')
2056{
2057 global $conf, $db, $user;
2058
2059 $error = 0;
2060
2061 if (empty($dir)) {
2062 dol_syslog("deleteFilesIntoDatabaseIndex: dir parameter can't be empty", LOG_ERR);
2063 return -1;
2064 }
2065
2066 $db->begin();
2067
2068 $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir);
2069
2070 $filename = basename($file);
2071 $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
2072 $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
2073
2074 if (!$error) {
2075 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'ecm_files';
2076 $sql .= ' WHERE entity = '.$conf->entity;
2077 $sql .= " AND filepath = '".$db->escape($rel_dir)."'";
2078 if ($file) {
2079 $sql .= " AND filename = '".$db->escape($file)."'";
2080 }
2081 if ($mode) {
2082 $sql .= " AND gen_or_uploaded = '".$db->escape($mode)."'";
2083 }
2084
2085 $resql = $db->query($sql);
2086 if (!$resql) {
2087 $error++;
2088 dol_syslog(__METHOD__.' '.$db->lasterror(), LOG_ERR);
2089 }
2090 }
2091
2092 // Commit or rollback
2093 if ($error) {
2094 $db->rollback();
2095 return -1 * $error;
2096 } else {
2097 $db->commit();
2098 return 1;
2099 }
2100}
2101
2102
2114function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '')
2115{
2116 if (class_exists('Imagick')) {
2117 $image = new Imagick();
2118 try {
2119 $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : '');
2120 //var_dump($filetoconvert);
2121 $ret = $image->readImage($filetoconvert);
2122 } catch (Exception $e) {
2123 $ext = pathinfo($fileinput, PATHINFO_EXTENSION);
2124 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);
2125 return 0;
2126 }
2127 if ($ret) {
2128 $ret = $image->setImageFormat($ext);
2129 if ($ret) {
2130 if (empty($fileoutput)) {
2131 $fileoutput = $fileinput.".".$ext;
2132 }
2133
2134 $count = $image->getNumberImages();
2135
2136 if (!dol_is_file($fileoutput) || is_writeable($fileoutput)) {
2137 try {
2138 $ret = $image->writeImages($fileoutput, true);
2139 } catch (Exception $e) {
2140 dol_syslog($e->getMessage(), LOG_WARNING);
2141 }
2142 } else {
2143 dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR);
2144 }
2145 if ($ret) {
2146 return $count;
2147 } else {
2148 return -3;
2149 }
2150 } else {
2151 return -2;
2152 }
2153 } else {
2154 return -1;
2155 }
2156 } else {
2157 return 0;
2158 }
2159}
2160
2161
2173function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring = null)
2174{
2175 global $conf;
2176
2177 $foundhandler = 0;
2178
2179 try {
2180 dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile);
2181
2182 $data = implode("", file(dol_osencode($inputfile)));
2183 if ($mode == 'gz' && function_exists('gzencode')) {
2184 $foundhandler = 1;
2185 $compressdata = gzencode($data, 9);
2186 } elseif ($mode == 'bz' && function_exists('bzcompress')) {
2187 $foundhandler = 1;
2188 $compressdata = bzcompress($data, 9);
2189 } elseif ($mode == 'zstd' && function_exists('zstd_compress')) {
2190 $foundhandler = 1;
2191 $compressdata = zstd_compress($data, 9);
2192 } elseif ($mode == 'zip') {
2193 if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) {
2194 $foundhandler = 1;
2195
2196 $rootPath = realpath($inputfile);
2197
2198 dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath);
2199 $zip = new ZipArchive;
2200
2201 if ($zip->open($outputfile, ZipArchive::CREATE) !== true) {
2202 $errorstring = "dol_compress_file failure - Failed to open file ".$outputfile."\n";
2203 dol_syslog($errorstring, LOG_ERR);
2204
2205 global $errormsg;
2206 $errormsg = $errorstring;
2207
2208 return -6;
2209 }
2210
2211 // Create recursive directory iterator
2213 $files = new RecursiveIteratorIterator(
2214 new RecursiveDirectoryIterator($rootPath),
2215 RecursiveIteratorIterator::LEAVES_ONLY
2216 );
2217
2218 foreach ($files as $name => $file) {
2219 // Skip directories (they would be added automatically)
2220 if (!$file->isDir()) {
2221 // Get real and relative path for current file
2222 $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2223 $fileName = $file->getFilename();
2224 $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2225
2226 //$relativePath = substr($fileFullRealPath, strlen($rootPath) + 1);
2227 $relativePath = substr(($filePath ? $filePath.'/' : '').$fileName, strlen($rootPath) + 1);
2228
2229 // Add current file to archive
2230 $zip->addFile($fileFullRealPath, $relativePath);
2231 }
2232 }
2233
2234 // Zip archive will be created only after closing object
2235 $zip->close();
2236
2237 dol_syslog("dol_compress_file success - ".count($zip->numFiles)." files");
2238 return 1;
2239 }
2240
2241 if (defined('ODTPHP_PATHTOPCLZIP')) {
2242 $foundhandler = 1;
2243
2244 include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2245 $archive = new PclZip($outputfile);
2246 $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2247
2248 if ($result === 0) {
2249 global $errormsg;
2250 $errormsg = $archive->errorInfo(true);
2251
2252 if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) {
2253 $errorstring = "PCLZIP_ERR_WRITE_OPEN_FAIL";
2254 dol_syslog("dol_compress_file error - archive->errorCode() = PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR);
2255 return -4;
2256 }
2257
2258 $errorstring = "dol_compress_file error archive->errorCode = ".$archive->errorCode()." errormsg=".$errormsg;
2259 dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR);
2260 return -3;
2261 } else {
2262 dol_syslog("dol_compress_file success - ".count($result)." files");
2263 return 1;
2264 }
2265 }
2266 }
2267
2268 if ($foundhandler) {
2269 $fp = fopen($outputfile, "w");
2270 fwrite($fp, $compressdata);
2271 fclose($fp);
2272 return 1;
2273 } else {
2274 $errorstring = "Try to zip with format ".$mode." with no handler for this format";
2275 dol_syslog($errorstring, LOG_ERR);
2276
2277 global $errormsg;
2278 $errormsg = $errorstring;
2279 return -2;
2280 }
2281 } catch (Exception $e) {
2282 global $langs, $errormsg;
2283 $langs->load("errors");
2284 $errormsg = $langs->trans("ErrorFailedToWriteInDir");
2285
2286 $errorstring = "Failed to open file ".$outputfile;
2287 dol_syslog($errorstring, LOG_ERR);
2288 return -1;
2289 }
2290}
2291
2300function dol_uncompress($inputfile, $outputdir)
2301{
2302 global $conf, $langs, $db;
2303
2304 $fileinfo = pathinfo($inputfile);
2305 $fileinfo["extension"] = strtolower($fileinfo["extension"]);
2306
2307 if ($fileinfo["extension"] == "zip") {
2308 if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS)) {
2309 dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
2310 include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2311 $archive = new PclZip($inputfile);
2312
2313 // We create output dir manually, so it uses the correct permission (When created by the archive->extract, dir is rwx for everybody).
2314 dol_mkdir(dol_sanitizePathName($outputdir));
2315
2316 // Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .."
2317 $result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/');
2318
2319 if (!is_array($result) && $result <= 0) {
2320 return array('error'=>$archive->errorInfo(true));
2321 } else {
2322 $ok = 1;
2323 $errmsg = '';
2324 // Loop on each file to check result for unzipping file
2325 foreach ($result as $key => $val) {
2326 if ($val['status'] == 'path_creation_fail') {
2327 $langs->load("errors");
2328 $ok = 0;
2329 $errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']);
2330 break;
2331 }
2332 }
2333
2334 if ($ok) {
2335 return array();
2336 } else {
2337 return array('error'=>$errmsg);
2338 }
2339 }
2340 }
2341
2342 if (class_exists('ZipArchive')) { // Must install php-zip to have it
2343 dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
2344 $zip = new ZipArchive;
2345 $res = $zip->open($inputfile);
2346 if ($res === true) {
2347 //$zip->extractTo($outputdir.'/');
2348 // 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
2349 // python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/
2350 // with -l is the range of dot to go back in path.
2351 // and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py
2352 for ($i = 0; $i < $zip->numFiles; $i++) {
2353 if (preg_match('/\.\./', $zip->getNameIndex($i))) {
2354 dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING);
2355 continue; // Discard the file
2356 }
2357 $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i)));
2358 }
2359
2360 $zip->close();
2361 return array();
2362 } else {
2363 return array('error'=>'ErrUnzipFails');
2364 }
2365 }
2366
2367 return array('error'=>'ErrNoZipEngine');
2368 } elseif (in_array($fileinfo["extension"], array('gz', 'bz2', 'zst'))) {
2369 include_once DOL_DOCUMENT_ROOT."/core/class/utils.class.php";
2370 $utils = new Utils($db);
2371
2372 dol_mkdir(dol_sanitizePathName($outputdir));
2373 $outputfilename = escapeshellcmd(dol_sanitizePathName($outputdir).'/'.dol_sanitizeFileName($fileinfo["filename"]));
2374 dol_delete_file($outputfilename.'.tmp');
2375 dol_delete_file($outputfilename.'.err');
2376
2377 $extension = strtolower(pathinfo($fileinfo["filename"], PATHINFO_EXTENSION));
2378 if ($extension == "tar") {
2379 $cmd = 'tar -C '.escapeshellcmd(dol_sanitizePathName($outputdir)).' -xvf '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2380
2381 $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, $outputfilename.'.err', 0);
2382 if ($resarray["result"] != 0) {
2383 $resarray["error"] .= file_get_contents($outputfilename.'.err');
2384 }
2385 } else {
2386 $program = "";
2387 if ($fileinfo["extension"] == "gz") {
2388 $program = 'gzip';
2389 } elseif ($fileinfo["extension"] == "bz2") {
2390 $program = 'bzip2';
2391 } elseif ($fileinfo["extension"] == "zst") {
2392 $program = 'zstd';
2393 } else {
2394 return array('error'=>'ErrorBadFileExtension');
2395 }
2396 $cmd = $program.' -dc '.escapeshellcmd(dol_sanitizePathName($fileinfo["dirname"]).'/'.dol_sanitizeFileName($fileinfo["basename"]));
2397 $cmd .= ' > '.$outputfilename;
2398
2399 $resarray = $utils->executeCLI($cmd, $outputfilename.'.tmp', 0, null, 1, $outputfilename.'.err');
2400 if ($resarray["result"] != 0) {
2401 $errfilecontent = @file_get_contents($outputfilename.'.err');
2402 if ($errfilecontent) {
2403 $resarray["error"] .= " - ".$errfilecontent;
2404 }
2405 }
2406 }
2407 return $resarray["result"] != 0 ? array('error' => $resarray["error"]) : array();
2408 }
2409
2410 return array('error'=>'ErrorBadFileExtension');
2411}
2412
2413
2426function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '', $rootdirinzip = '', $newmask = 0)
2427{
2428 global $conf;
2429
2430 $foundhandler = 0;
2431
2432 dol_syslog("Try to zip dir ".$inputdir." into ".$outputfile." mode=".$mode);
2433
2434 if (!dol_is_dir(dirname($outputfile)) || !is_writable(dirname($outputfile))) {
2435 global $langs, $errormsg;
2436 $langs->load("errors");
2437 $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile);
2438 return -3;
2439 }
2440
2441 try {
2442 if ($mode == 'gz') {
2443 $foundhandler = 0;
2444 } elseif ($mode == 'bz') {
2445 $foundhandler = 0;
2446 } elseif ($mode == 'zip') {
2447 /*if (defined('ODTPHP_PATHTOPCLZIP'))
2448 {
2449 $foundhandler=0; // TODO implement this
2450
2451 include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
2452 $archive = new PclZip($outputfile);
2453 $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
2454 //$archive->add($inputfile);
2455 return 1;
2456 }
2457 else*/
2458 //if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS))
2459
2460 if (class_exists('ZipArchive')) {
2461 $foundhandler = 1;
2462
2463 // Initialize archive object
2464 $zip = new ZipArchive();
2465 $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
2466 if ($result !== true) {
2467 global $langs, $errormsg;
2468 $langs->load("errors");
2469 $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile);
2470 return -4;
2471 }
2472
2473 // Create recursive directory iterator
2474 // This does not return symbolic links
2476 $files = new RecursiveIteratorIterator(
2477 new RecursiveDirectoryIterator($inputdir),
2478 RecursiveIteratorIterator::LEAVES_ONLY
2479 );
2480
2481 //var_dump($inputdir);
2482 foreach ($files as $name => $file) {
2483 // Skip directories (they would be added automatically)
2484 if (!$file->isDir()) {
2485 // Get real and relative path for current file
2486 $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
2487 $fileName = $file->getFilename();
2488 $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
2489
2490 //$relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($fileFullRealPath, strlen($inputdir) + 1);
2491 $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr(($filePath ? $filePath.'/' : '').$fileName, strlen($inputdir) + 1);
2492
2493 //var_dump($filePath);var_dump($fileFullRealPath);var_dump($relativePath);
2494 if (empty($excludefiles) || !preg_match($excludefiles, $fileFullRealPath)) {
2495 // Add current file to archive
2496 $zip->addFile($fileFullRealPath, $relativePath);
2497 }
2498 }
2499 }
2500
2501 // Zip archive will be created only after closing object
2502 $zip->close();
2503
2504 if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) {
2505 $newmask = $conf->global->MAIN_UMASK;
2506 }
2507 if (empty($newmask)) { // This should no happen
2508 dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
2509 $newmask = '0664';
2510 }
2511
2512 dolChmod($outputfile, $newmask);
2513
2514 return 1;
2515 }
2516 }
2517
2518 if (!$foundhandler) {
2519 dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR);
2520 return -2;
2521 } else {
2522 return 0;
2523 }
2524 } catch (Exception $e) {
2525 global $langs, $errormsg;
2526 $langs->load("errors");
2527 dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
2528 dol_syslog($e->getMessage(), LOG_ERR);
2529 $errormsg = $langs->trans("ErrorFailedToBuildArchive", $outputfile).' - '.$e->getMessage();
2530 return -1;
2531 }
2532}
2533
2534
2535
2546function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$', '^\.'), $nohook = false, $mode = '')
2547{
2548 $tmparray = dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook);
2549 return isset($tmparray[0])?$tmparray[0]:null;
2550}
2551
2565function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = '', $refname = '', $mode = 'read')
2566{
2567 global $conf, $db, $user, $hookmanager;
2568 global $dolibarr_main_data_root, $dolibarr_main_document_root_alt;
2569 global $object;
2570
2571 if (!is_object($fuser)) {
2572 $fuser = $user;
2573 }
2574
2575 if (empty($modulepart)) {
2576 return 'ErrorBadParameter';
2577 }
2578 if (empty($entity)) {
2579 if (!isModEnabled('multicompany')) {
2580 $entity = 1;
2581 } else {
2582 $entity = 0;
2583 }
2584 }
2585 // Fix modulepart for backward compatibility
2586 if ($modulepart == 'users') {
2587 $modulepart = 'user';
2588 }
2589 if ($modulepart == 'tva') {
2590 $modulepart = 'tax-vat';
2591 }
2592 // Fix modulepart delivery
2593 if ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) {
2594 $modulepart = 'delivery';
2595 }
2596
2597 //print 'dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity;
2598 dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
2599
2600 // We define $accessallowed and $sqlprotectagainstexternals
2601 $accessallowed = 0;
2602 $sqlprotectagainstexternals = '';
2603 $ret = array();
2604
2605 // Find the subdirectory name as the reference. For example original_file='10/myfile.pdf' -> refname='10'
2606 if (empty($refname)) {
2607 $refname = basename(dirname($original_file)."/");
2608 if ($refname == 'thumbs' || $refname == 'temp') {
2609 // If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10'
2610 $refname = basename(dirname(dirname($original_file))."/");
2611 }
2612 }
2613
2614 // Define possible keys to use for permission check
2615 $lire = 'lire';
2616 $read = 'read';
2617 $download = 'download';
2618 if ($mode == 'write') {
2619 $lire = 'creer';
2620 $read = 'write';
2621 $download = 'upload';
2622 }
2623
2624 // Wrapping for miscellaneous medias files
2625 if ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) {
2626 if (empty($entity) || empty($conf->medias->multidir_output[$entity])) {
2627 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2628 }
2629 $accessallowed = 1;
2630 $original_file = $conf->medias->multidir_output[$entity].'/'.$original_file;
2631 } elseif ($modulepart == 'logs' && !empty($dolibarr_main_data_root)) {
2632 // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
2633 $accessallowed = ($user->admin && basename($original_file) == $original_file && preg_match('/^dolibarr.*\.(log|json)$/', basename($original_file)));
2634 $original_file = $dolibarr_main_data_root.'/'.$original_file;
2635 } elseif ($modulepart == 'doctemplates' && !empty($dolibarr_main_data_root)) {
2636 // Wrapping for doctemplates
2637 $accessallowed = $user->admin;
2638 $original_file = $dolibarr_main_data_root.'/doctemplates/'.$original_file;
2639 } elseif ($modulepart == 'doctemplateswebsite' && !empty($dolibarr_main_data_root)) {
2640 // Wrapping for doctemplates of websites
2641 $accessallowed = ($fuser->rights->website->write && preg_match('/\.jpg$/i', basename($original_file)));
2642 $original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file;
2643 } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) {
2644 // Wrapping for *.zip package files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
2645 // Dir for custom dirs
2646 $tmp = explode(',', $dolibarr_main_document_root_alt);
2647 $dirins = $tmp[0];
2648
2649 $accessallowed = ($user->admin && preg_match('/^module_.*\.zip$/', basename($original_file)));
2650 $original_file = $dirins.'/'.$original_file;
2651 } elseif ($modulepart == 'mycompany' && !empty($conf->mycompany->dir_output)) {
2652 // Wrapping for some images
2653 $accessallowed = 1;
2654 $original_file = $conf->mycompany->dir_output.'/'.$original_file;
2655 } elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output)) {
2656 // Wrapping for users photos (user photos are allowed to any connected users)
2657 $accessallowed = 0;
2658 if (preg_match('/^\d+\/photos\//', $original_file)) {
2659 $accessallowed = 1;
2660 }
2661 $original_file = $conf->user->dir_output.'/'.$original_file;
2662 } elseif ($modulepart == 'userphotopublic' && !empty($conf->user->dir_output)) {
2663 // Wrapping for users photos that were set to public by their owner (public user photos can be read with the public link and securekey)
2664 $accessok = false;
2665 $reg = array();
2666 if (preg_match('/^(\d+)\/photos\//', $original_file, $reg)) {
2667 if ($reg[1]) {
2668 $tmpobject = new User($db);
2669 $tmpobject->fetch($reg[1], '', '', 1);
2670 if (getDolUserInt('USER_ENABLE_PUBLIC', 0, $tmpobject)) {
2671 $securekey = GETPOST('securekey', 'alpha', 1);
2672 // Security check
2673 global $dolibarr_main_cookie_cryptkey, $dolibarr_main_instance_unique_id;
2674 $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
2675 $encodedsecurekey = dol_hash($valuetouse.'uservirtualcard'.$tmpobject->id.'-'.$tmpobject->login, 'md5');
2676 if ($encodedsecurekey == $securekey) {
2677 $accessok = true;
2678 }
2679 }
2680 }
2681 }
2682 if ($accessok) {
2683 $accessallowed = 1;
2684 }
2685 $original_file = $conf->user->dir_output.'/'.$original_file;
2686 } elseif (($modulepart == 'companylogo') && !empty($conf->mycompany->dir_output)) {
2687 // Wrapping for company logos (company logos are allowed to anyboby, they are public)
2688 $accessallowed = 1;
2689 $original_file = $conf->mycompany->dir_output.'/logos/'.$original_file;
2690 } elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output)) {
2691 // Wrapping for members photos
2692 $accessallowed = 0;
2693 if (preg_match('/^\d+\/photos\//', $original_file)) {
2694 $accessallowed = 1;
2695 }
2696 $original_file = $conf->adherent->dir_output.'/'.$original_file;
2697 } elseif ($modulepart == 'apercufacture' && !empty($conf->facture->multidir_output[$entity])) {
2698 // Wrapping for invoices (user need permission to read invoices)
2699 if ($fuser->hasRight('facture', $lire)) {
2700 $accessallowed = 1;
2701 }
2702 $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2703 } elseif ($modulepart == 'apercupropal' && !empty($conf->propal->multidir_output[$entity])) {
2704 // Wrapping pour les apercu propal
2705 if ($fuser->hasRight('propal', $lire)) {
2706 $accessallowed = 1;
2707 }
2708 $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
2709 } elseif ($modulepart == 'apercucommande' && !empty($conf->commande->multidir_output[$entity])) {
2710 // Wrapping pour les apercu commande
2711 if ($fuser->hasRight('commande', $lire)) {
2712 $accessallowed = 1;
2713 }
2714 $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
2715 } elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output)) {
2716 // Wrapping pour les apercu intervention
2717 if ($fuser->hasRight('ficheinter', $lire)) {
2718 $accessallowed = 1;
2719 }
2720 $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2721 } elseif (($modulepart == 'apercucontract') && !empty($conf->contrat->multidir_output[$entity])) {
2722 // Wrapping pour les apercu contrat
2723 if ($fuser->hasRight('contrat', $lire)) {
2724 $accessallowed = 1;
2725 }
2726 $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
2727 } elseif (($modulepart == 'apercusupplier_proposal' || $modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output)) {
2728 // Wrapping pour les apercu supplier proposal
2729 if ($fuser->hasRight('supplier_proposal', $lire)) {
2730 $accessallowed = 1;
2731 }
2732 $original_file = $conf->supplier_proposal->dir_output.'/'.$original_file;
2733 } elseif (($modulepart == 'apercusupplier_order' || $modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output)) {
2734 // Wrapping pour les apercu supplier order
2735 if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2736 $accessallowed = 1;
2737 }
2738 $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
2739 } elseif (($modulepart == 'apercusupplier_invoice' || $modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output)) {
2740 // Wrapping pour les apercu supplier invoice
2741 if ($fuser->hasRight('fournisseur', $lire)) {
2742 $accessallowed = 1;
2743 }
2744 $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
2745 } elseif (($modulepart == 'holiday') && !empty($conf->holiday->dir_output)) {
2746 if ($fuser->hasRight('holiday', $read) || !empty($fuser->rights->holiday->readall) || preg_match('/^specimen/i', $original_file)) {
2747 $accessallowed = 1;
2748 // If we known $id of holiday, call checkUserAccessToObject to check permission on properties and hierarchy of leave request
2749 if ($refname && empty($fuser->rights->holiday->readall) && !preg_match('/^specimen/i', $original_file)) {
2750 include_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
2751 $tmpholiday = new Holiday($db);
2752 $tmpholiday->fetch('', $refname);
2753 $accessallowed = checkUserAccessToObject($user, array('holiday'), $tmpholiday, 'holiday', '', '', 'rowid', '');
2754 }
2755 }
2756 $original_file = $conf->holiday->dir_output.'/'.$original_file;
2757 } elseif (($modulepart == 'expensereport') && !empty($conf->expensereport->dir_output)) {
2758 if ($fuser->hasRight('expensereport', $lire) || !empty($fuser->rights->expensereport->readall) || preg_match('/^specimen/i', $original_file)) {
2759 $accessallowed = 1;
2760 // If we known $id of expensereport, call checkUserAccessToObject to check permission on properties and hierarchy of expense report
2761 if ($refname && empty($fuser->rights->expensereport->readall) && !preg_match('/^specimen/i', $original_file)) {
2762 include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
2763 $tmpexpensereport = new ExpenseReport($db);
2764 $tmpexpensereport->fetch('', $refname);
2765 $accessallowed = checkUserAccessToObject($user, array('expensereport'), $tmpexpensereport, 'expensereport', '', '', 'rowid', '');
2766 }
2767 }
2768 $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2769 } elseif (($modulepart == 'apercuexpensereport') && !empty($conf->expensereport->dir_output)) {
2770 // Wrapping pour les apercu expense report
2771 if ($fuser->hasRight('expensereport', $lire)) {
2772 $accessallowed = 1;
2773 }
2774 $original_file = $conf->expensereport->dir_output.'/'.$original_file;
2775 } elseif ($modulepart == 'propalstats' && !empty($conf->propal->multidir_temp[$entity])) {
2776 // Wrapping pour les images des stats propales
2777 if ($fuser->hasRight('propal', $lire)) {
2778 $accessallowed = 1;
2779 }
2780 $original_file = $conf->propal->multidir_temp[$entity].'/'.$original_file;
2781 } elseif ($modulepart == 'orderstats' && !empty($conf->commande->dir_temp)) {
2782 // Wrapping pour les images des stats commandes
2783 if ($fuser->hasRight('commande', $lire)) {
2784 $accessallowed = 1;
2785 }
2786 $original_file = $conf->commande->dir_temp.'/'.$original_file;
2787 } elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2788 if ($fuser->hasRight('fournisseur', 'commande', $lire)) {
2789 $accessallowed = 1;
2790 }
2791 $original_file = $conf->fournisseur->commande->dir_temp.'/'.$original_file;
2792 } elseif ($modulepart == 'billstats' && !empty($conf->facture->dir_temp)) {
2793 // Wrapping pour les images des stats factures
2794 if ($fuser->hasRight('facture', $lire)) {
2795 $accessallowed = 1;
2796 }
2797 $original_file = $conf->facture->dir_temp.'/'.$original_file;
2798 } elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output)) {
2799 if ($fuser->hasRight('fournisseur', 'facture', $lire)) {
2800 $accessallowed = 1;
2801 }
2802 $original_file = $conf->fournisseur->facture->dir_temp.'/'.$original_file;
2803 } elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp)) {
2804 // Wrapping pour les images des stats expeditions
2805 if ($fuser->hasRight('expedition', $lire)) {
2806 $accessallowed = 1;
2807 }
2808 $original_file = $conf->expedition->dir_temp.'/'.$original_file;
2809 } elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp)) {
2810 // Wrapping pour les images des stats expeditions
2811 if ($fuser->hasRight('deplacement', $lire)) {
2812 $accessallowed = 1;
2813 }
2814 $original_file = $conf->deplacement->dir_temp.'/'.$original_file;
2815 } elseif ($modulepart == 'memberstats' && !empty($conf->adherent->dir_temp)) {
2816 // Wrapping pour les images des stats expeditions
2817 if ($fuser->hasRight('adherent', $lire)) {
2818 $accessallowed = 1;
2819 }
2820 $original_file = $conf->adherent->dir_temp.'/'.$original_file;
2821 } elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) {
2822 // Wrapping pour les images des stats produits
2823 if ($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) {
2824 $accessallowed = 1;
2825 }
2826 $original_file = (!empty($conf->product->multidir_temp[$entity]) ? $conf->product->multidir_temp[$entity] : $conf->service->multidir_temp[$entity]).'/'.$original_file;
2827 } elseif (in_array($modulepart, array('tax', 'tax-vat', 'tva')) && !empty($conf->tax->dir_output)) {
2828 // Wrapping for taxes
2829 if ($fuser->hasRight('tax', 'charges', $lire)) {
2830 $accessallowed = 1;
2831 }
2832 $modulepartsuffix = str_replace('tax-', '', $modulepart);
2833 $original_file = $conf->tax->dir_output.'/'.($modulepartsuffix != 'tax' ? $modulepartsuffix.'/' : '').$original_file;
2834 } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
2835 // Wrapping for events
2836 if ($fuser->hasRight('agenda', 'myactions', $read)) {
2837 $accessallowed = 1;
2838 // If we known $id of project, call checkUserAccessToObject to check permission on the given agenda event on properties and assigned users
2839 if ($refname && !preg_match('/^specimen/i', $original_file)) {
2840 include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
2841 $tmpobject = new ActionComm($db);
2842 $tmpobject->fetch((int) $refname);
2843 $accessallowed = checkUserAccessToObject($user, array('agenda'), $tmpobject->id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id', '');
2844 if ($user->socid && $tmpobject->socid) {
2845 $accessallowed = checkUserAccessToObject($user, array('societe'), $tmpobject->socid);
2846 }
2847 }
2848 }
2849 $original_file = $conf->agenda->dir_output.'/'.$original_file;
2850 } elseif ($modulepart == 'category' && !empty($conf->categorie->multidir_output[$entity])) {
2851 // Wrapping for categories (categories are allowed if user has permission to read categories or to work on TakePos)
2852 if (empty($entity) || empty($conf->categorie->multidir_output[$entity])) {
2853 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2854 }
2855 if ($fuser->hasRight("categorie", $lire) || $fuser->hasRight("takepos", "run")) {
2856 $accessallowed = 1;
2857 }
2858 $original_file = $conf->categorie->multidir_output[$entity].'/'.$original_file;
2859 } elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) {
2860 // Wrapping pour les prelevements
2861 if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i', $original_file)) {
2862 $accessallowed = 1;
2863 }
2864 $original_file = $conf->prelevement->dir_output.'/'.$original_file;
2865 } elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp)) {
2866 // Wrapping pour les graph energie
2867 $accessallowed = 1;
2868 $original_file = $conf->stock->dir_temp.'/'.$original_file;
2869 } elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp)) {
2870 // Wrapping pour les graph fournisseurs
2871 $accessallowed = 1;
2872 $original_file = $conf->fournisseur->dir_temp.'/'.$original_file;
2873 } elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp)) {
2874 // Wrapping pour les graph des produits
2875 $accessallowed = 1;
2876 $original_file = $conf->product->multidir_temp[$entity].'/'.$original_file;
2877 } elseif ($modulepart == 'barcode') {
2878 // Wrapping pour les code barre
2879 $accessallowed = 1;
2880 // If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
2881 //$original_file=$conf->barcode->dir_temp.'/'.$original_file;
2882 $original_file = '';
2883 } elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp)) {
2884 // Wrapping pour les icones de background des mailings
2885 $accessallowed = 1;
2886 $original_file = $conf->mailing->dir_temp.'/'.$original_file;
2887 } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
2888 // Wrapping pour le scanner
2889 $accessallowed = 1;
2890 $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
2891 } elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output)) {
2892 // Wrapping pour les images fckeditor
2893 $accessallowed = 1;
2894 $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
2895 } elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) {
2896 // Wrapping for users
2897 $canreaduser = (!empty($fuser->admin) || $fuser->rights->user->user->{$lire});
2898 if ($fuser->id == (int) $refname) {
2899 $canreaduser = 1;
2900 } // A user can always read its own card
2901 if ($canreaduser || preg_match('/^specimen/i', $original_file)) {
2902 $accessallowed = 1;
2903 }
2904 $original_file = $conf->user->dir_output.'/'.$original_file;
2905 } elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->multidir_output[$entity])) {
2906 // Wrapping for third parties
2907 if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
2908 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2909 }
2910 if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i', $original_file)) {
2911 $accessallowed = 1;
2912 }
2913 $original_file = $conf->societe->multidir_output[$entity].'/'.$original_file;
2914 $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe').")";
2915 } elseif ($modulepart == 'contact' && !empty($conf->societe->multidir_output[$entity])) {
2916 // Wrapping for contact
2917 if (empty($entity) || empty($conf->societe->multidir_output[$entity])) {
2918 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
2919 }
2920 if ($fuser->hasRight('societe', $lire)) {
2921 $accessallowed = 1;
2922 }
2923 $original_file = $conf->societe->multidir_output[$entity].'/contact/'.$original_file;
2924 } elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->multidir_output[$entity])) {
2925 // Wrapping for invoices
2926 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2927 $accessallowed = 1;
2928 }
2929 $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file;
2930 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('invoice').")";
2931 } elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) {
2932 // Wrapping for mass actions
2933 if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
2934 $accessallowed = 1;
2935 }
2936 $original_file = $conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2937 } elseif ($modulepart == 'massfilesarea_orders') {
2938 if ($fuser->hasRight('commande', $lire) || preg_match('/^specimen/i', $original_file)) {
2939 $accessallowed = 1;
2940 }
2941 $original_file = $conf->commande->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2942 } elseif ($modulepart == 'massfilesarea_sendings') {
2943 if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
2944 $accessallowed = 1;
2945 }
2946 $original_file = $conf->expedition->dir_output.'/sending/temp/massgeneration/'.$user->id.'/'.$original_file;
2947 } elseif ($modulepart == 'massfilesarea_invoices') {
2948 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2949 $accessallowed = 1;
2950 }
2951 $original_file = $conf->facture->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file;
2952 } elseif ($modulepart == 'massfilesarea_expensereport') {
2953 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2954 $accessallowed = 1;
2955 }
2956 $original_file = $conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2957 } elseif ($modulepart == 'massfilesarea_interventions') {
2958 if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
2959 $accessallowed = 1;
2960 }
2961 $original_file = $conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2962 } elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) {
2963 if ($fuser->hasRight('supplier_proposal', $lire) || preg_match('/^specimen/i', $original_file)) {
2964 $accessallowed = 1;
2965 }
2966 $original_file = $conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2967 } elseif ($modulepart == 'massfilesarea_supplier_order') {
2968 if ($fuser->hasRight('fournisseur', 'commande', $lire) || preg_match('/^specimen/i', $original_file)) {
2969 $accessallowed = 1;
2970 }
2971 $original_file = $conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2972 } elseif ($modulepart == 'massfilesarea_supplier_invoice') {
2973 if ($fuser->hasRight('fournisseur', 'facture', $lire) || preg_match('/^specimen/i', $original_file)) {
2974 $accessallowed = 1;
2975 }
2976 $original_file = $conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2977 } elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) {
2978 if ($fuser->hasRight('contrat', $lire) || preg_match('/^specimen/i', $original_file)) {
2979 $accessallowed = 1;
2980 }
2981 $original_file = $conf->contrat->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
2982 } elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) {
2983 // Wrapping for interventions
2984 if ($fuser->hasRight('ficheinter', $lire) || preg_match('/^specimen/i', $original_file)) {
2985 $accessallowed = 1;
2986 }
2987 $original_file = $conf->ficheinter->dir_output.'/'.$original_file;
2988 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2989 } elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) {
2990 // Wrapping pour les deplacements et notes de frais
2991 if ($fuser->hasRight('deplacement', $lire) || preg_match('/^specimen/i', $original_file)) {
2992 $accessallowed = 1;
2993 }
2994 $original_file = $conf->deplacement->dir_output.'/'.$original_file;
2995 //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2996 } elseif (($modulepart == 'propal' || $modulepart == 'propale') && isset($conf->propal->multidir_output[$entity])) {
2997 // Wrapping pour les propales
2998 if ($fuser->hasRight('propal', $lire) || preg_match('/^specimen/i', $original_file)) {
2999 $accessallowed = 1;
3000 }
3001 $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file;
3002 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('propal').")";
3003 } elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->multidir_output[$entity])) {
3004 // Wrapping pour les commandes
3005 if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) {
3006 $accessallowed = 1;
3007 }
3008 $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file;
3009 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")";
3010 } elseif ($modulepart == 'project' && !empty($conf->project->multidir_output[$entity])) {
3011 // Wrapping pour les projets
3012 if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3013 $accessallowed = 1;
3014 // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3015 if ($refname && !preg_match('/^specimen/i', $original_file)) {
3016 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
3017 $tmpproject = new Project($db);
3018 $tmpproject->fetch('', $refname);
3019 $accessallowed = checkUserAccessToObject($user, array('projet'), $tmpproject->id, 'projet&project', '', '', 'rowid', '');
3020 }
3021 }
3022 $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3023 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3024 } elseif ($modulepart == 'project_task' && !empty($conf->project->multidir_output[$entity])) {
3025 if ($fuser->hasRight('projet', $lire) || preg_match('/^specimen/i', $original_file)) {
3026 $accessallowed = 1;
3027 // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project
3028 if ($refname && !preg_match('/^specimen/i', $original_file)) {
3029 include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
3030 $tmptask = new Task($db);
3031 $tmptask->fetch('', $refname);
3032 $accessallowed = checkUserAccessToObject($user, array('projet_task'), $tmptask->id, 'projet_task&project', '', '', 'rowid', '');
3033 }
3034 }
3035 $original_file = $conf->project->multidir_output[$entity].'/'.$original_file;
3036 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")";
3037 } elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) {
3038 // Wrapping pour les commandes fournisseurs
3039 if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) {
3040 $accessallowed = 1;
3041 }
3042 $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file;
3043 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3044 } elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) {
3045 // Wrapping pour les factures fournisseurs
3046 if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) {
3047 $accessallowed = 1;
3048 }
3049 $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file;
3050 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3051 } elseif ($modulepart == 'supplier_payment') {
3052 // Wrapping pour les rapport de paiements
3053 if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) {
3054 $accessallowed = 1;
3055 }
3056 $original_file = $conf->fournisseur->payment->dir_output.'/'.$original_file;
3057 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
3058 } elseif ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) {
3059 // Wrapping pour les rapport de paiements
3060 if ($fuser->hasRight('facture', $lire) || preg_match('/^specimen/i', $original_file)) {
3061 $accessallowed = 1;
3062 }
3063 if ($fuser->socid > 0) {
3064 $original_file = $conf->facture->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file;
3065 } else {
3066 $original_file = $conf->facture->dir_output.'/payments/'.$original_file;
3067 }
3068 } elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) {
3069 // Wrapping for accounting exports
3070 if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i', $original_file)) {
3071 $accessallowed = 1;
3072 }
3073 $original_file = $conf->accounting->dir_output.'/'.$original_file;
3074 } elseif (($modulepart == 'expedition' || $modulepart == 'shipment') && !empty($conf->expedition->dir_output)) {
3075 // Wrapping pour les expedition
3076 if ($fuser->hasRight('expedition', $lire) || preg_match('/^specimen/i', $original_file)) {
3077 $accessallowed = 1;
3078 }
3079 $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'sending/') === 0 ? '' : 'sending/').$original_file;
3080 //$original_file = $conf->expedition->dir_output."/".$original_file;
3081 } elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output)) {
3082 // Delivery Note Wrapping
3083 if ($fuser->hasRight('expedition', 'delivery', $lire) || preg_match('/^specimen/i', $original_file)) {
3084 $accessallowed = 1;
3085 }
3086 $original_file = $conf->expedition->dir_output."/".(strpos($original_file, 'receipt/') === 0 ? '' : 'receipt/').$original_file;
3087 } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) {
3088 // Wrapping pour les actions
3089 if ($fuser->hasRight('agenda', 'myactions', $read) || preg_match('/^specimen/i', $original_file)) {
3090 $accessallowed = 1;
3091 }
3092 $original_file = $conf->agenda->dir_output.'/'.$original_file;
3093 } elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) {
3094 // Wrapping pour les actions
3095 if ($fuser->hasRight('agenda', 'allactions', $read) || preg_match('/^specimen/i', $original_file)) {
3096 $accessallowed = 1;
3097 }
3098 $original_file = $conf->agenda->dir_temp."/".$original_file;
3099 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
3100 // Wrapping pour les produits et services
3101 if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) {
3102 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3103 }
3104 if (($fuser->hasRight('produit', $lire) || $fuser->hasRight('service', $lire)) || preg_match('/^specimen/i', $original_file)) {
3105 $accessallowed = 1;
3106 }
3107 if (isModEnabled("product")) {
3108 $original_file = $conf->product->multidir_output[$entity].'/'.$original_file;
3109 } elseif (isModEnabled("service")) {
3110 $original_file = $conf->service->multidir_output[$entity].'/'.$original_file;
3111 }
3112 } elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') {
3113 // Wrapping pour les lots produits
3114 if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) {
3115 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3116 }
3117 if (($fuser->hasRight('produit', $lire)) || preg_match('/^specimen/i', $original_file)) {
3118 $accessallowed = 1;
3119 }
3120 if (isModEnabled('productbatch')) {
3121 $original_file = $conf->productbatch->multidir_output[$entity].'/'.$original_file;
3122 }
3123 } elseif ($modulepart == 'movement' || $modulepart == 'mouvement') {
3124 // Wrapping for stock movements
3125 if (empty($entity) || empty($conf->stock->multidir_output[$entity])) {
3126 return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
3127 }
3128 if (($fuser->hasRight('stock', $lire) || $fuser->hasRight('stock', 'movement', $lire) || $fuser->hasRight('stock', 'mouvement', $lire)) || preg_match('/^specimen/i', $original_file)) {
3129 $accessallowed = 1;
3130 }
3131 if (isModEnabled('stock')) {
3132 $original_file = $conf->stock->multidir_output[$entity].'/movement/'.$original_file;
3133 }
3134 } elseif ($modulepart == 'contract' && !empty($conf->contrat->multidir_output[$entity])) {
3135 // Wrapping pour les contrats
3136 if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) {
3137 $accessallowed = 1;
3138 }
3139 $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file;
3140 $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract').")";
3141 } elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) {
3142 // Wrapping pour les dons
3143 if ($fuser->hasRight('don', $lire) || preg_match('/^specimen/i', $original_file)) {
3144 $accessallowed = 1;
3145 }
3146 $original_file = $conf->don->dir_output.'/'.$original_file;
3147 } elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) {
3148 // Wrapping pour les dons
3149 if ($fuser->hasRight('resource', $read) || preg_match('/^specimen/i', $original_file)) {
3150 $accessallowed = 1;
3151 }
3152 $original_file = $conf->resource->dir_output.'/'.$original_file;
3153 } elseif (($modulepart == 'remisecheque' || $modulepart == 'chequereceipt') && !empty($conf->bank->dir_output)) {
3154 // Wrapping pour les remises de cheques
3155 if ($fuser->hasRight('banque', $lire) || preg_match('/^specimen/i', $original_file)) {
3156 $accessallowed = 1;
3157 }
3158
3159 $original_file = $conf->bank->dir_output.'/checkdeposits/'.$original_file; // original_file should contains relative path so include the get_exdir result
3160 } elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) {
3161 // Wrapping for bank
3162 if ($fuser->hasRight('banque', $lire)) {
3163 $accessallowed = 1;
3164 }
3165 $original_file = $conf->bank->dir_output.'/'.$original_file;
3166 } elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) {
3167 // Wrapping for export module
3168 // Note that a test may not be required because we force the dir of download on the directory of the user that export
3169 $accessallowed = $user->rights->export->lire;
3170 $original_file = $conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file;
3171 } elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) {
3172 // Wrapping for import module
3173 $accessallowed = $user->rights->import->run;
3174 $original_file = $conf->import->dir_temp.'/'.$original_file;
3175 } elseif ($modulepart == 'recruitment' && !empty($conf->recruitment->dir_output)) {
3176 // Wrapping for recruitment module
3177 $accessallowed = $user->hasRight('recruitment', 'recruitmentjobposition', 'read');
3178 $original_file = $conf->recruitment->dir_output.'/'.$original_file;
3179 } elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) {
3180 // Wrapping for wysiwyg editor
3181 $accessallowed = 1;
3182 $original_file = $conf->fckeditor->dir_output.'/'.$original_file;
3183 } elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) {
3184 // Wrapping for backups
3185 if ($fuser->admin) {
3186 $accessallowed = 1;
3187 }
3188 $original_file = $conf->admin->dir_output.'/'.$original_file;
3189 } elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) {
3190 // Wrapping for upload file test
3191 if ($fuser->admin) {
3192 $accessallowed = 1;
3193 }
3194 $original_file = $conf->admin->dir_temp.'/'.$original_file;
3195 } elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) {
3196 // Wrapping pour BitTorrent
3197 $accessallowed = 1;
3198 $dir = 'files';
3199 if (dol_mimetype($original_file) == 'application/x-bittorrent') {
3200 $dir = 'torrents';
3201 }
3202 $original_file = $conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
3203 } elseif ($modulepart == 'member' && !empty($conf->adherent->dir_output)) {
3204 // Wrapping pour Foundation module
3205 if ($fuser->hasRight('adherent', $lire) || preg_match('/^specimen/i', $original_file)) {
3206 $accessallowed = 1;
3207 }
3208 $original_file = $conf->adherent->dir_output.'/'.$original_file;
3209 } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) {
3210 // Wrapping for Scanner
3211 $accessallowed = 1;
3212 $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
3213 // If modulepart=module_user_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser
3214 // If modulepart=module_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp
3215 // If modulepart=module_user Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser
3216 // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3217 // If modulepart=module-abc Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
3218 } else {
3219 // GENERIC Wrapping
3220 //var_dump($modulepart);
3221 //var_dump($original_file);
3222 if (preg_match('/^specimen/i', $original_file)) {
3223 $accessallowed = 1; // If link to a file called specimen. Test must be done before changing $original_file int full path.
3224 }
3225 if ($fuser->admin) {
3226 $accessallowed = 1; // If user is admin
3227 }
3228
3229 $tmpmodulepart = explode('-', $modulepart);
3230 if (!empty($tmpmodulepart[1])) {
3231 $modulepart = $tmpmodulepart[0];
3232 $original_file = $tmpmodulepart[1].'/'.$original_file;
3233 }
3234
3235 // Define $accessallowed
3236 $reg = array();
3237 if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) {
3238 $tmpmodule = $reg[1];
3239 if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3240 dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3241 exit;
3242 }
3243 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3244 $accessallowed = 1;
3245 }
3246 $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
3247 } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) {
3248 $tmpmodule = $reg[1];
3249 if (empty($conf->$tmpmodule->dir_temp)) { // modulepart not supported
3250 dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3251 exit;
3252 }
3253 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3254 $accessallowed = 1;
3255 }
3256 $original_file = $conf->$tmpmodule->dir_temp.'/'.$original_file;
3257 } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) {
3258 $tmpmodule = $reg[1];
3259 if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3260 dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3261 exit;
3262 }
3263 if ($fuser->hasRight($tmpmodule, $lire) || $fuser->hasRight($tmpmodule, $read) || $fuser->hasRight($tmpmodule, $download)) {
3264 $accessallowed = 1;
3265 }
3266 $original_file = $conf->$tmpmodule->dir_output.'/'.$fuser->id.'/'.$original_file;
3267 } elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) {
3268 $tmpmodule = $reg[1];
3269 if (empty($conf->$tmpmodule->dir_output)) { // modulepart not supported
3270 dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
3271 exit;
3272 }
3273 if ($fuser->hasRight($tmpmodule, $lire) || preg_match('/^specimen/i', $original_file)) {
3274 $accessallowed = 1;
3275 }
3276 $original_file = $conf->$tmpmodule->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
3277 } else {
3278 if (empty($conf->$modulepart->dir_output)) { // modulepart not supported
3279 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.');
3280 exit;
3281 }
3282
3283 // Check fuser->rights->modulepart->myobject->read and fuser->rights->modulepart->read
3284 $partsofdirinoriginalfile = explode('/', $original_file);
3285 if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use)
3286 $partofdirinoriginalfile = $partsofdirinoriginalfile[0];
3287 if ($partofdirinoriginalfile && ($fuser->hasRight($modulepart, $partofdirinoriginalfile, 'lire') || $fuser->hasRight($modulepart, $partofdirinoriginalfile, 'read'))) {
3288 $accessallowed = 1;
3289 }
3290 }
3291 if ($fuser->hasRight($modulepart, $lire) || $fuser->hasRight($modulepart, $read)) {
3292 $accessallowed = 1;
3293 }
3294
3295 if (is_array($conf->$modulepart->multidir_output) && !empty($conf->$modulepart->multidir_output[$entity])) {
3296 $original_file = $conf->$modulepart->multidir_output[$entity].'/'.$original_file;
3297 } else {
3298 $original_file = $conf->$modulepart->dir_output.'/'.$original_file;
3299 }
3300 }
3301
3302 $parameters = array(
3303 'modulepart' => $modulepart,
3304 'original_file' => $original_file,
3305 'entity' => $entity,
3306 'fuser' => $fuser,
3307 'refname' => '',
3308 'mode' => $mode
3309 );
3310 $reshook = $hookmanager->executeHooks('checkSecureAccess', $parameters, $object);
3311 if ($reshook > 0) {
3312 if (!empty($hookmanager->resArray['original_file'])) {
3313 $original_file = $hookmanager->resArray['original_file'];
3314 }
3315 if (!empty($hookmanager->resArray['accessallowed'])) {
3316 $accessallowed = $hookmanager->resArray['accessallowed'];
3317 }
3318 if (!empty($hookmanager->resArray['sqlprotectagainstexternals'])) {
3319 $sqlprotectagainstexternals = $hookmanager->resArray['sqlprotectagainstexternals'];
3320 }
3321 }
3322 }
3323
3324 $ret = array(
3325 'accessallowed' => ($accessallowed ? 1 : 0),
3326 'sqlprotectagainstexternals' => $sqlprotectagainstexternals,
3327 'original_file' => $original_file
3328 );
3329
3330 return $ret;
3331}
3332
3341function dol_filecache($directory, $filename, $object)
3342{
3343 if (!dol_is_dir($directory)) {
3344 dol_mkdir($directory);
3345 }
3346 $cachefile = $directory.$filename;
3347 file_put_contents($cachefile, serialize($object), LOCK_EX);
3348 dolChmod($cachefile, '0644');
3349}
3350
3359function dol_cache_refresh($directory, $filename, $cachetime)
3360{
3361 $now = dol_now();
3362 $cachefile = $directory.$filename;
3363 $refresh = !file_exists($cachefile) || ($now - $cachetime) > dol_filemtime($cachefile);
3364 return $refresh;
3365}
3366
3374function dol_readcachefile($directory, $filename)
3375{
3376 $cachefile = $directory.$filename;
3377 $object = unserialize(file_get_contents($cachefile));
3378 return $object;
3379}
3380
3387function dirbasename($pathfile)
3388{
3389 return preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'\//', '', $pathfile);
3390}
3391
3392
3404function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
3405{
3406 global $conffile;
3407
3408 $exclude = 'install';
3409
3410 foreach ($dir->md5file as $file) { // $file is a simpleXMLElement
3411 $filename = $path.$file['name'];
3412 $file_list['insignature'][] = $filename;
3413 $expectedsize = (empty($file['size']) ? '' : $file['size']);
3414 $expectedmd5 = (string) $file;
3415
3416 //if (preg_match('#'.$exclude.'#', $filename)) continue;
3417
3418 if (!file_exists($pathref.'/'.$filename)) {
3419 $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize);
3420 } else {
3421 $md5_local = md5_file($pathref.'/'.$filename);
3422
3423 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
3424 $checksumconcat[] = $expectedmd5;
3425 } else {
3426 if ($md5_local != $expectedmd5) {
3427 $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize, 'md5'=>(string) $md5_local);
3428 }
3429 $checksumconcat[] = $md5_local;
3430 }
3431 }
3432 }
3433
3434 foreach ($dir->dir as $subdir) { // $subdir['name'] is '' or '/accountancy/admin' for example
3435 getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat);
3436 }
3437
3438 return $file_list;
3439}
3440
3448function dragAndDropFileUpload($htmlname)
3449{
3450 global $object, $langs;
3451
3452 $out = "";
3453 $out .= '<div id="'.$htmlname.'Message" class="dragDropAreaMessage hidden"><span>'.img_picto("", 'download').'<br>'.$langs->trans("DropFileToAddItToObject").'</span></div>';
3454 $out .= "\n<!-- JS CODE TO ENABLE DRAG AND DROP OF FILE -->\n";
3455 $out .= "<script>";
3456 $out .= '
3457 jQuery(document).ready(function() {
3458 var enterTargetDragDrop = null;
3459
3460 $("#'.$htmlname.'").addClass("cssDragDropArea");
3461
3462 $(".cssDragDropArea").on("dragenter", function(ev, ui) {
3463 var dataTransfer = ev.originalEvent.dataTransfer;
3464 var dataTypes = dataTransfer.types;
3465 //console.log(dataTransfer);
3466 //console.log(dataTypes);
3467
3468 if (!dataTypes || ($.inArray(\'Files\', dataTypes) === -1)) {
3469 // The element dragged is not a file, so we avoid the "dragenter"
3470 ev.preventDefault();
3471 return false;
3472 }
3473
3474 // Entering drop area. Highlight area
3475 console.log("dragAndDropFileUpload: We add class highlightDragDropArea")
3476 enterTargetDragDrop = ev.target;
3477 $(this).addClass("highlightDragDropArea");
3478 $("#'.$htmlname.'Message").removeClass("hidden");
3479 ev.preventDefault();
3480 });
3481
3482 $(".cssDragDropArea").on("dragleave", function(ev) {
3483 // Going out of drop area. Remove Highlight
3484 if (enterTargetDragDrop == ev.target){
3485 console.log("dragAndDropFileUpload: We remove class highlightDragDropArea")
3486 $("#'.$htmlname.'Message").addClass("hidden");
3487 $(this).removeClass("highlightDragDropArea");
3488 }
3489 });
3490
3491 $(".cssDragDropArea").on("dragover", function(ev) {
3492 ev.preventDefault();
3493 return false;
3494 });
3495
3496 $(".cssDragDropArea").on("drop", function(e) {
3497 console.log("Trigger event file dropped. fk_element='.dol_escape_js($object->id).' element='.dol_escape_js($object->element).'");
3498 e.preventDefault();
3499 fd = new FormData();
3500 fd.append("fk_element", "'.dol_escape_js($object->id).'");
3501 fd.append("element", "'.dol_escape_js($object->element).'");
3502 fd.append("token", "'.currentToken().'");
3503 fd.append("action", "linkit");
3504
3505 var dataTransfer = e.originalEvent.dataTransfer;
3506
3507 if (dataTransfer.files && dataTransfer.files.length){
3508 var droppedFiles = e.originalEvent.dataTransfer.files;
3509 $.each(droppedFiles, function(index,file){
3510 fd.append("files[]", file,file.name)
3511 });
3512 }
3513 $(".cssDragDropArea").removeClass("highlightDragDropArea");
3514 counterdragdrop = 0;
3515 $.ajax({
3516 url: "'.DOL_URL_ROOT.'/core/ajax/fileupload.php",
3517 type: "POST",
3518 processData: false,
3519 contentType: false,
3520 data: fd,
3521 success:function() {
3522 console.log("Uploaded.", arguments);
3523 /* arguments[0] is the json string of files */
3524 /* arguments[1] is the value for variable "success", can be 0 or 1 */
3525 let listoffiles = JSON.parse(arguments[0]);
3526 console.log(listoffiles);
3527 let nboferror = 0;
3528 for (let i = 0; i < listoffiles.length; i++) {
3529 console.log(listoffiles[i].error);
3530 if (listoffiles[i].error) {
3531 nboferror++;
3532 }
3533 }
3534 console.log(nboferror);
3535 if (nboferror > 0) {
3536 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorOnAtLeastOneFileUpload:warnings";
3537 } else {
3538 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=UploadFileDragDropSuccess:mesgs";
3539 }
3540 },
3541 error:function() {
3542 console.log("Error Uploading.", arguments)
3543 if (arguments[0].status == 403) {
3544 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadPermissionDenied:errors";
3545 }
3546 window.location.href = "'.$_SERVER["PHP_SELF"].'?id='.dol_escape_js($object->id).'&seteventmessages=ErrorUploadFileDragDropPermissionDenied:errors";
3547 },
3548 })
3549 });
3550 });
3551 ';
3552 $out .= "</script>\n";
3553 return $out;
3554}
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.