golden hour
/home/phakp/public_html/erp/core/lib
⬆️ Go Up
Upload
File/Folder
Size
Actions
accounting.lib.php
9.12 KB
Del
OK
admin.lib.php
66.42 KB
Del
OK
agenda.lib.php
18.22 KB
Del
OK
ajax.lib.php
31.31 KB
Del
OK
asset.lib.php
4.8 KB
Del
OK
bank.lib.php
12.94 KB
Del
OK
barcode.lib.php
15.26 KB
Del
OK
categories.lib.php
3.43 KB
Del
OK
company.lib.php
79.8 KB
Del
OK
contact.lib.php
4.51 KB
Del
OK
contract.lib.php
4.77 KB
Del
OK
cron.lib.php
4.69 KB
Del
OK
date.lib.php
37.78 KB
Del
OK
doc.lib.php
6.73 KB
Del
OK
doleditor.lib.php
3.93 KB
Del
OK
donation.lib.php
3.61 KB
Del
OK
ecm.lib.php
5.12 KB
Del
OK
emailing.lib.php
2.25 KB
Del
OK
eventorganization.lib.php
2.21 KB
Del
OK
expedition.lib.php
3.9 KB
Del
OK
expensereport.lib.php
5.6 KB
Del
OK
fichinter.lib.php
6.45 KB
Del
OK
files.lib.php
122.46 KB
Del
OK
fiscalyear.lib.php
1.86 KB
Del
OK
format_cards.lib.php
2.8 KB
Del
OK
fourn.lib.php
10.09 KB
Del
OK
functions.lib.php
429.39 KB
Del
OK
functions2.lib.php
91.31 KB
Del
OK
functions_ch.lib.php
3.66 KB
Del
OK
functionsnumtoword.lib.php
9.96 KB
Del
OK
geturl.lib.php
14.68 KB
Del
OK
holiday.lib.php
3.43 KB
Del
OK
hrm.lib.php
3.21 KB
Del
OK
images.lib.php
24.95 KB
Del
OK
import.lib.php
1.89 KB
Del
OK
intracommreport.lib.php
2.59 KB
Del
OK
invoice.lib.php
50.52 KB
Del
OK
invoice2.lib.php
9.16 KB
Del
OK
json.lib.php
10.92 KB
Del
OK
ldap.lib.php
5.37 KB
Del
OK
loan.lib.php
5.24 KB
Del
OK
mailmanspip.lib.php
1.24 KB
Del
OK
member.lib.php
10.23 KB
Del
OK
memory.lib.php
9.5 KB
Del
OK
modulebuilder.lib.php
13.56 KB
Del
OK
multicurrency.lib.php
2.07 KB
Del
OK
oauth.lib.php
5.73 KB
Del
OK
order.lib.php
9.82 KB
Del
OK
parsemd.lib.php
2.54 KB
Del
OK
payments.lib.php
17.44 KB
Del
OK
pdf.lib.php
104 KB
Del
OK
phpsessionindb.lib.php
8.28 KB
Del
OK
prelevement.lib.php
3.23 KB
Del
OK
price.lib.php
21.38 KB
Del
OK
product.lib.php
24.78 KB
Del
OK
project.lib.php
111.69 KB
Del
OK
propal.lib.php
9.38 KB
Del
OK
receiptprinter.lib.php
2.19 KB
Del
OK
reception.lib.php
4.69 KB
Del
OK
report.lib.php
3.84 KB
Del
OK
resource.lib.php
4.7 KB
Del
OK
salaries.lib.php
3.54 KB
Del
OK
security.lib.php
38.24 KB
Del
OK
security2.lib.php
18.07 KB
Del
OK
sendings.lib.php
16.55 KB
Del
OK
signature.lib.php
4.08 KB
Del
OK
stock.lib.php
3.6 KB
Del
OK
supplier_proposal.lib.php
4.82 KB
Del
OK
takepos.lib.php
2.18 KB
Del
OK
tax.lib.php
56.03 KB
Del
OK
ticket.lib.php
36.72 KB
Del
OK
treeview.lib.php
9.23 KB
Del
OK
trip.lib.php
1.98 KB
Del
OK
usergroups.lib.php
42.7 KB
Del
OK
vat.lib.php
2.6 KB
Del
OK
website.lib.php
53.39 KB
Del
OK
website2.lib.php
24.95 KB
Del
OK
ws.lib.php
3.34 KB
Del
OK
xcal.lib.php
16.9 KB
Del
OK
Edit: files.lib.php
<?php /* Copyright (C) 2008-2012 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2012-2021 Regis Houssin <regis.houssin@inodbox.com> * Copyright (C) 2012-2016 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com> * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * or see https://www.gnu.org/ */ /** * \file htdocs/core/lib/files.lib.php * \brief Library for file managing functions */ /** * Make a basename working with all page code (default PHP basenamed fails with cyrillic). * We supose dir separator for input is '/'. * * @param string $pathfile String to find basename. * @return string Basename of input */ function dol_basename($pathfile) { return preg_replace('/^.*\/([^\/]+)$/', '$1', rtrim($pathfile, '/')); } /** * Scan a directory and return a list of files/directories. * Content for string is UTF8 and dir separator is "/". * * @param string $path Starting path from which to search. This is a full path. * @param string $types Can be "directories", "files", or "all" * @param int $recursive Determines whether subdirectories are searched * @param string $filter Regex filter to restrict list. This regex value must be escaped for '/' by doing preg_quote($var,'/'), since this char is used for preg_match function, * but must not contains the start and end '/'. Filter is checked into basename only. * @param array $excludefilter Array of Regex for exclude filter (example: array('(\.meta|_preview.*\.png)$','^\.')). Exclude is checked both into fullpath and into basename (So '^xxx' may exclude 'xxx/dirscanned/...' and dirscanned/xxx'). * @param string $sortcriteria Sort criteria ('','fullname','relativename','name','date','size') * @param string $sortorder Sort order (SORT_ASC, SORT_DESC) * @param int $mode 0=Return array minimum keys loaded (faster), 1=Force all keys like date and size to be loaded (slower), 2=Force load of date only, 3=Force load of size only, 4=Force load of perm * @param int $nohook Disable all hooks * @param string $relativename For recursive purpose only. Must be "" at first call. * @param string $donotfollowsymlinks Do not follow symbolic links * @return array Array of array('name'=>'xxx','fullname'=>'/abc/xxx','date'=>'yyy','size'=>99,'type'=>'dir|file',...) * @see dol_dir_list_in_database() */ function dol_dir_list($path, $types = "all", $recursive = 0, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0, $nohook = 0, $relativename = "", $donotfollowsymlinks = 0) { global $db, $hookmanager; global $object; if ($recursive <= 1) { // Avoid too verbose log dol_syslog("files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter)); //print 'xxx'."files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter); } $loaddate = ($mode == 1 || $mode == 2) ?true:false; $loadsize = ($mode == 1 || $mode == 3) ?true:false; $loadperm = ($mode == 1 || $mode == 4) ?true:false; // Clean parameters $path = preg_replace('/([\\/]+)$/i', '', $path); $newpath = dol_osencode($path); $reshook = 0; $file_list = array(); if (is_object($hookmanager) && !$nohook) { $hookmanager->resArray = array(); $hookmanager->initHooks(array('fileslib')); $parameters = array( 'path' => $newpath, 'types'=> $types, 'recursive' => $recursive, 'filter' => $filter, 'excludefilter' => $excludefilter, 'sortcriteria' => $sortcriteria, 'sortorder' => $sortorder, 'loaddate' => $loaddate, 'loadsize' => $loadsize, 'mode' => $mode ); $reshook = $hookmanager->executeHooks('getDirList', $parameters, $object); } // $hookmanager->resArray may contain array stacked by other modules if (empty($reshook)) { if (!is_dir($newpath)) { return array(); } if ($dir = opendir($newpath)) { $filedate = ''; $filesize = ''; $fileperm = ''; while (false !== ($file = readdir($dir))) { // $file is always a basename (into directory $newpath) if (!utf8_check($file)) { $file = utf8_encode($file); // To be sure data is stored in utf8 in memory } $fullpathfile = ($newpath ? $newpath.'/' : '').$file; $qualified = 1; // Define excludefilterarray $excludefilterarray = array('^\.'); if (is_array($excludefilter)) { $excludefilterarray = array_merge($excludefilterarray, $excludefilter); } elseif ($excludefilter) { $excludefilterarray[] = $excludefilter; } // Check if file is qualified foreach ($excludefilterarray as $filt) { if (preg_match('/'.$filt.'/i', $file) || preg_match('/'.$filt.'/i', $fullpathfile)) { $qualified = 0; break; } } //print $fullpathfile.' '.$file.' '.$qualified.'<br>'; if ($qualified) { $isdir = is_dir(dol_osencode($path."/".$file)); // Check whether this is a file or directory and whether we're interested in that type if ($isdir && (($types == "directories") || ($types == "all") || $recursive > 0)) { // Add entry into file_list array if (($types == "directories") || ($types == "all")) { if ($loaddate || $sortcriteria == 'date') { $filedate = dol_filemtime($path."/".$file); } if ($loadsize || $sortcriteria == 'size') { $filesize = dol_filesize($path."/".$file); } if ($loadperm || $sortcriteria == 'perm') { $fileperm = dol_fileperm($path."/".$file); } if (!$filter || preg_match('/'.$filter.'/i', $file)) { // We do not search key $filter into all $path, only into $file part $reg = array(); preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg); $level1name = (isset($reg[1]) ? $reg[1] : ''); $file_list[] = array( "name" => $file, "path" => $path, "level1name" => $level1name, "relativename" => ($relativename ? $relativename.'/' : '').$file, "fullname" => $path.'/'.$file, "date" => $filedate, "size" => $filesize, "perm" => $fileperm, "type" => 'dir' ); } } // if we're in a directory and we want recursive behavior, call this function again if ($recursive > 0) { if (empty($donotfollowsymlinks) || !is_link($path."/".$file)) { //var_dump('eee '. $path."/".$file. ' '.is_dir($path."/".$file).' '.is_link($path."/".$file)); $file_list = array_merge($file_list, dol_dir_list($path."/".$file, $types, $recursive + 1, $filter, $excludefilter, $sortcriteria, $sortorder, $mode, $nohook, ($relativename != '' ? $relativename.'/' : '').$file, $donotfollowsymlinks)); } } } elseif (!$isdir && (($types == "files") || ($types == "all"))) { // Add file into file_list array if ($loaddate || $sortcriteria == 'date') { $filedate = dol_filemtime($path."/".$file); } if ($loadsize || $sortcriteria == 'size') { $filesize = dol_filesize($path."/".$file); } if (!$filter || preg_match('/'.$filter.'/i', $file)) { // We do not search key $filter into $path, only into $file preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg); $level1name = (isset($reg[1]) ? $reg[1] : ''); $file_list[] = array( "name" => $file, "path" => $path, "level1name" => $level1name, "relativename" => ($relativename ? $relativename.'/' : '').$file, "fullname" => $path.'/'.$file, "date" => $filedate, "size" => $filesize, "type" => 'file' ); } } } } closedir($dir); // Obtain a list of columns if (!empty($sortcriteria) && $sortorder) { $file_list = dol_sort_array($file_list, $sortcriteria, ($sortorder == SORT_ASC ? 'asc' : 'desc')); } } } if (is_object($hookmanager) && is_array($hookmanager->resArray)) { $file_list = array_merge($file_list, $hookmanager->resArray); } return $file_list; } /** * Scan a directory and return a list of files/directories. * Content for string is UTF8 and dir separator is "/". * * @param string $path Starting path from which to search. Example: 'produit/MYPROD' * @param string $filter Regex filter to restrict list. This regex value must be escaped for '/', since this char is used for preg_match function * @param array|null $excludefilter Array of Regex for exclude filter (example: array('(\.meta|_preview.*\.png)$','^\.')) * @param string $sortcriteria Sort criteria ("","fullname","name","date","size") * @param string $sortorder Sort order (SORT_ASC, SORT_DESC) * @param int $mode 0=Return array minimum keys loaded (faster), 1=Force all keys like description * @return array Array of array('name'=>'xxx','fullname'=>'/abc/xxx','type'=>'dir|file',...) * @see dol_dir_list() */ function dol_dir_list_in_database($path, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0) { global $conf, $db; $sql = " SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams,"; $sql .= " date_c, tms as date_m, fk_user_c, fk_user_m, acl, position, share"; if ($mode) { $sql .= ", description"; } $sql .= " FROM ".MAIN_DB_PREFIX."ecm_files"; $sql .= " WHERE entity = ".$conf->entity; if (preg_match('/%$/', $path)) { $sql .= " AND filepath LIKE '".$db->escape($path)."'"; } else { $sql .= " AND filepath = '".$db->escape($path)."'"; } $resql = $db->query($sql); if ($resql) { $file_list = array(); $num = $db->num_rows($resql); $i = 0; while ($i < $num) { $obj = $db->fetch_object($resql); if ($obj) { $reg = array(); preg_match('/([^\/]+)\/[^\/]+$/', DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename, $reg); $level1name = (isset($reg[1]) ? $reg[1] : ''); $file_list[] = array( "rowid" => $obj->rowid, "label" => $obj->label, // md5 "name" => $obj->filename, "path" => DOL_DATA_ROOT.'/'.$obj->filepath, "level1name" => $level1name, "fullname" => DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename, "fullpath_orig" => $obj->fullpath_orig, "date_c" => $db->jdate($obj->date_c), "date_m" => $db->jdate($obj->date_m), "type" => 'file', "keywords" => $obj->keywords, "cover" => $obj->cover, "position" => (int) $obj->position, "acl" => $obj->acl, "share" => $obj->share ); } $i++; } // Obtain a list of columns if (!empty($sortcriteria)) { $myarray = array(); foreach ($file_list as $key => $row) { $myarray[$key] = (isset($row[$sortcriteria]) ? $row[$sortcriteria] : ''); } // Sort the data if ($sortorder) { array_multisort($myarray, $sortorder, $file_list); } } return $file_list; } else { dol_print_error($db); return array(); } } /** * Complete $filearray with data from database. * This will call doldir_list_indatabase to complate filearray. * * @param array $filearray Array of files obtained using dol_dir_list * @param string $relativedir Relative dir from DOL_DATA_ROOT * @return void */ function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir) { global $conf, $db, $user; $filearrayindatabase = dol_dir_list_in_database($relativedir, '', null, 'name', SORT_ASC); // TODO Remove this when PRODUCT_USE_OLD_PATH_FOR_PHOTO will be removed global $modulepart; if ($modulepart == 'produit' && !empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) { global $object; if (!empty($object->id)) { if (!empty($conf->product->enabled)) { $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"; } else { $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"; } $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dirold); $relativedirold = preg_replace('/^[\\/]/', '', $relativedirold); $filearrayindatabase = array_merge($filearrayindatabase, dol_dir_list_in_database($relativedirold, '', null, 'name', SORT_ASC)); } } /*var_dump($relativedir); var_dump($filearray); var_dump($filearrayindatabase);*/ // Complete filearray with properties found into $filearrayindatabase foreach ($filearray as $key => $val) { $tmpfilename = preg_replace('/\.noexe$/', '', $filearray[$key]['name']); $found = 0; // Search if it exists into $filearrayindatabase foreach ($filearrayindatabase as $key2 => $val2) { if (($filearrayindatabase[$key2]['path'] == $filearray[$key]['path']) && ($filearrayindatabase[$key2]['name'] == $tmpfilename)) { $filearray[$key]['position_name'] = ($filearrayindatabase[$key2]['position'] ? $filearrayindatabase[$key2]['position'] : '0').'_'.$filearrayindatabase[$key2]['name']; $filearray[$key]['position'] = $filearrayindatabase[$key2]['position']; $filearray[$key]['cover'] = $filearrayindatabase[$key2]['cover']; $filearray[$key]['acl'] = $filearrayindatabase[$key2]['acl']; $filearray[$key]['rowid'] = $filearrayindatabase[$key2]['rowid']; $filearray[$key]['label'] = $filearrayindatabase[$key2]['label']; $filearray[$key]['share'] = $filearrayindatabase[$key2]['share']; $found = 1; break; } } if (!$found) { // This happen in transition toward version 6, or if files were added manually into os dir. $filearray[$key]['position'] = '999999'; // File not indexed are at end. So if we add a file, it will not replace an existing position $filearray[$key]['cover'] = 0; $filearray[$key]['acl'] = ''; $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filearray[$key]['fullname']); if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filename)) { // If not a tmp file dol_syslog("list_of_documents We found a file called '".$filearray[$key]['name']."' not indexed into database. We add it"); include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; $ecmfile = new EcmFiles($db); // Add entry into database $filename = basename($rel_filename); $rel_dir = dirname($rel_filename); $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); $ecmfile->filepath = $rel_dir; $ecmfile->filename = $filename; $ecmfile->label = md5_file(dol_osencode($filearray[$key]['fullname'])); // $destfile is a full path to file $ecmfile->fullpath_orig = $filearray[$key]['fullname']; $ecmfile->gen_or_uploaded = 'unknown'; $ecmfile->description = ''; // indexed content $ecmfile->keywords = ''; // keyword content $result = $ecmfile->create($user); if ($result < 0) { setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); } else { $filearray[$key]['rowid'] = $result; } } else { $filearray[$key]['rowid'] = 0; // Should not happened } } } //var_dump($filearray); var_dump($relativedir.' - tmpfilename='.$tmpfilename.' - found='.$found); } /** * Fast compare of 2 files identified by their properties ->name, ->date and ->size * * @param string $a File 1 * @param string $b File 2 * @return int 1, 0, 1 */ function dol_compare_file($a, $b) { global $sortorder; global $sortfield; $sortorder = strtoupper($sortorder); if ($sortorder == 'ASC') { $retup = -1; $retdown = 1; } else { $retup = 1; $retdown = -1; } if ($sortfield == 'name') { if ($a->name == $b->name) { return 0; } return ($a->name < $b->name) ? $retup : $retdown; } if ($sortfield == 'date') { if ($a->date == $b->date) { return 0; } return ($a->date < $b->date) ? $retup : $retdown; } if ($sortfield == 'size') { if ($a->size == $b->size) { return 0; } return ($a->size < $b->size) ? $retup : $retdown; } } /** * Test if filename is a directory * * @param string $folder Name of folder * @return boolean True if it's a directory, False if not found */ function dol_is_dir($folder) { $newfolder = dol_osencode($folder); if (is_dir($newfolder)) { return true; } else { return false; } } /** * Return if path is empty * * @param string $dir Path of Directory * @return boolean True or false */ function dol_is_dir_empty($dir) { if (!is_readable($dir)) { return false; } return (count(scandir($dir)) == 2); } /** * Return if path is a file * * @param string $pathoffile Path of file * @return boolean True or false */ function dol_is_file($pathoffile) { $newpathoffile = dol_osencode($pathoffile); return is_file($newpathoffile); } /** * Return if path is a symbolic link * * @param string $pathoffile Path of file * @return boolean True or false */ function dol_is_link($pathoffile) { $newpathoffile = dol_osencode($pathoffile); return is_link($newpathoffile); } /** * Return if path is an URL * * @param string $url Url * @return boolean True or false */ function dol_is_url($url) { $tmpprot = array('file', 'http', 'https', 'ftp', 'zlib', 'data', 'ssh', 'ssh2', 'ogg', 'expect'); foreach ($tmpprot as $prot) { if (preg_match('/^'.$prot.':/i', $url)) { return true; } } return false; } /** * Test if a folder is empty * * @param string $folder Name of folder * @return boolean True if dir is empty or non-existing, False if it contains files */ function dol_dir_is_emtpy($folder) { $newfolder = dol_osencode($folder); if (is_dir($newfolder)) { $handle = opendir($newfolder); $folder_content = ''; while ((gettype($name = readdir($handle)) != "boolean")) { $name_array[] = $name; } foreach ($name_array as $temp) { $folder_content .= $temp; } closedir($handle); if ($folder_content == "...") { return true; } else { return false; } } else { return true; // Dir does not exists } } /** * Count number of lines in a file * * @param string $file Filename * @return int <0 if KO, Number of lines in files if OK * @see dol_nboflines() */ function dol_count_nb_of_line($file) { $nb = 0; $newfile = dol_osencode($file); //print 'x'.$file; $fp = fopen($newfile, 'r'); if ($fp) { while (!feof($fp)) { $line = fgets($fp); // We increase count only if read was success. We need test because feof return true only after fgets so we do n+1 fgets for a file with n lines. if (!$line === false) { $nb++; } } fclose($fp); } else { $nb = -1; } return $nb; } /** * Return size of a file * * @param string $pathoffile Path of file * @return integer File size * @see dol_print_size() */ function dol_filesize($pathoffile) { $newpathoffile = dol_osencode($pathoffile); return filesize($newpathoffile); } /** * Return time of a file * * @param string $pathoffile Path of file * @return int Time of file */ function dol_filemtime($pathoffile) { $newpathoffile = dol_osencode($pathoffile); return @filemtime($newpathoffile); // @Is to avoid errors if files does not exists } /** * Return permissions of a file * * @param string $pathoffile Path of file * @return integer File permissions */ function dol_fileperm($pathoffile) { $newpathoffile = dol_osencode($pathoffile); return fileperms($newpathoffile); } /** * Make replacement of strings into a file. * * @param string $srcfile Source file (can't be a directory) * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file. * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' * @param int $indexdatabase 1=index new file into database. * @param int $arrayreplacementisregex 1=Array of replacement is regex * @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK * @see dol_copy() */ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask = 0, $indexdatabase = 0, $arrayreplacementisregex = 0) { global $conf; dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase." arrayreplacementisregex=".$arrayreplacementisregex); if (empty($srcfile)) { return -1; } if (empty($destfile)) { $destfile = $srcfile; } $destexists = dol_is_file($destfile); if (($destfile != $srcfile) && $destexists) { return 0; } $tmpdestfile = $destfile.'.tmp'; $newpathofsrcfile = dol_osencode($srcfile); $newpathoftmpdestfile = dol_osencode($tmpdestfile); $newpathofdestfile = dol_osencode($destfile); $newdirdestfile = dirname($newpathofdestfile); if ($destexists && !is_writable($newpathofdestfile)) { dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to overwrite target file", LOG_WARNING); return -1; } if (!is_writable($newdirdestfile)) { dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING); return -2; } dol_delete_file($tmpdestfile); // Create $newpathoftmpdestfile from $newpathofsrcfile $content = file_get_contents($newpathofsrcfile, 'r'); if (empty($arrayreplacementisregex)) { $content = make_substitutions($content, $arrayreplacement, null); } else { foreach ($arrayreplacement as $key => $value) { $content = preg_replace($key, $value, $content); } } file_put_contents($newpathoftmpdestfile, $content); @chmod($newpathoftmpdestfile, octdec($newmask)); // Rename $result = dol_move($newpathoftmpdestfile, $newpathofdestfile, $newmask, (($destfile == $srcfile) ? 1 : 0), 0, $indexdatabase); if (!$result) { dol_syslog("files.lib.php::dolReplaceInFile failed to move tmp file to final dest", LOG_WARNING); return -3; } if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) { $newmask = $conf->global->MAIN_UMASK; } if (empty($newmask)) { // This should no happen dol_syslog("Warning: dolReplaceInFile called with empty value for newmask and no default value defined", LOG_WARNING); $newmask = '0664'; } @chmod($newpathofdestfile, octdec($newmask)); return 1; } /** * Copy a file to another file. * * @param string $srcfile Source file (can't be a directory) * @param string $destfile Destination file (can't be a directory) * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' * @param int $overwriteifexists Overwrite file if exists (1 by default) * @return int <0 if error, 0 if nothing done (dest file already exists and overwriteifexists=0), >0 if OK * @see dol_delete_file() dolCopyDir() */ function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) { global $conf; dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists); if (empty($srcfile) || empty($destfile)) { return -1; } $destexists = dol_is_file($destfile); if (!$overwriteifexists && $destexists) { return 0; } $newpathofsrcfile = dol_osencode($srcfile); $newpathofdestfile = dol_osencode($destfile); $newdirdestfile = dirname($newpathofdestfile); if ($destexists && !is_writable($newpathofdestfile)) { dol_syslog("files.lib.php::dol_copy failed Permission denied to overwrite target file", LOG_WARNING); return -1; } if (!is_writable($newdirdestfile)) { dol_syslog("files.lib.php::dol_copy failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING); return -2; } // Copy with overwriting if exists $result = @copy($newpathofsrcfile, $newpathofdestfile); //$result=copy($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @ if (!$result) { dol_syslog("files.lib.php::dol_copy failed to copy", LOG_WARNING); return -3; } if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) { $newmask = $conf->global->MAIN_UMASK; } if (empty($newmask)) { // This should no happen dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING); $newmask = '0664'; } @chmod($newpathofdestfile, octdec($newmask)); return 1; } /** * Copy a dir to another dir. This include recursive subdirectories. * * @param string $srcfile Source file (a directory) * @param string $destfile Destination file (a directory) * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' * @param int $overwriteifexists Overwrite file if exists (1 by default) * @param array $arrayreplacement Array to use to replace filenames with another one during the copy (works only on file names, not on directory names). * @param int $excludesubdir 0=Do not exclude subdirectories, 1=Exclude subdirectories, 2=Exclude subdirectories if name is not a 2 chars (used for country codes subdirectories). * @return int <0 if error, 0 if nothing done (all files already exists and overwriteifexists=0), >0 if OK * @see dol_copy() */ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null, $excludesubdir = 0) { global $conf; $result = 0; dol_syslog("files.lib.php::dolCopyDir srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists); if (empty($srcfile) || empty($destfile)) { return -1; } $destexists = dol_is_dir($destfile); //if (! $overwriteifexists && $destexists) return 0; // The overwriteifexists is for files only, so propagated to dol_copy only. if (!$destexists) { // We must set mask just before creating dir, becaause it can be set differently by dol_copy umask(0); $dirmaskdec = octdec($newmask); if (empty($newmask) && !empty($conf->global->MAIN_UMASK)) { $dirmaskdec = octdec($conf->global->MAIN_UMASK); } $dirmaskdec |= octdec('0200'); // Set w bit required to be able to create content for recursive subdirs files dol_mkdir($destfile, '', decoct($dirmaskdec)); } $ossrcfile = dol_osencode($srcfile); $osdestfile = dol_osencode($destfile); // Recursive function to copy all subdirectories and contents: if (is_dir($ossrcfile)) { $dir_handle = opendir($ossrcfile); while ($file = readdir($dir_handle)) { if ($file != "." && $file != ".." && !is_link($ossrcfile."/".$file)) { if (is_dir($ossrcfile."/".$file)) { if (empty($excludesubdir) || ($excludesubdir == 2 && strlen($file) == 2)) { $newfile = $file; // Replace destination filename with a new one if (is_array($arrayreplacement)) { foreach ($arrayreplacement as $key => $val) { $newfile = str_replace($key, $val, $newfile); } } //var_dump("xxx dolCopyDir $srcfile/$file, $destfile/$file, $newmask, $overwriteifexists"); $tmpresult = dolCopyDir($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists, $arrayreplacement, $excludesubdir); } } else { $newfile = $file; // Replace destination filename with a new one if (is_array($arrayreplacement)) { foreach ($arrayreplacement as $key => $val) { $newfile = str_replace($key, $val, $newfile); } } $tmpresult = dol_copy($srcfile."/".$file, $destfile."/".$newfile, $newmask, $overwriteifexists); } // Set result if ($result > 0 && $tmpresult >= 0) { // Do nothing, so we don't set result to 0 if tmpresult is 0 and result was success in a previous pass } else { $result = $tmpresult; } if ($result < 0) { break; } } } closedir($dir_handle); } else { // Source directory does not exists $result = -2; } return $result; } /** * Move a file into another name. * Note: * - This function differs from dol_move_uploaded_file, because it can be called in any context. * - Database indexes for files are updated. * - Test on antivirus is done only if param testvirus is provided and an antivirus was set. * * @param string $srcfile Source file (can't be a directory. use native php @rename() to move a directory) * @param string $destfile Destination file (can't be a directory. use native php @rename() to move a directory) * @param integer $newmask Mask in octal string for new file (0 by default means $conf->global->MAIN_UMASK) * @param int $overwriteifexists Overwrite file if exists (1 by default) * @param int $testvirus Do an antivirus test. Move is canceled if a virus is found. * @param int $indexdatabase Index new file into database. * @return boolean True if OK, false if KO * @see dol_move_uploaded_file() */ function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1) { global $user, $db, $conf; $result = false; dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists); $srcexists = dol_is_file($srcfile); $destexists = dol_is_file($destfile); if (!$srcexists) { dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request."); return false; } if ($overwriteifexists || !$destexists) { $newpathofsrcfile = dol_osencode($srcfile); $newpathofdestfile = dol_osencode($destfile); // Check virus $testvirusarray = array(); if ($testvirus) { $testvirusarray = dolCheckVirus($newpathofsrcfile); if (count($testvirusarray)) { dol_syslog("files.lib.php::dol_move canceled because a virus was found into source file. we ignore the move request.", LOG_WARNING); return false; } } $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @ if (!$result) { if ($destexists) { dol_syslog("files.lib.php::dol_move Failed. We try to delete target first and move after.", LOG_WARNING); // We force delete and try again. Rename function sometimes fails to replace dest file with some windows NTFS partitions. dol_delete_file($destfile); $result = @rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @ } else { dol_syslog("files.lib.php::dol_move Failed.", LOG_WARNING); } } // Move ok if ($result && $indexdatabase) { // Rename entry into ecm database $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile); $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile); if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) { // If not a tmp file $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore); $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter); //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);exit; dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG); include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; $ecmfiletarget = new EcmFiles($db); $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetorenameafter); if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created. $ecmfiletarget->delete($user); } $ecmfile = new EcmFiles($db); $resultecm = $ecmfile->fetch(0, '', $rel_filetorenamebefore); if ($resultecm > 0) { // If an entry was found for src file, we use it to move entry $filename = basename($rel_filetorenameafter); $rel_dir = dirname($rel_filetorenameafter); $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); $ecmfile->filepath = $rel_dir; $ecmfile->filename = $filename; $resultecm = $ecmfile->update($user); } elseif ($resultecm == 0) { // If no entry were found for src files, create/update target file $filename = basename($rel_filetorenameafter); $rel_dir = dirname($rel_filetorenameafter); $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); $ecmfile->filepath = $rel_dir; $ecmfile->filename = $filename; $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file $ecmfile->fullpath_orig = $srcfile; $ecmfile->gen_or_uploaded = 'unknown'; $ecmfile->description = ''; // indexed content $ecmfile->keywords = ''; // keyword content $resultecm = $ecmfile->create($user); if ($resultecm < 0) { setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); } } elseif ($resultecm < 0) { setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); } if ($resultecm > 0) { $result = true; } else { $result = false; } } } if (empty($newmask)) { $newmask = empty($conf->global->MAIN_UMASK) ? '0755' : $conf->global->MAIN_UMASK; } $newmaskdec = octdec($newmask); // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too) // to allow mask usage for dir, we shoul introduce a new param "isdir" to 1 to complete newmask like this // if ($isdir) $newmaskdec |= octdec('0111'); // Set x bit required for directories @chmod($newpathofdestfile, $newmaskdec); } return $result; } /** * Unescape a file submitted by upload. * PHP escape char " (%22) or char ' (%27) into $FILES. * * @param string $filename Filename * @return string Filename sanitized */ function dol_unescapefile($filename) { // Remove path information and dots around the filename, to prevent uploading // into different directories or replacing hidden system files. // Also remove control characters and spaces (\x00..\x20) around the filename: return trim(basename($filename), ".\x00..\x20"); } /** * Check virus into a file * * @param string $src_file Source file to check * @return array Array of errors or empty array if not virus found */ function dolCheckVirus($src_file) { global $conf, $db; if (!empty($conf->global->MAIN_ANTIVIRUS_COMMAND)) { if (!class_exists('AntiVir')) { require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php'; } $antivir = new AntiVir($db); $result = $antivir->dol_avscan_file($src_file); if ($result < 0) { // If virus or error, we stop here $reterrors = $antivir->errors; return $reterrors; } } return array(); } /** * Make control on an uploaded file from an GUI page and move it to final destination. * If there is errors (virus found, antivir in error, bad filename), file is not moved. * Note: * - This function can be used only into a HTML page context. Use dol_move if you are outside. * - Test on antivirus is always done (if antivirus set). * - Database of files is NOT updated (this is done by dol_add_file_process() that calls this function). * - Extension .noexe may be added if file is executable and MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED is not set. * * @param string $src_file Source full path filename ($_FILES['field']['tmp_name']) * @param string $dest_file Target full path filename ($_FILES['field']['name']) * @param int $allowoverwrite 1=Overwrite target file if it already exists * @param int $disablevirusscan 1=Disable virus scan * @param integer $uploaderrorcode Value of PHP upload error code ($_FILES['field']['error']) * @param int $nohook Disable all hooks * @param string $varfiles _FILES var name * @param string $upload_dir For information. Already included into $dest_file. * @return int|string 1 if OK, 2 if OK and .noexe appended, <0 or string if KO * @see dol_move() */ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile', $upload_dir = '') { global $conf, $db, $user, $langs; global $object, $hookmanager; $reshook = 0; $file_name = $dest_file; $successcode = 1; if (empty($nohook)) { $reshook = $hookmanager->initHooks(array('fileslib')); $parameters = array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); $reshook = $hookmanager->executeHooks('moveUploadedFile', $parameters, $object); } if (empty($reshook)) { // If an upload error has been reported if ($uploaderrorcode) { switch ($uploaderrorcode) { case UPLOAD_ERR_INI_SIZE: // 1 return 'ErrorFileSizeTooLarge'; case UPLOAD_ERR_FORM_SIZE: // 2 return 'ErrorFileSizeTooLarge'; case UPLOAD_ERR_PARTIAL: // 3 return 'ErrorPartialFile'; case UPLOAD_ERR_NO_TMP_DIR: // return 'ErrorNoTmpDir'; case UPLOAD_ERR_CANT_WRITE: return 'ErrorFailedToWriteInDir'; case UPLOAD_ERR_EXTENSION: return 'ErrorUploadBlockedByAddon'; default: break; } } // If we need to make a virus scan if (empty($disablevirusscan) && file_exists($src_file)) { $checkvirusarray = dolCheckVirus($src_file); if (count($checkvirusarray)) { dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING); return 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray); } } // Security: // Disallow file with some extensions. We rename them. // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code. if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) { // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too. $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity]; if (!preg_match('/\/$/', $publicmediasdirwithslash)) { $publicmediasdirwithslash .= '/'; } if (strpos($upload_dir, $publicmediasdirwithslash) !== 0) { // We never add .noexe on files into media directory $file_name .= '.noexe'; $successcode = 2; } } // Security: // We refuse cache files/dirs, upload using .. and pipes into filenames. if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) { dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING); return -1; } // Security: // We refuse cache files/dirs, upload using .. and pipes into filenames. if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) { dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING); return -2; } } if ($reshook < 0) { // At least one blocking error returned by one hook $errmsg = join(',', $hookmanager->errors); if (empty($errmsg)) { $errmsg = 'ErrorReturnedBySomeHooks'; // Should not occurs. Added if hook is bugged and does not set ->errors when there is error. } return $errmsg; } elseif (empty($reshook)) { // The file functions must be in OS filesystem encoding. $src_file_osencoded = dol_osencode($src_file); $file_name_osencoded = dol_osencode($file_name); // Check if destination dir is writable if (!is_writable(dirname($file_name_osencoded))) { dol_syslog("Files.lib::dol_move_uploaded_file Dir ".dirname($file_name_osencoded)." is not writable. Return 'ErrorDirNotWritable'", LOG_WARNING); return 'ErrorDirNotWritable'; } // Check if destination file already exists if (!$allowoverwrite) { if (file_exists($file_name_osencoded)) { dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING); return 'ErrorFileAlreadyExists'; } } else { // We are allowed to erase if (is_dir($file_name_osencoded)) { // If there is a directory with name of file to create dol_syslog("Files.lib::dol_move_uploaded_file A directory with name ".$file_name." already exists. Return 'ErrorDirWithFileNameAlreadyExists'", LOG_WARNING); return 'ErrorDirWithFileNameAlreadyExists'; } } // Move file $return = move_uploaded_file($src_file_osencoded, $file_name_osencoded); if ($return) { if (!empty($conf->global->MAIN_UMASK)) { @chmod($file_name_osencoded, octdec($conf->global->MAIN_UMASK)); } dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG); return $successcode; // Success } else { dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR); return -3; // Unknown error } } return $successcode; // Success } /** * Remove a file or several files with a mask. * This delete file physically but also database indexes. * * @param string $file File to delete or mask of files to delete * @param int $disableglob Disable usage of glob like * so function is an exact delete function that will return error if no file found * @param int $nophperrors Disable all PHP output errors * @param int $nohook Disable all hooks * @param object $object Current object in use * @param boolean $allowdotdot Allow to delete file path with .. inside. Never use this, it is reserved for migration purpose. * @param int $indexdatabase Try to remove also index entries. * @param int $nolog Disable log file * @return boolean True if no error (file is deleted or if glob is used and there's nothing to delete), False if error * @see dol_delete_dir() */ function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1, $nolog = 0) { global $db, $conf, $user, $langs; global $hookmanager; // Load translation files required by the page $langs->loadLangs(array('other', 'errors')); if (empty($nolog)) { dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook); } // Security: // We refuse transversal using .. and pipes into filenames. if ((!$allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file)) { dol_syslog("Refused to delete file ".$file, LOG_WARNING); return false; } $reshook = 0; if (empty($nohook)) { $hookmanager->initHooks(array('fileslib')); $parameters = array( 'GET' => $_GET, 'file' => $file, 'disableglob'=> $disableglob, 'nophperrors' => $nophperrors ); $reshook = $hookmanager->executeHooks('deleteFile', $parameters, $object); } if (empty($nohook) && $reshook != 0) { // reshook = 0 to do standard actions, 1 = ok and replace, -1 = ko dol_syslog("reshook=".$reshook); if ($reshook < 0) { return false; } return true; } else { $file_osencoded = dol_osencode($file); // New filename encoded in OS filesystem encoding charset if (empty($disableglob) && !empty($file_osencoded)) { $ok = true; $globencoded = str_replace('[', '\[', $file_osencoded); $globencoded = str_replace(']', '\]', $globencoded); $listofdir = glob($globencoded); if (!empty($listofdir) && is_array($listofdir)) { foreach ($listofdir as $filename) { if ($nophperrors) { $ok = @unlink($filename); } else { $ok = unlink($filename); } // If it fails and it is because of the missing write permission on parent dir if (!$ok && file_exists(dirname($filename)) && !(fileperms(dirname($filename)) & 0200)) { 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); @chmod(dirname($filename), fileperms(dirname($filename)) | 0200); // Now we retry deletion if ($nophperrors) { $ok = @unlink($filename); } else { $ok = unlink($filename); } } if ($ok) { if (empty($nolog)) { dol_syslog("Removed file ".$filename, LOG_DEBUG); } // Delete entry into ecm database $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename); if (!preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) { // If not a tmp file if (is_object($db) && $indexdatabase) { // $db may not be defined when lib is in a context with define('NOREQUIREDB',1) $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete); $rel_filetodelete = preg_replace('/\.noexe$/', '', $rel_filetodelete); dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG); include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; $ecmfile = new EcmFiles($db); $result = $ecmfile->fetch(0, '', $rel_filetodelete); if ($result >= 0 && $ecmfile->id > 0) { $result = $ecmfile->delete($user); } if ($result < 0) { setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); } } } } else { dol_syslog("Failed to remove file ".$filename, LOG_WARNING); // TODO Failure to remove can be because file was already removed or because of permission // If error because it does not exists, we should return true, and we should return false if this is a permission problem } } } else { dol_syslog("No files to delete found", LOG_DEBUG); } } else { $ok = false; if ($nophperrors) { $ok = @unlink($file_osencoded); } else { $ok = unlink($file_osencoded); } if ($ok) { if (empty($nolog)) { dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG); } } else { dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING); } } return $ok; } } /** * Remove a directory (not recursive, so content must be empty). * If directory is not empty, return false * * @param string $dir Directory to delete * @param int $nophperrors Disable all PHP output errors * @return boolean True if success, false if error * @see dol_delete_file() dolCopyDir() */ function dol_delete_dir($dir, $nophperrors = 0) { // Security: // We refuse transversal using .. and pipes into filenames. if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) { dol_syslog("Refused to delete dir ".$dir, LOG_WARNING); return false; } $dir_osencoded = dol_osencode($dir); return ($nophperrors ? @rmdir($dir_osencoded) : rmdir($dir_osencoded)); } /** * Remove a directory $dir and its subdirectories (or only files and subdirectories) * * @param string $dir Dir to delete * @param int $count Counter to count nb of elements found to delete * @param int $nophperrors Disable all PHP output errors * @param int $onlysub Delete only files and subdir, not main directory * @param int $countdeleted Counter to count nb of elements found really deleted * @param int $indexdatabase Try to remove also index entries. * @param int $nolog Disable log files (too verbose when making recursive directories) * @return int Number of files and directory we try to remove. NB really removed is returned into var by reference $countdeleted. */ function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0, $indexdatabase = 1, $nolog = 0) { if (empty($nolog)) { dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG); } if (dol_is_dir($dir)) { $dir_osencoded = dol_osencode($dir); if ($handle = opendir("$dir_osencoded")) { while (false !== ($item = readdir($handle))) { if (!utf8_check($item)) { $item = utf8_encode($item); // should be useless } if ($item != "." && $item != "..") { if (is_dir(dol_osencode("$dir/$item")) && !is_link(dol_osencode("$dir/$item"))) { $count = dol_delete_dir_recursive("$dir/$item", $count, $nophperrors, 0, $countdeleted, $indexdatabase, $nolog); } else { $result = dol_delete_file("$dir/$item", 1, $nophperrors, 0, null, false, $indexdatabase, $nolog); $count++; if ($result) { $countdeleted++; } //else print 'Error on '.$item."\n"; } } } closedir($handle); // Delete also the main directory if (empty($onlysub)) { $result = dol_delete_dir($dir, $nophperrors); $count++; if ($result) { $countdeleted++; } //else print 'Error on '.$dir."\n"; } } } return $count; } /** * Delete all preview files linked to object instance. * Note that preview image of PDF files is generated when required, by dol_banner_tab() for example. * * @param object $object Object to clean * @return int 0 if error, 1 if OK * @see dol_convert_file() */ function dol_delete_preview($object) { global $langs, $conf; // Define parent dir of elements $element = $object->element; if ($object->element == 'order_supplier') { $dir = $conf->fournisseur->commande->dir_output; } elseif ($object->element == 'invoice_supplier') { $dir = $conf->fournisseur->facture->dir_output; } elseif ($object->element == 'project') { $dir = $conf->projet->dir_output; } elseif ($object->element == 'shipping') { $dir = $conf->expedition->dir_output.'/sending'; } elseif ($object->element == 'delivery') { $dir = $conf->expedition->dir_output.'/receipt'; } elseif ($object->element == 'fichinter') { $dir = $conf->ficheinter->dir_output; } else { $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output; } if (empty($dir)) { return 'ErrorObjectNoSupportedByFunction'; } $refsan = dol_sanitizeFileName($object->ref); $dir = $dir."/".$refsan; $filepreviewnew = $dir."/".$refsan.".pdf_preview.png"; $filepreviewnewbis = $dir."/".$refsan.".pdf_preview-0.png"; $filepreviewold = $dir."/".$refsan.".pdf.png"; // For new preview files if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) { if (!dol_delete_file($filepreviewnew, 1)) { $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnew); return 0; } } if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) { if (!dol_delete_file($filepreviewnewbis, 1)) { $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis); return 0; } } // For old preview files if (file_exists($filepreviewold) && is_writable($filepreviewold)) { if (!dol_delete_file($filepreviewold, 1)) { $object->error = $langs->trans("ErrorFailedToDeleteFile", $filepreviewold); return 0; } } else { $multiple = $filepreviewold."."; for ($i = 0; $i < 20; $i++) { $preview = $multiple.$i; if (file_exists($preview) && is_writable($preview)) { if (!dol_delete_file($preview, 1)) { $object->error = $langs->trans("ErrorFailedToOpenFile", $preview); return 0; } } } } return 1; } /** * Create a meta file with document file into same directory. * This make "grep" search possible. * This feature to generate the meta file is enabled only if option MAIN_DOC_CREATE_METAFILE is set. * * @param CommonObject $object Object * @return int 0 if do nothing, >0 if we update meta file too, <0 if KO */ function dol_meta_create($object) { global $conf; // Create meta file if (empty($conf->global->MAIN_DOC_CREATE_METAFILE)) { return 0; // By default, no metafile. } // Define parent dir of elements $element = $object->element; if ($object->element == 'order_supplier') { $dir = $conf->fournisseur->dir_output.'/commande'; } elseif ($object->element == 'invoice_supplier') { $dir = $conf->fournisseur->dir_output.'/facture'; } elseif ($object->element == 'project') { $dir = $conf->projet->dir_output; } elseif ($object->element == 'shipping') { $dir = $conf->expedition->dir_output.'/sending'; } elseif ($object->element == 'delivery') { $dir = $conf->expedition->dir_output.'/receipt'; } elseif ($object->element == 'fichinter') { $dir = $conf->ficheinter->dir_output; } else { $dir = empty($conf->$element->dir_output) ? '' : $conf->$element->dir_output; } if ($dir) { $object->fetch_thirdparty(); $objectref = dol_sanitizeFileName($object->ref); $dir = $dir."/".$objectref; $file = $dir."/".$objectref.".meta"; if (!is_dir($dir)) { dol_mkdir($dir); } if (is_dir($dir)) { $nblines = count($object->lines); $client = $object->thirdparty->name." ".$object->thirdparty->address." ".$object->thirdparty->zip." ".$object->thirdparty->town; $meta = "REFERENCE=\"".$object->ref."\" DATE=\"" . dol_print_date($object->date, '')."\" NB_ITEMS=\"" . $nblines."\" CLIENT=\"" . $client."\" AMOUNT_EXCL_TAX=\"" . $object->total_ht."\" AMOUNT=\"" . $object->total_ttc."\"\n"; for ($i = 0; $i < $nblines; $i++) { //Pour les articles $meta .= "ITEM_".$i."_QUANTITY=\"".$object->lines[$i]->qty."\" ITEM_" . $i."_AMOUNT_WO_TAX=\"".$object->lines[$i]->total_ht."\" ITEM_" . $i."_VAT=\"".$object->lines[$i]->tva_tx."\" ITEM_" . $i."_DESCRIPTION=\"".str_replace("\r\n", "", nl2br($object->lines[$i]->desc))."\" "; } } $fp = fopen($file, "w"); fputs($fp, $meta); fclose($fp); if (!empty($conf->global->MAIN_UMASK)) { @chmod($file, octdec($conf->global->MAIN_UMASK)); } return 1; } else { dol_syslog('FailedToDetectDirInDolMetaCreateFor'.$object->element, LOG_WARNING); } return 0; } /** * Scan a directory and init $_SESSION to manage uploaded files with list of all found files. * Note: Only email module seems to use this. Other feature initialize the $_SESSION doing $formmail->clear_attached_files(); $formmail->add_attached_files() * * @param string $pathtoscan Path to scan * @param string $trackid Track id (used to prefix name of session vars to avoid conflict) * @return void */ function dol_init_file_process($pathtoscan = '', $trackid = '') { $listofpaths = array(); $listofnames = array(); $listofmimes = array(); if ($pathtoscan) { $listoffiles = dol_dir_list($pathtoscan, 'files'); foreach ($listoffiles as $key => $val) { $listofpaths[] = $val['fullname']; $listofnames[] = $val['name']; $listofmimes[] = dol_mimetype($val['name']); } } $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid; $_SESSION["listofpaths".$keytoavoidconflict] = join(';', $listofpaths); $_SESSION["listofnames".$keytoavoidconflict] = join(';', $listofnames); $_SESSION["listofmimes".$keytoavoidconflict] = join(';', $listofmimes); } /** * Get and save an upload file (for example after submitting a new file a mail form). Database index of file is also updated if donotupdatesession is set. * All information used are in db, conf, langs, user and _FILES. * Note: This function can be used only into a HTML page context. * * @param string $upload_dir Directory where to store uploaded file (note: used to forge $destpath = $upload_dir + filename) * @param int $allowoverwrite 1=Allow overwrite existing file * @param int $donotupdatesession 1=Do no edit _SESSION variable but update database index. 0=Update _SESSION and not database index. -1=Do not update SESSION neither db. * @param string $varfiles _FILES var name * @param string $savingdocmask Mask to use to define output filename. For example 'XXXXX-__YYYYMMDD__-__file__' * @param string $link Link to add (to add a link instead of a file) * @param string $trackid Track id (used to prefix name of session vars to avoid conflict) * @param int $generatethumbs 1=Generate also thumbs for uploaded image files * @param Object $object Object used to set 'src_object_*' fields * @return int <=0 if KO, >0 if OK * @see dol_remove_file_process() */ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null) { global $db, $user, $conf, $langs; $res = 0; if (!empty($_FILES[$varfiles])) { // For view $_FILES[$varfiles]['error'] dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG); $result = dol_mkdir($upload_dir); // var_dump($result);exit; if ($result >= 0) { $TFile = $_FILES[$varfiles]; if (!is_array($TFile['name'])) { foreach ($TFile as $key => &$val) { $val = array($val); } } $nbfile = count($TFile['name']); $nbok = 0; for ($i = 0; $i < $nbfile; $i++) { if (empty($TFile['name'][$i])) { continue; // For example, when submitting a form with no file name } // Define $destfull (path to file including filename) and $destfile (only filename) $destfull = $upload_dir."/".$TFile['name'][$i]; $destfile = $TFile['name'][$i]; $destfilewithoutext = preg_replace('/\.[^\.]+$/', '', $destfile); if ($savingdocmask && strpos($savingdocmask, $destfilewithoutext) !== 0) { $destfull = $upload_dir."/".preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask); $destfile = preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask); } $filenameto = basename($destfile); if (preg_match('/^\./', $filenameto)) { $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now. setEventMessages($langs->trans("ErrorFilenameCantStartWithDot", $filenameto), null, 'errors'); break; } // dol_sanitizeFileName the file name and lowercase extension $info = pathinfo($destfull); $destfull = $info['dirname'].'/'.dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : '')); $info = pathinfo($destfile); $destfile = dol_sanitizeFileName($info['filename'].($info['extension'] != '' ? ('.'.strtolower($info['extension'])) : '')); // We apply dol_string_nohtmltag also to clean file names (this remove duplicate spaces) because // this function is also applied when we rename and when we make try to download file (by the GETPOST(filename, 'alphanohtml') call). $destfile = dol_string_nohtmltag($destfile); $destfull = dol_string_nohtmltag($destfull); // Move file from temp directory to final directory. A .noexe may also be appended on file name. $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles, $upload_dir); if (is_numeric($resupload) && $resupload > 0) { // $resupload can be 'ErrorFileAlreadyExists' global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini; include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; // Generate thumbs. if ($generatethumbs) { if (image_format_supported($destfull) == 1) { // Create thumbs // We can't use $object->addThumbs here because there is no $object known // Used on logon for example $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs"); // Create mini thumbs for image (Ratio is near 16/9) // Used on menu or for setup page for example $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs"); } } // Update session if (empty($donotupdatesession)) { include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; $formmail = new FormMail($db); $formmail->trackid = $trackid; $formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]); } // Update index table of files (llx_ecm_files) if ($donotupdatesession == 1) { $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', 0, $object); if ($result < 0) { if ($allowoverwrite) { // Do not show error message. We can have an error due to DB_ERROR_RECORD_ALREADY_EXISTS } else { setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', '', 'warnings'); } } } $nbok++; } else { $langs->load("errors"); if ($resupload < 0) { // Unknown error setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors'); } elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) { // Files infected by a virus setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors'); } else // Known error { setEventMessages($langs->trans($resupload), null, 'errors'); } } } if ($nbok > 0) { $res = 1; setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs'); } } else { setEventMessages($langs->trans("ErrorFailedToCreateDir", $upload_dir), null, 'errors'); } } elseif ($link) { require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; $linkObject = new Link($db); $linkObject->entity = $conf->entity; $linkObject->url = $link; $linkObject->objecttype = GETPOST('objecttype', 'alpha'); $linkObject->objectid = GETPOST('objectid', 'int'); $linkObject->label = GETPOST('label', 'alpha'); $res = $linkObject->create($user); $langs->load('link'); if ($res > 0) { setEventMessages($langs->trans("LinkComplete"), null, 'mesgs'); } else { setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors'); } } else { $langs->load("errors"); setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors'); } return $res; } /** * Remove an uploaded file (for example after submitting a new file a mail form). * All information used are in db, conf, langs, user and _FILES. * * @param int $filenb File nb to delete * @param int $donotupdatesession -1 or 1 = Do not update _SESSION variable * @param int $donotdeletefile 1=Do not delete physically file * @param string $trackid Track id (used to prefix name of session vars to avoid conflict) * @return void * @see dol_add_file_process() */ function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '') { global $db, $user, $conf, $langs, $_FILES; $keytodelete = $filenb; $keytodelete--; $listofpaths = array(); $listofnames = array(); $listofmimes = array(); $keytoavoidconflict = empty($trackid) ? '' : '-'.$trackid; if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) { $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]); } if (!empty($_SESSION["listofnames".$keytoavoidconflict])) { $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]); } if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) { $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]); } if ($keytodelete >= 0) { $pathtodelete = $listofpaths[$keytodelete]; $filetodelete = $listofnames[$keytodelete]; if (empty($donotdeletefile)) { $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file } else { $result = 0; } if ($result >= 0) { if (empty($donotdeletefile)) { $langs->load("other"); setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs'); } if (empty($donotupdatesession)) { include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; $formmail = new FormMail($db); $formmail->trackid = $trackid; $formmail->remove_attached_files($keytodelete); } } } } /** * Add a file into database index. * Called by dol_add_file_process when uploading a file and on other cases. * See also commonGenerateDocument that also add/update database index when a file is generated. * * @param string $dir Directory name (full real path without ending /) * @param string $file File name (May end with '.noexe') * @param string $fullpathorig Full path of origin for file (can be '') * @param string $mode How file was created ('uploaded', 'generated', ...) * @param int $setsharekey Set also the share key * @param Object $object Object used to set 'src_object_*' fields * @return int <0 if KO, 0 if nothing done, >0 if OK */ function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null) { global $db, $user, $conf; $result = 0; $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir); if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) { // If not a tmp dir $filename = basename(preg_replace('/\.noexe$/', '', $file)); $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; $ecmfile = new EcmFiles($db); $ecmfile->filepath = $rel_dir; $ecmfile->filename = $filename; $ecmfile->label = md5_file(dol_osencode($dir.'/'.$file)); // MD5 of file content $ecmfile->fullpath_orig = $fullpathorig; $ecmfile->gen_or_uploaded = $mode; $ecmfile->description = ''; // indexed content $ecmfile->keywords = ''; // keyword content if (is_object($object) && $object->id > 0) { $ecmfile->src_object_id = $object->id; if (isset($object->table_element)) { $ecmfile->src_object_type = $object->table_element; } else { dol_syslog('Error: object ' . get_class($object) . ' has no table_element attribute.'); return -1; } if (isset($object->src_object_description)) $ecmfile->description = $object->src_object_description; if (isset($object->src_object_keywords)) $ecmfile->keywords = $object->src_object_keywords; } if (!empty($conf->global->MAIN_FORCE_SHARING_ON_ANY_UPLOADED_FILE)) { $setsharekey = 1; } if ($setsharekey) { require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; $ecmfile->share = getRandomPassword(true); } $result = $ecmfile->create($user); if ($result < 0) { dol_syslog($ecmfile->error); } } return $result; } /** * Delete files into database index using search criterias. * * @param string $dir Directory name (full real path without ending /) * @param string $file File name * @param string $mode How file was created ('uploaded', 'generated', ...) * @return int <0 if KO, 0 if nothing done, >0 if OK */ function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded') { global $conf, $db, $user; $error = 0; if (empty($dir)) { dol_syslog("deleteFilesIntoDatabaseIndex: dir parameter can't be empty", LOG_ERR); return -1; } $db->begin(); $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir); $filename = basename($file); $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); if (!$error) { $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'ecm_files'; $sql .= ' WHERE entity = '.$conf->entity; $sql .= " AND filepath = '".$db->escape($rel_dir)."'"; if ($file) { $sql .= " AND filename = '".$db->escape($file)."'"; } if ($mode) { $sql .= " AND gen_or_uploaded = '".$db->escape($mode)."'"; } $resql = $db->query($sql); if (!$resql) { $error++; dol_syslog(__METHOD__.' '.$db->lasterror(), LOG_ERR); } } // Commit or rollback if ($error) { $db->rollback(); return -1 * $error; } else { $db->commit(); return 1; } } /** * Convert an image file or a PDF into another image format. * This need Imagick php extension. You can use dol_imageResizeOrCrop() for a function that need GD. * * @param string $fileinput Input file name * @param string $ext Format of target file (It is also extension added to file if fileoutput is not provided). * @param string $fileoutput Output filename * @param string $page Page number if we convert a PDF into png * @return int <0 if KO, 0=Nothing done, >0 if OK * @see dol_imageResizeOrCrop() */ function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '') { global $langs; if (class_exists('Imagick')) { $image = new Imagick(); try { $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : ''); //var_dump($filetoconvert); $ret = $image->readImage($filetoconvert); } catch (Exception $e) { $ext = pathinfo($fileinput, PATHINFO_EXTENSION); dol_syslog("Failed to read image using Imagick (Try to install package 'apt-get install php-imagick ghostscript' and check there is no policy to disable ".$ext." convertion in /etc/ImageMagick*/policy.xml): ".$e->getMessage(), LOG_WARNING); return 0; } if ($ret) { $ret = $image->setImageFormat($ext); if ($ret) { if (empty($fileoutput)) { $fileoutput = $fileinput.".".$ext; } $count = $image->getNumberImages(); if (!dol_is_file($fileoutput) || is_writeable($fileoutput)) { try { $ret = $image->writeImages($fileoutput, true); } catch (Exception $e) { dol_syslog($e->getMessage(), LOG_WARNING); } } else { dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR); } if ($ret) { return $count; } else { return -3; } } else { return -2; } } else { return -1; } } else { return 0; } } /** * Compress a file. * An error string may be returned into parameters. * * @param string $inputfile Source file name * @param string $outputfile Target file name * @param string $mode 'gz' or 'bz' or 'zip' * @param string $errorstring Error string * @return int <0 if KO, >0 if OK */ function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring = null) { global $conf; $foundhandler = 0; try { dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile); $data = implode("", file(dol_osencode($inputfile))); if ($mode == 'gz') { $foundhandler = 1; $compressdata = gzencode($data, 9); } elseif ($mode == 'bz') { $foundhandler = 1; $compressdata = bzcompress($data, 9); } elseif ($mode == 'zstd') { $foundhandler = 1; $compressdata = zstd_compress($data, 9); } elseif ($mode == 'zip') { if (class_exists('ZipArchive') && !empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) { $foundhandler = 1; $rootPath = realpath($inputfile); dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath); $zip = new ZipArchive; if ($zip->open($outputfile, ZipArchive::CREATE) !== true) { $errorstring = "dol_compress_file failure - Failed to open file ".$outputfile."\n"; dol_syslog($errorstring, LOG_ERR); global $errormsg; $errormsg = $errorstring; return -6; } // Create recursive directory iterator /** @var SplFileInfo[] $files */ $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY ); foreach ($files as $name => $file) { // Skip directories (they would be added automatically) if (!$file->isDir()) { // Get real and relative path for current file $filePath = $file->getPath(); // the full path with filename using the $inputdir root. $fileName = $file->getFilename(); $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory. //$relativePath = substr($fileFullRealPath, strlen($rootPath) + 1); $relativePath = substr(($filePath ? $filePath.'/' : '').$fileName, strlen($rootPath) + 1); // Add current file to archive $zip->addFile($fileFullRealPath, $relativePath); } } // Zip archive will be created only after closing object $zip->close(); dol_syslog("dol_compress_file success - ".count($zip->numFiles)." files"); return 1; } if (defined('ODTPHP_PATHTOPCLZIP')) { $foundhandler = 1; include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php'; $archive = new PclZip($outputfile); $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile)); if ($result === 0) { global $errormsg; $errormsg = $archive->errorInfo(true); if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) { $errorstring = "PCLZIP_ERR_WRITE_OPEN_FAIL"; dol_syslog("dol_compress_file error - archive->errorCode() = PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR); return -4; } $errorstring = "dol_compress_file error archive->errorCode = ".$archive->errorCode()." errormsg=".$errormsg; dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR); return -3; } else { dol_syslog("dol_compress_file success - ".count($result)." files"); return 1; } } } if ($foundhandler) { $fp = fopen($outputfile, "w"); fwrite($fp, $compressdata); fclose($fp); return 1; } else { $errorstring = "Try to zip with format ".$mode." with no handler for this format"; dol_syslog($errorstring, LOG_ERR); global $errormsg; $errormsg = $errorstring; return -2; } } catch (Exception $e) { global $langs, $errormsg; $langs->load("errors"); $errormsg = $langs->trans("ErrorFailedToWriteInDir"); $errorstring = "Failed to open file ".$outputfile; dol_syslog($errorstring, LOG_ERR); return -1; } } /** * Uncompress a file * * @param string $inputfile File to uncompress * @param string $outputdir Target dir name * @return array array('error'=>'Error code') or array() if no error */ function dol_uncompress($inputfile, $outputdir) { global $conf, $langs; if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS)) { dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir); include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php'; $archive = new PclZip($inputfile); // Extract into outputdir, but only files that match the regex '/^((?!\.\.).)*$/' that means "does not include .." $result = $archive->extract(PCLZIP_OPT_PATH, $outputdir, PCLZIP_OPT_BY_PREG, '/^((?!\.\.).)*$/'); if (!is_array($result) && $result <= 0) { return array('error'=>$archive->errorInfo(true)); } else { $ok = 1; $errmsg = ''; // Loop on each file to check result for unzipping file foreach ($result as $key => $val) { if ($val['status'] == 'path_creation_fail') { $langs->load("errors"); $ok = 0; $errmsg = $langs->trans("ErrorFailToCreateDir", $val['filename']); break; } } if ($ok) { return array(); } else { return array('error'=>$errmsg); } } } if (class_exists('ZipArchive')) { // Must install php-zip to have it dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir); $zip = new ZipArchive; $res = $zip->open($inputfile); if ($res === true) { //$zip->extractTo($outputdir.'/'); // We must extract one file at time so we can check that file name does not contains '..' to avoid transversal path of zip built for example using // python3 path_traversal_archiver.py <Created_file_name> test.zip -l 10 -p tmp/ // with -l is the range of dot to go back in path. // and path_traversal_archiver.py found at https://github.com/Alamot/code-snippets/blob/master/path_traversal/path_traversal_archiver.py for ($i = 0; $i < $zip->numFiles; $i++) { if (preg_match('/\.\./', $zip->getNameIndex($i))) { dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING); continue; // Discard the file } $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i))); } $zip->close(); return array(); } else { return array('error'=>'ErrUnzipFails'); } } return array('error'=>'ErrNoZipEngine'); } /** * Compress a directory and subdirectories into a package file. * * @param string $inputdir Source dir name * @param string $outputfile Target file name (output directory must exists and be writable) * @param string $mode 'zip' * @param string $excludefiles A regex pattern. For example: '/\.log$|\/temp\//' * @param string $rootdirinzip Add a root dir level in zip file * @return int <0 if KO, >0 if OK */ function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '', $rootdirinzip = '') { $foundhandler = 0; dol_syslog("Try to zip dir ".$inputdir." into ".$outputfile." mode=".$mode); if (!dol_is_dir(dirname($outputfile)) || !is_writable(dirname($outputfile))) { global $langs, $errormsg; $langs->load("errors"); $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile); return -3; } try { if ($mode == 'gz') { $foundhandler = 0; } elseif ($mode == 'bz') { $foundhandler = 0; } elseif ($mode == 'zip') { /*if (defined('ODTPHP_PATHTOPCLZIP')) { $foundhandler=0; // TODO implement this include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php'; $archive = new PclZip($outputfile); $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile)); //$archive->add($inputfile); return 1; } else*/ //if (class_exists('ZipArchive') && ! empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) if (class_exists('ZipArchive')) { $foundhandler = 1; // Initialize archive object $zip = new ZipArchive(); $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE); if (!$result) { global $langs, $errormsg; $langs->load("errors"); $errormsg = $langs->trans("ErrorFailedToWriteInFile", $outputfile); return -4; } // Create recursive directory iterator // This does not return symbolic links /** @var SplFileInfo[] $files */ $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($inputdir), RecursiveIteratorIterator::LEAVES_ONLY ); //var_dump($inputdir); foreach ($files as $name => $file) { // Skip directories (they would be added automatically) if (!$file->isDir()) { // Get real and relative path for current file $filePath = $file->getPath(); // the full path with filename using the $inputdir root. $fileName = $file->getFilename(); $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory. //$relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($fileFullRealPath, strlen($inputdir) + 1); $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr(($filePath ? $filePath.'/' : '').$fileName, strlen($inputdir) + 1); //var_dump($filePath);var_dump($fileFullRealPath);var_dump($relativePath); if (empty($excludefiles) || !preg_match($excludefiles, $fileFullRealPath)) { // Add current file to archive $zip->addFile($fileFullRealPath, $relativePath); } } } // Zip archive will be created only after closing object $zip->close(); return 1; } } if (!$foundhandler) { dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR); return -2; } else { return 0; } } catch (Exception $e) { global $langs, $errormsg; $langs->load("errors"); dol_syslog("Failed to open file ".$outputfile, LOG_ERR); dol_syslog($e->getMessage(), LOG_ERR); $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputfile); return -1; } } /** * Return file(s) into a directory (by default most recent) * * @param string $dir Directory to scan * @param string $regexfilter Regex filter to restrict list. This regex value must be escaped for '/', since this char is used for preg_match function * @param array $excludefilter Array of Regex for exclude filter (example: array('(\.meta|_preview.*\.png)$','^\.')). This regex value must be escaped for '/', since this char is used for preg_match function * @param int $nohook Disable all hooks * @param int $mode 0=Return array minimum keys loaded (faster), 1=Force all keys like date and size to be loaded (slower), 2=Force load of date only, 3=Force load of size only * @return string Full path to most recent file */ function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$', '^\.'), $nohook = false, $mode = '') { $tmparray = dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook); return $tmparray[0]; } /** * Security check when accessing to a document (used by document.php, viewimage.php and webservices to get documents). * TODO Replace code that set $accessallowed by a call to restrictedArea() * * @param string $modulepart Module of document ('module', 'module_user_temp', 'module_user' or 'module_temp'). Exemple: 'medias', 'invoice', 'logs', 'tax-vat', ... * @param string $original_file Relative path with filename, relative to modulepart. * @param string $entity Restrict onto entity (0=no restriction) * @param User $fuser User object (forced) * @param string $refname Ref of object to check permission for external users (autodetect if not provided) or for hierarchy * @param string $mode Check permission for 'read' or 'write' * @return mixed Array with access information : 'accessallowed' & 'sqlprotectagainstexternals' & 'original_file' (as a full path name) * @see restrictedArea() */ function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = '', $refname = '', $mode = 'read') { global $conf, $db, $user, $hookmanager; global $dolibarr_main_data_root, $dolibarr_main_document_root_alt; global $object; if (!is_object($fuser)) { $fuser = $user; } if (empty($modulepart)) { return 'ErrorBadParameter'; } if (empty($entity)) { if (empty($conf->multicompany->enabled)) { $entity = 1; } else { $entity = 0; } } // Fix modulepart for backward compatibility if ($modulepart == 'users') { $modulepart = 'user'; } if ($modulepart == 'tva') { $modulepart = 'tax-vat'; } //print 'dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity; dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity); // We define $accessallowed and $sqlprotectagainstexternals $accessallowed = 0; $sqlprotectagainstexternals = ''; $ret = array(); // Find the subdirectory name as the reference. For example original_file='10/myfile.pdf' -> refname='10' if (empty($refname)) { $refname = basename(dirname($original_file)."/"); if ($refname == 'thumbs') { // If we get the thumbns directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10' $refname = basename(dirname(dirname($original_file))."/"); } } // Define possible keys to use for permission check $lire = 'lire'; $read = 'read'; $download = 'download'; if ($mode == 'write') { $lire = 'creer'; $read = 'write'; $download = 'upload'; } // Wrapping for miscellaneous medias files if ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) { if (empty($entity) || empty($conf->medias->multidir_output[$entity])) { return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); } $accessallowed = 1; $original_file = $conf->medias->multidir_output[$entity].'/'.$original_file; } elseif ($modulepart == 'logs' && !empty($dolibarr_main_data_root)) { // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log $accessallowed = ($user->admin && basename($original_file) == $original_file && preg_match('/^dolibarr.*\.log$/', basename($original_file))); $original_file = $dolibarr_main_data_root.'/'.$original_file; } elseif ($modulepart == 'doctemplates' && !empty($dolibarr_main_data_root)) { // Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log $accessallowed = $user->admin; $original_file = $dolibarr_main_data_root.'/doctemplates/'.$original_file; } elseif ($modulepart == 'doctemplateswebsite' && !empty($dolibarr_main_data_root)) { // Wrapping for *.zip files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip $accessallowed = ($fuser->rights->website->write && preg_match('/\.jpg$/i', basename($original_file))); $original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file; } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) { // Wrapping for *.zip files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip // Dir for custom dirs $tmp = explode(',', $dolibarr_main_document_root_alt); $dirins = $tmp[0]; $accessallowed = ($user->admin && preg_match('/^module_.*\.zip$/', basename($original_file))); $original_file = $dirins.'/'.$original_file; } elseif ($modulepart == 'mycompany' && !empty($conf->mycompany->dir_output)) { // Wrapping for some images $accessallowed = 1; $original_file = $conf->mycompany->dir_output.'/'.$original_file; } elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output)) { // Wrapping for users photos $accessallowed = 1; $original_file = $conf->user->dir_output.'/'.$original_file; } elseif (($modulepart == 'companylogo') && !empty($conf->mycompany->dir_output)) { // Wrapping for users logos $accessallowed = 1; $original_file = $conf->mycompany->dir_output.'/logos/'.$original_file; } elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output)) { // Wrapping for members photos $accessallowed = 1; $original_file = $conf->adherent->dir_output.'/'.$original_file; } elseif ($modulepart == 'apercufacture' && !empty($conf->facture->multidir_output[$entity])) { // Wrapping pour les apercu factures if ($fuser->rights->facture->{$lire}) { $accessallowed = 1; } $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file; } elseif ($modulepart == 'apercupropal' && !empty($conf->propal->multidir_output[$entity])) { // Wrapping pour les apercu propal if ($fuser->rights->propale->{$lire}) { $accessallowed = 1; } $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file; } elseif ($modulepart == 'apercucommande' && !empty($conf->commande->multidir_output[$entity])) { // Wrapping pour les apercu commande if ($fuser->rights->commande->{$lire}) { $accessallowed = 1; } $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file; } elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output)) { // Wrapping pour les apercu intervention if ($fuser->rights->ficheinter->{$lire}) { $accessallowed = 1; } $original_file = $conf->ficheinter->dir_output.'/'.$original_file; } elseif (($modulepart == 'apercucontract') && !empty($conf->contrat->multidir_output[$entity])) { // Wrapping pour les apercu contrat if ($fuser->rights->contrat->{$lire}) { $accessallowed = 1; } $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file; } elseif (($modulepart == 'apercusupplier_proposal' || $modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output)) { // Wrapping pour les apercu supplier proposal if ($fuser->rights->supplier_proposal->{$lire}) { $accessallowed = 1; } $original_file = $conf->supplier_proposal->dir_output.'/'.$original_file; } elseif (($modulepart == 'apercusupplier_order' || $modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output)) { // Wrapping pour les apercu supplier order if ($fuser->rights->fournisseur->commande->{$lire}) { $accessallowed = 1; } $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file; } elseif (($modulepart == 'apercusupplier_invoice' || $modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output)) { // Wrapping pour les apercu supplier invoice if ($fuser->rights->fournisseur->facture->{$lire}) { $accessallowed = 1; } $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file; } elseif (($modulepart == 'holiday') && !empty($conf->holiday->dir_output)) { if ($fuser->rights->holiday->{$read} || !empty($fuser->rights->holiday->readall) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; // If we known $id of holiday, call checkUserAccessToObject to check permission on properties and hierarchy of leave request if ($refname && empty($fuser->rights->holiday->readall) && !preg_match('/^specimen/i', $original_file)) { include_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php'; $tmpholiday = new Holiday($db); $tmpholiday->fetch('', $refname); $accessallowed = checkUserAccessToObject($user, array('holiday'), $tmpholiday, 'holiday', '', '', 'rowid', ''); } } $original_file = $conf->holiday->dir_output.'/'.$original_file; } elseif (($modulepart == 'expensereport') && !empty($conf->expensereport->dir_output)) { if ($fuser->rights->expensereport->{$lire} || !empty($fuser->rights->expensereport->readall) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; // If we known $id of expensereport, call checkUserAccessToObject to check permission on properties and hierarchy of expense report if ($refname && empty($fuser->rights->expensereport->readall) && !preg_match('/^specimen/i', $original_file)) { include_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php'; $tmpexpensereport = new ExpenseReport($db); $tmpexpensereport->fetch('', $refname); $accessallowed = checkUserAccessToObject($user, array('expensereport'), $tmpexpensereport, 'expensereport', '', '', 'rowid', ''); } } $original_file = $conf->expensereport->dir_output.'/'.$original_file; } elseif (($modulepart == 'apercuexpensereport') && !empty($conf->expensereport->dir_output)) { // Wrapping pour les apercu supplier invoice if ($fuser->rights->expensereport->{$lire}) { $accessallowed = 1; } $original_file = $conf->expensereport->dir_output.'/'.$original_file; } elseif ($modulepart == 'propalstats' && !empty($conf->propal->multidir_temp[$entity])) { // Wrapping pour les images des stats propales if ($fuser->rights->propale->{$lire}) { $accessallowed = 1; } $original_file = $conf->propal->multidir_temp[$entity].'/'.$original_file; } elseif ($modulepart == 'orderstats' && !empty($conf->commande->dir_temp)) { // Wrapping pour les images des stats commandes if ($fuser->rights->commande->{$lire}) { $accessallowed = 1; } $original_file = $conf->commande->dir_temp.'/'.$original_file; } elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output)) { if ($fuser->rights->fournisseur->commande->{$lire}) { $accessallowed = 1; } $original_file = $conf->fournisseur->commande->dir_temp.'/'.$original_file; } elseif ($modulepart == 'billstats' && !empty($conf->facture->dir_temp)) { // Wrapping pour les images des stats factures if ($fuser->rights->facture->{$lire}) { $accessallowed = 1; } $original_file = $conf->facture->dir_temp.'/'.$original_file; } elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output)) { if ($fuser->rights->fournisseur->facture->{$lire}) { $accessallowed = 1; } $original_file = $conf->fournisseur->facture->dir_temp.'/'.$original_file; } elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp)) { // Wrapping pour les images des stats expeditions if ($fuser->rights->expedition->{$lire}) { $accessallowed = 1; } $original_file = $conf->expedition->dir_temp.'/'.$original_file; } elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp)) { // Wrapping pour les images des stats expeditions if ($fuser->rights->deplacement->{$lire}) { $accessallowed = 1; } $original_file = $conf->deplacement->dir_temp.'/'.$original_file; } elseif ($modulepart == 'memberstats' && !empty($conf->adherent->dir_temp)) { // Wrapping pour les images des stats expeditions if ($fuser->rights->adherent->{$lire}) { $accessallowed = 1; } $original_file = $conf->adherent->dir_temp.'/'.$original_file; } elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) { // Wrapping pour les images des stats produits if ($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) { $accessallowed = 1; } $original_file = (!empty($conf->product->multidir_temp[$entity]) ? $conf->product->multidir_temp[$entity] : $conf->service->multidir_temp[$entity]).'/'.$original_file; } elseif (in_array($modulepart, array('tax', 'tax-vat', 'tva')) && !empty($conf->tax->dir_output)) { // Wrapping for taxes if ($fuser->rights->tax->charges->{$lire}) { $accessallowed = 1; } $modulepartsuffix = str_replace('tax-', '', $modulepart); $original_file = $conf->tax->dir_output.'/'.($modulepartsuffix != 'tax' ? $modulepartsuffix.'/' : '').$original_file; } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) { // Wrapping for events if ($fuser->rights->agenda->myactions->{$read}) { $accessallowed = 1; // If we known $id of project, call checkUserAccessToObject to check permission on the given agenda event on properties and assigned users if ($refname && !preg_match('/^specimen/i', $original_file)) { include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; $tmpobject = new ActionComm($db); $tmpobject->fetch((int) $refname); $accessallowed = checkUserAccessToObject($user, array('agenda'), $tmpobject->id, 'actioncomm&societe', 'myactions|allactions', 'fk_soc', 'id', ''); if ($user->socid && $tmpobject->socid) { $accessallowed = checkUserAccessToObject($user, array('societe'), $tmpobject->socid); } } } $original_file = $conf->agenda->dir_output.'/'.$original_file; } elseif ($modulepart == 'category' && !empty($conf->categorie->multidir_output[$entity])) { // Wrapping for categories if (empty($entity) || empty($conf->categorie->multidir_output[$entity])) { return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); } if ($fuser->rights->categorie->{$lire} || $fuser->rights->takepos->run) { $accessallowed = 1; } $original_file = $conf->categorie->multidir_output[$entity].'/'.$original_file; } elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) { // Wrapping pour les prelevements if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->prelevement->dir_output.'/'.$original_file; } elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp)) { // Wrapping pour les graph energie $accessallowed = 1; $original_file = $conf->stock->dir_temp.'/'.$original_file; } elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp)) { // Wrapping pour les graph fournisseurs $accessallowed = 1; $original_file = $conf->fournisseur->dir_temp.'/'.$original_file; } elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp)) { // Wrapping pour les graph des produits $accessallowed = 1; $original_file = $conf->product->multidir_temp[$entity].'/'.$original_file; } elseif ($modulepart == 'barcode') { // Wrapping pour les code barre $accessallowed = 1; // If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk. //$original_file=$conf->barcode->dir_temp.'/'.$original_file; $original_file = ''; } elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp)) { // Wrapping pour les icones de background des mailings $accessallowed = 1; $original_file = $conf->mailing->dir_temp.'/'.$original_file; } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) { // Wrapping pour le scanner $accessallowed = 1; $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file; } elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output)) { // Wrapping pour les images fckeditor $accessallowed = 1; $original_file = $conf->fckeditor->dir_output.'/'.$original_file; } elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) { // Wrapping for users $canreaduser = (!empty($fuser->admin) || $fuser->rights->user->user->{$lire}); if ($fuser->id == (int) $refname) { $canreaduser = 1; } // A user can always read its own card if ($canreaduser || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->user->dir_output.'/'.$original_file; } elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->multidir_output[$entity])) { // Wrapping for third parties if (empty($entity) || empty($conf->societe->multidir_output[$entity])) { return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); } if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->societe->multidir_output[$entity].'/'.$original_file; $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe').")"; } elseif ($modulepart == 'contact' && !empty($conf->societe->multidir_output[$entity])) { // Wrapping for contact if (empty($entity) || empty($conf->societe->multidir_output[$entity])) { return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); } if ($fuser->rights->societe->{$lire}) { $accessallowed = 1; } $original_file = $conf->societe->multidir_output[$entity].'/contact/'.$original_file; } elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->multidir_output[$entity])) { // Wrapping for invoices if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->facture->multidir_output[$entity].'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('invoice').")"; } elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) { // Wrapping for mass actions if ($fuser->rights->propal->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_orders') { if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->commande->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_sendings') { if ($fuser->rights->expedition->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->expedition->dir_output.'/sending/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_invoices') { if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->facture->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_expensereport') { if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_interventions') { if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) { if ($fuser->rights->supplier_proposal->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_supplier_order') { if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_supplier_invoice') { if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) { if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->contrat->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) { // Wrapping for interventions if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->ficheinter->dir_output.'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) { // Wrapping pour les deplacements et notes de frais if ($fuser->rights->deplacement->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->deplacement->dir_output.'/'.$original_file; //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } elseif (($modulepart == 'propal' || $modulepart == 'propale') && !empty($conf->propal->multidir_output[$entity])) { // Wrapping pour les propales if ($fuser->rights->propale->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->propal->multidir_output[$entity].'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('propal').")"; } elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->multidir_output[$entity])) { // Wrapping pour les commandes if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->commande->multidir_output[$entity].'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('order').")"; } elseif ($modulepart == 'project' && !empty($conf->projet->dir_output)) { // Wrapping pour les projets if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project if ($refname && !preg_match('/^specimen/i', $original_file)) { include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; $tmpproject = new Project($db); $tmpproject->fetch('', $refname); $accessallowed = checkUserAccessToObject($user, array('projet'), $tmpproject->id, 'projet&project', '', '', 'rowid', ''); } } $original_file = $conf->projet->dir_output.'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")"; } elseif ($modulepart == 'project_task' && !empty($conf->projet->dir_output)) { if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; // If we known $id of project, call checkUserAccessToObject to check permission on properties and contact of project if ($refname && !preg_match('/^specimen/i', $original_file)) { include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; $tmptask = new Task($db); $tmptask->fetch('', $refname); $accessallowed = checkUserAccessToObject($user, array('projet_task'), $tmptask->id, 'projet_task&project', '', '', 'rowid', ''); } } $original_file = $conf->projet->dir_output.'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")"; } elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) { // Wrapping pour les commandes fournisseurs if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->fournisseur->commande->dir_output.'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) { // Wrapping pour les factures fournisseurs if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->fournisseur->facture->dir_output.'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } elseif ($modulepart == 'supplier_payment') { // Wrapping pour les rapport de paiements if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->fournisseur->payment->dir_output.'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } elseif ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) { // Wrapping pour les rapport de paiements if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } if ($fuser->societe_id > 0) { $original_file = $conf->facture->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file; } else { $original_file = $conf->facture->dir_output.'/payments/'.$original_file; } } elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) { // Wrapping for accounting exports if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->accounting->dir_output.'/'.$original_file; } elseif (($modulepart == 'expedition' || $modulepart == 'shipment') && !empty($conf->expedition->dir_output)) { // Wrapping pour les expedition if ($fuser->rights->expedition->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->expedition->dir_output."/".(strpos('sending/', $original_file) === 0 ? '' : 'sending/').$original_file; //$original_file = $conf->expedition->dir_output."/".$original_file; } elseif (($modulepart == 'livraison' || $modulepart == 'delivery') && !empty($conf->expedition->dir_output)) { // Delivery Note Wrapping if ($fuser->rights->expedition->delivery->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->expedition->dir_output."/".(strpos('receipt/', $original_file) === 0 ? '' : 'receipt/').$original_file; } elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) { // Wrapping pour les actions if ($fuser->rights->agenda->myactions->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->agenda->dir_output.'/'.$original_file; } elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) { // Wrapping pour les actions if ($fuser->rights->agenda->allactions->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->agenda->dir_temp."/".$original_file; } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') { // Wrapping pour les produits et services if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) { return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); } if (($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } if (!empty($conf->product->enabled)) { $original_file = $conf->product->multidir_output[$entity].'/'.$original_file; } elseif (!empty($conf->service->enabled)) { $original_file = $conf->service->multidir_output[$entity].'/'.$original_file; } } elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') { // Wrapping pour les lots produits if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) { return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); } if (($fuser->rights->produit->{$lire} ) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } if (!empty($conf->productbatch->enabled)) { $original_file = $conf->productbatch->multidir_output[$entity].'/'.$original_file; } } elseif ($modulepart == 'movement' || $modulepart == 'mouvement') { // Wrapping for stock movements if (empty($entity) || empty($conf->stock->multidir_output[$entity])) { return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); } if (($fuser->rights->stock->{$lire} || $fuser->rights->stock->movement->{$lire} || $fuser->rights->stock->mouvement->{$lire}) || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } if (!empty($conf->stock->enabled)) { $original_file = $conf->stock->multidir_output[$entity].'/movement/'.$original_file; } } elseif ($modulepart == 'contract' && !empty($conf->contrat->multidir_output[$entity])) { // Wrapping pour les contrats if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->contrat->multidir_output[$entity].'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract').")"; } elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) { // Wrapping pour les dons if ($fuser->rights->don->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->don->dir_output.'/'.$original_file; } elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) { // Wrapping pour les dons if ($fuser->rights->resource->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->resource->dir_output.'/'.$original_file; } elseif ($modulepart == 'remisecheque' && !empty($conf->bank->dir_output)) { // Wrapping pour les remises de cheques if ($fuser->rights->banque->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->bank->dir_output.'/checkdeposits/'.$original_file; // original_file should contains relative path so include the get_exdir result } elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) { // Wrapping for bank if ($fuser->rights->banque->{$lire}) { $accessallowed = 1; } $original_file = $conf->bank->dir_output.'/'.$original_file; } elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) { // Wrapping for export module // Note that a test may not be required because we force the dir of download on the directory of the user that export $accessallowed = $user->rights->export->lire; $original_file = $conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file; } elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) { // Wrapping for import module $accessallowed = $user->rights->import->run; $original_file = $conf->import->dir_temp.'/'.$original_file; } elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) { // Wrapping for wysiwyg editor $accessallowed = 1; $original_file = $conf->fckeditor->dir_output.'/'.$original_file; } elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) { // Wrapping for backups if ($fuser->admin) { $accessallowed = 1; } $original_file = $conf->admin->dir_output.'/'.$original_file; } elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) { // Wrapping for upload file test if ($fuser->admin) { $accessallowed = 1; } $original_file = $conf->admin->dir_temp.'/'.$original_file; } elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) { // Wrapping pour BitTorrent $accessallowed = 1; $dir = 'files'; if (dol_mimetype($original_file) == 'application/x-bittorrent') { $dir = 'torrents'; } $original_file = $conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file; } elseif ($modulepart == 'member' && !empty($conf->adherent->dir_output)) { // Wrapping pour Foundation module if ($fuser->rights->adherent->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->adherent->dir_output.'/'.$original_file; } elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) { // Wrapping for Scanner $accessallowed = 1; $original_file = $conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file; // If modulepart=module_user_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser // If modulepart=module_temp Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp // If modulepart=module_user Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart // If modulepart=module-abc Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart } else { // GENERIC Wrapping //var_dump($modulepart); //var_dump($original_file); if (preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; // If link to a file called specimen. Test must be done before changing $original_file int full path. } if ($fuser->admin) { $accessallowed = 1; // If user is admin } $tmpmodulepart = explode('-', $modulepart); if (!empty($tmpmodulepart[1])) { $modulepart = $tmpmodulepart[0]; $original_file = $tmpmodulepart[1].'/'.$original_file; } // Define $accessallowed $reg = array(); if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_temp)) { // modulepart not supported dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) { $accessallowed = 1; } $original_file = $conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file; } elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_temp)) { // modulepart not supported dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) { $accessallowed = 1; } $original_file = $conf->{$reg[1]}->dir_temp.'/'.$original_file; } elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_output)) { // modulepart not supported dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) { $accessallowed = 1; } $original_file = $conf->{$reg[1]}->dir_output.'/'.$fuser->id.'/'.$original_file; } elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_output)) { // modulepart not supported dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed = 1; } $original_file = $conf->{$reg[1]}->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } else { if (empty($conf->$modulepart->dir_output)) { // modulepart not supported dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.'). The module for this modulepart value may not be activated.'); exit; } // Check fuser->rights->modulepart->myobject->read and fuser->rights->modulepart->read $partsofdirinoriginalfile = explode('/', $original_file); if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use) $partofdirinoriginalfile = $partsofdirinoriginalfile[0]; if ($partofdirinoriginalfile && !empty($fuser->rights->$modulepart->$partofdirinoriginalfile) && ($fuser->rights->$modulepart->$partofdirinoriginalfile->{$lire} || $fuser->rights->$modulepart->$partofdirinoriginalfile->{$read})) { $accessallowed = 1; } } if (!empty($fuser->rights->$modulepart->{$lire}) || !empty($fuser->rights->$modulepart->{$read})) { $accessallowed = 1; } if (is_array($conf->$modulepart->multidir_output) && !empty($conf->$modulepart->multidir_output[$entity])) { $original_file = $conf->$modulepart->multidir_output[$entity].'/'.$original_file; } else { $original_file = $conf->$modulepart->dir_output.'/'.$original_file; } } $parameters = array( 'modulepart' => $modulepart, 'original_file' => $original_file, 'entity' => $entity, 'fuser' => $fuser, 'refname' => '', 'mode' => $mode ); $reshook = $hookmanager->executeHooks('checkSecureAccess', $parameters, $object); if ($reshook > 0) { if (!empty($hookmanager->resArray['original_file'])) { $original_file = $hookmanager->resArray['original_file']; } if (!empty($hookmanager->resArray['accessallowed'])) { $accessallowed = $hookmanager->resArray['accessallowed']; } if (!empty($hookmanager->resArray['sqlprotectagainstexternals'])) { $sqlprotectagainstexternals = $hookmanager->resArray['sqlprotectagainstexternals']; } } } $ret = array( 'accessallowed' => ($accessallowed ? 1 : 0), 'sqlprotectagainstexternals' => $sqlprotectagainstexternals, 'original_file' => $original_file ); return $ret; } /** * Store object in file. * * @param string $directory Directory of cache * @param string $filename Name of filecache * @param mixed $object Object to store in cachefile * @return void */ function dol_filecache($directory, $filename, $object) { if (!dol_is_dir($directory)) { dol_mkdir($directory); } $cachefile = $directory.$filename; file_put_contents($cachefile, serialize($object), LOCK_EX); @chmod($cachefile, 0644); } /** * Test if Refresh needed. * * @param string $directory Directory of cache * @param string $filename Name of filecache * @param int $cachetime Cachetime delay * @return boolean 0 no refresh 1 if refresh needed */ function dol_cache_refresh($directory, $filename, $cachetime) { $now = dol_now(); $cachefile = $directory.$filename; $refresh = !file_exists($cachefile) || ($now - $cachetime) > dol_filemtime($cachefile); return $refresh; } /** * Read object from cachefile. * * @param string $directory Directory of cache * @param string $filename Name of filecache * @return mixed Unserialise from file */ function dol_readcachefile($directory, $filename) { $cachefile = $directory.$filename; $object = unserialize(file_get_contents($cachefile)); return $object; } /** * Function to get list of updated or modified files. * $file_list is used as global variable * * @param array $file_list Array for response * @param SimpleXMLElement $dir SimpleXMLElement of files to test * @param string $path Path of files relative to $pathref. We start with ''. Used by recursive calls. * @param string $pathref Path ref (DOL_DOCUMENT_ROOT) * @param array $checksumconcat Array of checksum * @return array Array of filenames */ function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array()) { global $conffile; $exclude = 'install'; foreach ($dir->md5file as $file) { // $file is a simpleXMLElement $filename = $path.$file['name']; $file_list['insignature'][] = $filename; $expectedsize = (empty($file['size']) ? '' : $file['size']); $expectedmd5 = (string) $file; //if (preg_match('#'.$exclude.'#', $filename)) continue; if (!file_exists($pathref.'/'.$filename)) { $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize); } else { $md5_local = md5_file($pathref.'/'.$filename); 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 $checksumconcat[] = $expectedmd5; } else { if ($md5_local != $expectedmd5) { $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>$expectedmd5, 'expectedsize'=>$expectedsize, 'md5'=>(string) $md5_local); } $checksumconcat[] = $md5_local; } } } foreach ($dir->dir as $subdir) { // $subdir['name'] is '' or '/accountancy/admin' for example getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat); } return $file_list; }
Save