Fix #yogosha15157

This commit is contained in:
Laurent Destailleur
2023-02-25 19:48:33 +01:00
parent ed9db6c9dd
commit cbb6ca071a
58 changed files with 321 additions and 345 deletions

View File

@@ -11522,17 +11522,35 @@ function jsonOrUnserialize($stringtodecode)
}
/**
* forgeSQLFromUniversalSearchCriteria
*
* @param string $filter String with universal search string
* @param string $error Error message
* @return string Return forged SQL string
*/
function forgeSQLFromUniversalSearchCriteria($filter, &$error = '')
{
$regexstring = '\(([a-zA-Z0-9_\.]+:[<>!=insotlke]+:[^\(\)]+)\)'; // Must be (aaa:bbb:...) with aaa is a field name (with alias or not) and bbb is one of this operator '=', '<', '>', '<=', '>=', '!=', 'in', 'notin', 'like', 'notlike', 'is', 'isnot'
if (!dolCheckFilters($filter, $error)) {
return '1 = 2'; // Bad balance of parenthesis, we force a SQL not found
}
// Test the filter syntax
$t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
$t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
// If the string result contains something else than '()', the syntax was wrong
if (preg_match('/[^\(\)]/', $t)) {
$error = 'Bad syntax of the search string, filter criteria is inhalited';
return '1 = 3'; // Bad syntax of the search string, we force a SQL not found
}
return " AND (".preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $filter).")";
}
/**
* Return if a $sqlfilters parameter is valid and will pass the preg_replace_callback() to replace Generic filter string with SQL filter string
* Example of usage:
* if ($sqlfilters) {
* $errormessage = '';
* if (dolCheckFilters($sqlfilters, $errormessage)) {
* $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
* $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $sqlfilters).")";
* }
* }
* Return if a $sqlfilters parameter has a valid balance of parenthesis
*
* @param string $sqlfilters sqlfilter string
* @param string $error Error message
@@ -11553,7 +11571,7 @@ function dolCheckFilters($sqlfilters, &$error = '')
$counter--;
}
if ($counter < 0) {
$error = "Bad sqlfilters=".$sqlfilters;
$error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
dol_syslog($error, LOG_WARNING);
return false;
}
@@ -11563,58 +11581,92 @@ function dolCheckFilters($sqlfilters, &$error = '')
}
/**
* Function to forge a SQL criteria from a Generic filter string.
* Example of usage:
* if ($sqlfilters) {
* $errormessage = '';
* if (dolCheckFilters($sqlfilters, $errormessage)) {
* $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
* $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $sqlfilters).")";
* }
* }
* Function to forge a SQL criteria from a Dolibarr filter syntax string.
* This method is called by forgeSQLFromUniversalSearchCriteria()
*
* @param array $matches Array of found string by regex search.
* Example: "t.ref:like:'SO-%'" or "t.date_creation:<:'20160101'" or "t.date_creation:<:'2016-01-01 12:30:00'" or "t.nature:is:NULL"
* @return string Forged criteria. Example: "t.field like 'abc%'"
* @param array $matches Array of found string by regex search. Example: "t.ref:like:'SO-%'" or "t.date_creation:<:'20160101'" or "t.nature:is:NULL"
* @return string Forged criteria. Example: "t.field like 'abc%'"
*/
function dolForgeDummyCriteriaCallback($matches)
{
//dol_syslog("Convert matches ".$matches[1]);
if (empty($matches[1])) {
return '';
}
$tmp = explode(':', $matches[1]);
if (count($tmp) < 3) {
return '';
}
return '()'; // An empty criteria
}
/**
* Function to forge a SQL criteria from a Dolibarr filter syntax string.
* This method is called by forgeSQLFromUniversalSearchCriteria()
*
* @param array $matches Array of found string by regex search.
* Example: "t.ref:like:'SO-%'" or "t.date_creation:<:'20160101'" or "t.date_creation:<:'2016-01-01 12:30:00'" or "t.nature:is:NULL"
* @return string Forged criteria. Example: "t.field like 'abc%'"
*/
function dolForgeCriteriaCallback($matches)
{
global $db;
dol_syslog("Convert matches ".$matches[1]);
//dol_syslog("Convert matches ".$matches[1]);
if (empty($matches[1])) {
return '';
}
$tmp = explode(':', $matches[1], 3);
$tmp = explode(':', $matches[1]);
if (count($tmp) < 3) {
return '';
}
$operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
$operator = strtoupper(preg_replace('/[^a-z<>=]/i', '', trim($tmp[1])));
if ($operator == 'NOTLIKE') {
$operator = 'NOT LIKE';
}
if ($operator == 'ISNOT') {
$operator = 'IS NOT';
}
if ($operator == '!=') {
$operator = '<>';
}
$tmpescaped = trim($tmp[2]);
$tmpescaped = $tmp[2];
$regbis = array();
if ($operator == 'IN') {
$tmpescaped = "(".$db->sanitize($tmpescaped, 1).")";
if ($operator == 'IN') { // IN is allowed for list of ID or code only
//if (!preg_match('/^\(.*\)$/', $tmpescaped)) {
$tmpescaped = '('.$db->escape($db->sanitize($tmpescaped, 1, 0)).')';
//} else {
// $tmpescaped = $db->escape($db->sanitize($tmpescaped, 1));
//}
} elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
$tmpescaped = $regbis[1];
}
//$tmpescaped = "'".$db->escapeforlike($db->escape($regbis[1]))."'";
$tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
} elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
$tmpescaped = "'".$db->escape($regbis[1])."'";
} else {
$tmpescaped = $db->sanitize($db->escape($tmpescaped));
if (strtoupper($tmpescaped) == 'NULL') {
$tmpescaped = 'NULL';
} elseif (is_int($tmpescaped)) {
$tmpescaped = (int) $tmpescaped;
} else {
$tmpescaped = (float) $tmpescaped;
}
}
return $db->escape($operand).' '.$db->escape($operator)." ".$tmpescaped;
return $db->escape($tmp[0]).' '.strtoupper($operator).' '.$tmpescaped;
}
/**
* Get timeline icon
*
* @param ActionComm $actionstatic actioncomm
* @param array $histo histo
* @param int $key key