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