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