Merge branch 'develop' into fix_element_type_part_03

This commit is contained in:
Laurent Destailleur
2024-03-07 20:33:17 +01:00
committed by GitHub
202 changed files with 1545 additions and 1189 deletions

View File

@@ -2332,7 +2332,7 @@ function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab
if (empty($tabsname)) {
$tabsname = str_replace("@", "", $picto);
}
$out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem">';
$out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
$out .= '<div class="tab valignmiddle"><a href="#" class="tab moretab inline-block tabunactive valignmiddle"><span class="hideonsmartphone">'.$langs->trans("More").'</span>... ('.$nbintab.')</a></div>'; // Do not use "reposition" class in the "More".
$out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
$out .= $outmore;
@@ -6890,7 +6890,7 @@ function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournpric
if (($mysoc->country_code == $thirdpartytouse->country_code)
|| (in_array($mysoc->country_code, array('FR', 'MC')) && in_array($thirdpartytouse->country_code, array('FR', 'MC')))
|| (in_array($mysoc->country_code, array('MQ', 'GP')) && in_array($thirdpartytouse->country_code, array('MQ', 'GP')))
) {
) {
// If country of thirdparty to consider is ours
if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
$result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
@@ -8274,12 +8274,13 @@ function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
/**
* Return array of possible common substitutions. This includes several families like: 'system', 'mycompany', 'object', 'objectamount', 'date', 'user'
*
* @param Translate $outputlangs Output language
* @param int $onlykey 1=Do not calculate some heavy values of keys (performance enhancement when we need only the keys), 2=Values are trunc and html sanitized (to use for help tooltip)
* @param array $exclude Array of family keys we want to exclude. For example array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...)
* @param Object $object Object for keys on object
* @param array $include Array of family keys we want to include. For example array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...)
* @return array Array of substitutions
* @param Translate $outputlangs Output language
* @param int $onlykey 1=Do not calculate some heavy values of keys (performance enhancement when we need only the keys),
* 2=Values are trunc and html sanitized (to use for help tooltip)
* @param array|null $exclude Array of family keys we want to exclude. For example array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...)
* @param Object|null $object Object for keys on object
* @param array|null $include Array of family keys we want to include. For example array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...)
* @return array Array of substitutions
* @see setSubstitFromObject()
*/
function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
@@ -9756,13 +9757,13 @@ function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid =
}
/**
* Check if a variable with name $var start with $text.
* Check if a variable with name $var startx with $text.
* Can be used to forge dol_eval() conditions.
*
* @param $var string Variable
* @param $regextext string Text that must be a valid regex string
* @param $matchrule int 1=Test if start with, 0=Test if equal
* @return boolean|string True or False, text if bad use.
* @param string $var Variable
* @param string $regextext Text that must be a valid regex string
* @param int $matchrule 1=Test if start with, 0=Test if equal
* @return boolean|string True or False, text if bad usage.
*/
function isStringVarMatching($var, $regextext, $matchrule = 1)
{
@@ -9786,9 +9787,9 @@ function isStringVarMatching($var, $regextext, $matchrule = 1)
* Verify if condition in string is ok or not
*
* @param string $strToEvaluate String with condition to check
* @param string $onlysimplestring '0' (deprecated, used for computed property of extrafields)=Accept all chars,
* @param string $onlysimplestring '0' (deprecated, do not use it anymore)=Accept all chars,
* '1' (most common use)=Accept only simple string with char 'a-z0-9\s^$_+-.*>&|=!?():"\',/@';',
* '2' (rarely used)=Accept also '[]'
* '2' (used for example for the compute property of extrafields)=Accept also '[]'
* @return boolean True or False. Note: It returns also True if $strToEvaluate is ''. False if error
*/
function verifCond($strToEvaluate, $onlysimplestring = '1')
@@ -9798,7 +9799,7 @@ function verifCond($strToEvaluate, $onlysimplestring = '1')
if (isset($strToEvaluate) && $strToEvaluate !== '') {
//var_dump($strToEvaluate);
//$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
$rep = dol_eval($strToEvaluate, 1, 1, $onlysimplestring); // The dol_eval() must contains all the "global $xxx;" for all variables $xxx found into the string condition
$rep = (int) dol_eval($strToEvaluate, 1, 1, $onlysimplestring); // The dol_eval() must contains all the "global $xxx;" for all variables $xxx found into the string condition
$rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
//var_dump($rights);
}
@@ -9810,15 +9811,15 @@ function verifCond($strToEvaluate, $onlysimplestring = '1')
* This function is called by verifCond() or trans() and transnoentitiesnoconv().
*
* @param string $s String to evaluate
* @param int $returnvalue 0=No return (used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)).
* @param int $returnvalue 0=No return (deprecated, used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)).
* @param int $hideerrors 1=Hide errors
* @param string $onlysimplestring '0' (deprecated, used for computed property of extrafields)=Accept all chars,
* @param string $onlysimplestring '0' (deprecated, do not use it anymore)=Accept all chars,
* '1' (most common use)=Accept only simple string with char 'a-z0-9\s^$_+-.*>&|=!?():"\',/@';',
* '2' (rarely used)=Accept also '[]'
* '2' (used for example for the compute property of extrafields)=Accept also '[]'
* @return mixed Nothing or return result of eval
* @see verifCond()
*/
function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1')
{
// Only this global variables can be read by eval function and returned to caller
global $conf; // Read of const is done with getDolGlobalString() but we need $conf->currency for example
@@ -9837,10 +9838,14 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1'
try {
// Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
if ($onlysimplestring == '1') {
// We must accept: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
// We must accept: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
if ($onlysimplestring == '1' || $onlysimplestring == '2') {
// We must accept with 1: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
// We must accept with 1: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
// We must accept with 2: (($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"
$specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
if ($onlysimplestring == '2') {
$specialcharsallowed .= '[]';
}
if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
$specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
}
@@ -9866,50 +9871,15 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1'
//print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
if (strpos($scheck, '(') !== false) {
if ($returnvalue) {
return 'Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s;
return 'Bad string syntax to evaluate (mode '.$onlysimplestring.', found call of a function or method without using the direct name of the function): '.$s;
} else {
dol_syslog('Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s);
dol_syslog('Bad string syntax to evaluate (mode '.$onlysimplestring.', found call of a function or method without using the direct name of the function): '.$s);
return '';
}
}
// TODO
// We can exclude $ char that are not: $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
} elseif ($onlysimplestring == '2') {
// We must accept: (($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"
$specialcharsallowed = '^$_+-.*>&|=!?():"\',/@[]';
if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
$specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
}
if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
if ($returnvalue) {
return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
} else {
dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
return '';
}
}
$savescheck = '';
$scheck = $s;
while ($scheck && $savescheck != $scheck) {
$savescheck = $scheck;
$scheck = preg_replace('/->[a-zA-Z0-9_]+\(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
$scheck = preg_replace('/^\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
$scheck = preg_replace('/\s\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
$scheck = preg_replace('/^!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
$scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
$scheck = preg_replace('/(\^|\')\(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
}
//print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
if (strpos($scheck, '(') !== false) {
if ($returnvalue) {
return 'Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s;
} else {
dol_syslog('Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s);
return '';
}
}
// TODO
// We can exclude $ char that are not: $db, $leftmenu, $topmenu, $user, $langs, $object...,
// We can exclude $ char that are not:
// $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
}
if (is_array($s) || $s === 'Array') {
return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
@@ -9949,6 +9919,7 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1'
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
$forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
@@ -9978,11 +9949,26 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1'
//print $s."<br>\n";
if ($returnvalue) {
if ($hideerrors) {
return @eval('return '.$s.';');
ob_start(); // An evaluation has no reason to output data
$tmps = @eval('return '.$s.';');
$tmpo = ob_get_contents();
ob_clean(); // End of interception of data
if ($tmpo) {
print 'Bad string syntax to evaluate. Some data were output when it should not when evaluating: '.$s;
}
return $tmps;
} else {
return eval('return '.$s.';');
ob_start(); // An evaluation has no reason to output data
$tmps = eval('return '.$s.';');
$tmpo = ob_get_contents();
ob_clean(); // End of interception of data
if ($tmpo) {
print 'Bad string syntax to evaluate. Some data were output when it should not when evaluating: '.$s;
}
return $tmps;
}
} else {
dol_syslog('Do not use anymore dol_eval with param returnvalue=0', LOG_WARNING);
if ($hideerrors) {
@eval($s);
} else {
@@ -13096,7 +13082,7 @@ function getActionCommEcmList($object)
* @param Translate $langs Object langs
* @param DoliDB $db Object db
* @param mixed $filterobj Filter on object Adherent|Societe|Project|Product|CommandeFournisseur|Dolresource|Ticket|... to list events linked to an object
* @param Contact $objcon Filter on object contact to filter events on a contact
* @param Contact|null $objcon Filter on object contact to filter events on a contact
* @param int $noprint Return string but does not output it
* @param string $actioncode Filter on actioncode
* @param string $donetodo Filter on event 'done' or 'todo' or ''=nofilter (all).
@@ -13105,7 +13091,7 @@ function getActionCommEcmList($object)
* @param string $sortorder Sort order
* @return string|void Return html part or void if noprint is 1
*/
function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = null, $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
{
global $user, $conf;
global $form;
@@ -13120,6 +13106,8 @@ function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $n
}
$histo = array();
'@phan-var-force array<int,array{type:string,tododone:string,id:string,datestart:int|string,dateend:int|string,note:string,message:string,percent:string,userid:string,login:string,userfirstname:string,userlastname:string,userphoto:string,msg_from?:string,contact_id?:string,socpeopleassigned?:int[],lastname?:string,firstname?:string,fk_element?:int,elementtype?:string,acode:string,alabel?:string,libelle?:string,apicto?:string}> $histo';
$numaction = 0;
$now = dol_now();
@@ -13199,7 +13187,7 @@ function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $n
}
$sql .= " WHERE a.entity IN (".getEntity('agenda').")";
if ($force_filter_contact === false) {
if (!$force_filter_contact) {
if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
$sql .= " AND a.fk_soc = ".((int) $filterobj->id);
} elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
@@ -13327,6 +13315,7 @@ function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $n
while ($i < $imaxinloop) {
$obj = $db->fetch_object($resql);
'@phan-var-force array{apicto:string,contact_id:string,dp:string,dp2:string,firstname:string,label:string,message:string,msg_from:string,ref:string,type:string,user_lastname:string} $obj';
if ($obj->type == 'action') {
$contactaction = new ActionComm($db);
$contactaction->id = $obj->id;