/**
  * Parses a trigger expression and returns an array of used hosts and items.
  *
  * @param string $expression
  *
  * @return array
  *
  * @throws Exception
  */
 protected function parseTriggerExpression($expression)
 {
     $expressions = array();
     $result = $this->triggerExpression->parse($expression);
     if (!$result) {
         throw new Exception($this->triggerExpression->error);
     }
     foreach ($result->getTokensByType(CTriggerExpressionParserResult::TOKEN_TYPE_FUNCTION_MACRO) as $token) {
         $expressions[] = array('host' => $token['data']['host'], 'item' => $token['data']['item']);
     }
     return $expressions;
 }
 /**
  * Break a trigger expression generated by the constructor.
  *
  * To be successfully parsed, each item function macro must be wrapped in additional parentheses, for example,
  * (({item.item.regex(param)})=0)
  *
  * Most of this function was left unchanged to preserve the current behavior of the constructor.
  * Feel free to rewrite and correct it if necessary.
  *
  * @param string $expression    trigger expression
  *
  * @return array    an array of expression parts, see self::getExpressionFromParts() for the structure of the part
  *                  array
  */
 public function getPartsFromExpression($expression)
 {
     // strip extra parentheses
     $expression = preg_replace('/\\(\\(\\((.+?)\\)\\) and/i', '(($1) and', $expression);
     $expression = preg_replace('/\\(\\(\\((.+?)\\)\\)$/i', '(($1)', $expression);
     $parseResult = $this->triggerExpression->parse($expression);
     $expressions = array();
     $splitTokens = $this->splitTokensByFirstLevel($parseResult->getTokens());
     foreach ($splitTokens as $key => $tokens) {
         $expr = array();
         // replace whole function macros with their functions
         foreach ($tokens as $token) {
             $value = $token['value'];
             switch ($token['type']) {
                 case CTriggerExpressionParserResult::TOKEN_TYPE_FUNCTION_MACRO:
                     $value = $token['data']['function'];
                     break;
                 case CTriggerExpressionParserResult::TOKEN_TYPE_OPERATOR:
                     if ($token['value'] === 'and' || $token['value'] === 'or' || $token['value'] === 'not') {
                         $value = ' ' . $token['value'] . ' ';
                     }
                     break;
             }
             $expr[] = $value;
         }
         $expr = implode($expr);
         // trim surrounding parentheses
         $expr = preg_replace('/^\\((.*)\\)$/u', '$1', $expr);
         // trim parentheses around item function macros
         $value = preg_replace('/\\((.*)\\)(=|<>)0/U', '$1', $expr);
         // trim surrounding parentheses
         $value = preg_replace('/^\\((.*)\\)$/u', '$1', $value);
         $expressions[$key]['value'] = trim($value);
         $expressions[$key]['type'] = strpos($expr, '<>0', mb_strlen($expr) - 4) === false ? self::EXPRESSION_TYPE_NO_MATCH : self::EXPRESSION_TYPE_MATCH;
     }
     return $expressions;
 }
Esempio n. 3
0
function get_item_function_info($expr)
{
    $value_type = array(ITEM_VALUE_TYPE_UINT64 => _('Numeric (integer 64bit)'), ITEM_VALUE_TYPE_FLOAT => _('Numeric (float)'), ITEM_VALUE_TYPE_STR => _('Character'), ITEM_VALUE_TYPE_LOG => _('Log'), ITEM_VALUE_TYPE_TEXT => _('Text'));
    $type_of_value_type = array(ITEM_VALUE_TYPE_UINT64 => T_ZBX_INT, ITEM_VALUE_TYPE_FLOAT => T_ZBX_DBL, ITEM_VALUE_TYPE_STR => T_ZBX_STR, ITEM_VALUE_TYPE_LOG => T_ZBX_STR, ITEM_VALUE_TYPE_TEXT => T_ZBX_STR);
    $function_info = array('band' => array('value_type' => _('Numeric (integer 64bit)'), 'type' => T_ZBX_INT, 'validation' => NOT_EMPTY), 'abschange' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'avg' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'change' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'count' => array('value_type' => _('Numeric (integer 64bit)'), 'type' => T_ZBX_INT, 'validation' => NOT_EMPTY), 'date' => array('value_type' => 'YYYYMMDD', 'type' => T_ZBX_INT, 'validation' => '{}>=19700101&&{}<=99991231'), 'dayofmonth' => array('value_type' => '1-31', 'type' => T_ZBX_INT, 'validation' => '{}>=1&&{}<=31'), 'dayofweek' => array('value_type' => '1-7', 'type' => T_ZBX_INT, 'validation' => IN('1,2,3,4,5,6,7')), 'delta' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'diff' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'fuzzytime' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'iregexp' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'last' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'logeventid' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'logseverity' => array('value_type' => _('Numeric (integer 64bit)'), 'type' => T_ZBX_INT, 'validation' => NOT_EMPTY), 'logsource' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'max' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'min' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'nodata' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'now' => array('value_type' => _('Numeric (integer 64bit)'), 'type' => T_ZBX_INT, 'validation' => NOT_EMPTY), 'prev' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'regexp' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'str' => array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1')), 'strlen' => array('value_type' => _('Numeric (integer 64bit)'), 'type' => T_ZBX_INT, 'validation' => NOT_EMPTY), 'sum' => array('value_type' => $value_type, 'type' => $type_of_value_type, 'validation' => NOT_EMPTY), 'time' => array('value_type' => 'HHMMSS', 'type' => T_ZBX_INT, 'validation' => 'zbx_strlen({})==6'));
    $expressionData = new CTriggerExpression();
    if ($expressionData->parse($expr)) {
        if (isset($expressionData->macros[0])) {
            $result = array('value_type' => _('0 or 1'), 'type' => T_ZBX_INT, 'validation' => IN('0,1'));
        } elseif (isset($expressionData->usermacros[0]) || isset($expressionData->lldmacros[0])) {
            $result = array('value_type' => $value_type[ITEM_VALUE_TYPE_FLOAT], 'type' => T_ZBX_STR, 'validation' => 'preg_match("/^' . ZBX_PREG_NUMBER . '$/u", {})');
        } elseif (isset($expressionData->expressions[0])) {
            $exprPart = reset($expressionData->expressions);
            if (!isset($function_info[$exprPart['functionName']])) {
                return EXPRESSION_FUNCTION_UNKNOWN;
            }
            $hostFound = API::Host()->get(array('filter' => array('host' => array($exprPart['host'])), 'templated_hosts' => true));
            if (!$hostFound) {
                return EXPRESSION_HOST_UNKNOWN;
            }
            $itemFound = API::Item()->get(array('output' => array('value_type'), 'hostids' => zbx_objectValues($hostFound, 'hostid'), 'filter' => array('key_' => array($exprPart['item'])), 'webitems' => true));
            if (!$itemFound) {
                $itemFound = API::ItemPrototype()->get(array('output' => array('value_type'), 'hostids' => zbx_objectValues($hostFound, 'hostid'), 'filter' => array('key_' => array($exprPart['item']))));
                if (!$itemFound) {
                    return EXPRESSION_HOST_ITEM_UNKNOWN;
                }
            }
            $itemFound = reset($itemFound);
            $result = $function_info[$exprPart['functionName']];
            if (is_array($result['value_type'])) {
                $result['value_type'] = $result['value_type'][$itemFound['value_type']];
                $result['type'] = $result['type'][$itemFound['value_type']];
                if ($result['type'] == T_ZBX_INT || $result['type'] == T_ZBX_DBL) {
                    $result['type'] = T_ZBX_STR;
                    $result['validation'] = 'preg_match("/^' . ZBX_PREG_NUMBER . '$/u",{})';
                }
            }
        } else {
            return EXPRESSION_NOT_A_MACRO_ERROR;
        }
    }
    return $result;
}
Esempio n. 4
0
define('COMBO_PATTERN', 'str_in_array({},array(');
define('COMBO_PATTERN_LENGTH', strlen(COMBO_PATTERN));
$definedErrorPhrases = [EXPRESSION_HOST_UNKNOWN => _('Unknown host, no such host present in system'), EXPRESSION_HOST_ITEM_UNKNOWN => _('Unknown host item, no such item in selected host'), EXPRESSION_NOT_A_MACRO_ERROR => _('Given expression is not a macro'), EXPRESSION_FUNCTION_UNKNOWN => _('Incorrect function is used')];
require_once dirname(__FILE__) . '/include/page_header.php';
// expression analyze
$expression = getRequest('expression', '');
define('NO_LINK_IN_TESTING', true);
list($outline, $eHTMLTree) = analyzeExpression($expression);
// test data (create table, create check fields)
$dataTable = (new CTable())->setAttribute('style', 'width: 100%;')->setHeader([_('Expression Variable Elements'), _('Result type'), _('Value')]);
$datas = [];
$fields = [];
$rplcts = [];
$allowedTesting = true;
$expressionData = new CTriggerExpression();
$result = $expressionData->parse($expression);
if ($result) {
    $macrosData = [];
    $supportedTokenTypes = [CTriggerExpressionParserResult::TOKEN_TYPE_FUNCTION_MACRO => 1, CTriggerExpressionParserResult::TOKEN_TYPE_MACRO => 1, CTriggerExpressionParserResult::TOKEN_TYPE_USER_MACRO => 1, CTriggerExpressionParserResult::TOKEN_TYPE_LLD_MACRO => 1];
    foreach ($result->getTokens() as $token) {
        if (!isset($supportedTokenTypes[$token['type']]) || isset($macrosData[$token['value']])) {
            continue;
        }
        $row = (new CRow())->addItem($token['value']);
        $fname = 'test_data_' . md5($token['value']);
        $macrosData[$token['value']] = getRequest($fname, '');
        $info = get_item_function_info($token['value']);
        if (!is_array($info) && isset($definedErrorPhrases[$info])) {
            $allowedTesting = false;
            $row->addItem((new CCol($definedErrorPhrases[$info]))->addClass(ZBX_STYLE_RED)->setColspan(2));
        } else {
Esempio n. 5
0
 /**
  * Checks that no trigger with the same description and expression as $trigger exist on the given host.
  * Assumes the given trigger is valid.
  *
  * @throws APIException if at least one trigger exists
  *
  * @param array $trigger a trigger with an exploded expression
  * @param null  $hostid
  *
  * @return void
  */
 protected function checkIfExistsOnHost(array $trigger, $hostId = null)
 {
     // skip the check if the description and expression haven't been changed
     if (!isset($trigger['description']) && !isset($trigger['expression'])) {
         return;
     }
     // make sure we have all the required data
     if (!isset($trigger['description']) || !isset($trigger['expression'])) {
         $explodeExpression = !isset($trigger['expression']);
         $trigger = $this->extendObject($this->tableName(), $trigger, array('description', 'expression'));
         if ($explodeExpression) {
             $trigger['expression'] = explode_exp($trigger['expression']);
         }
     }
     $filter = array('description' => $trigger['description']);
     if ($hostId) {
         $filter['hostid'] = $hostId;
     } else {
         $expressionData = new CTriggerExpression($trigger['expression']);
         $expressionData->parse($trigger['expression']);
         $expressionHosts = $expressionData->getHosts();
         $filter['host'] = reset($expressionHosts);
     }
     $triggers = $this->get(array('filter' => $filter, 'output' => array('expression', 'triggerid'), 'nopermissions' => true));
     foreach ($triggers as $dbTrigger) {
         $tmpExp = explode_exp($dbTrigger['expression']);
         // check if the expressions are also equal and that this is a different trigger
         $differentTrigger = !isset($trigger['triggerid']) || !idcmp($trigger['triggerid'], $dbTrigger['triggerid']);
         if (strcmp($tmpExp, $trigger['expression']) == 0 && $differentTrigger) {
             $options = array('output' => array('name'), 'templated_hosts' => true, 'nopermissions' => true, 'limit' => 1);
             if (isset($filter['host'])) {
                 $options['filter'] = array('host' => $filter['host']);
             } else {
                 $options['hostids'] = $hostId;
             }
             $host = API::Host()->get($options);
             $host = reset($host);
             self::exception(ZBX_API_ERROR_PARAMETERS, _s('Trigger "%1$s" already exists on "%2$s".', $trigger['description'], $host['name']));
         }
     }
 }
Esempio n. 6
0
 /**
  * Check if all templates trigger belongs to are linked to same hosts.
  *
  * @throws APIException
  *
  * @param $trigger
  *
  * @return bool
  */
 protected function validateItems(array $trigger)
 {
     $expressionData = new CTriggerExpression();
     $expressionData->parse($trigger['expression']);
     $templatesData = API::Template()->get(['output' => ['templateid'], 'selectHosts' => ['hostid'], 'selectTemplates' => ['templateid'], 'filter' => ['host' => $expressionData->getHosts()], 'nopermissions' => true, 'preservekeys' => true]);
     $firstTemplate = array_pop($templatesData);
     if ($firstTemplate) {
         $compareLinks = array_merge(zbx_objectValues($firstTemplate['hosts'], 'hostid'), zbx_objectValues($firstTemplate['templates'], 'templateid'));
         foreach ($templatesData as $data) {
             $linkedTo = array_merge(zbx_objectValues($data['hosts'], 'hostid'), zbx_objectValues($data['templates'], 'templateid'));
             if (array_diff($compareLinks, $linkedTo) || array_diff($linkedTo, $compareLinks)) {
                 self::exception(ZBX_API_ERROR_PARAMETERS, _s('Trigger "%s" belongs to templates with different linkages.', $trigger['description']));
             }
         }
     }
     return true;
 }
Esempio n. 7
0
 protected function updateReal(array $triggers)
 {
     $triggers = zbx_toArray($triggers);
     $dbTriggers = $this->get(array('triggerids' => zbx_objectValues($triggers, 'triggerid'), 'output' => API_OUTPUT_EXTEND, 'selectHosts' => array('name'), 'preservekeys' => true, 'nopermissions' => true));
     $descriptionChanged = $expressionChanged = false;
     foreach ($triggers as &$trigger) {
         $dbTrigger = $dbTriggers[$trigger['triggerid']];
         $hosts = zbx_objectValues($dbTrigger['hosts'], 'name');
         if (isset($trigger['description']) && strcmp($dbTrigger['description'], $trigger['description']) != 0) {
             $descriptionChanged = true;
         }
         $expressionFull = explode_exp($dbTrigger['expression']);
         if (isset($trigger['expression']) && strcmp($expressionFull, $trigger['expression']) != 0) {
             $expressionChanged = true;
             $expressionFull = $trigger['expression'];
         }
         if ($descriptionChanged || $expressionChanged) {
             $expressionData = new CTriggerExpression();
             if (!$expressionData->parse($expressionFull)) {
                 self::exception(ZBX_API_ERROR_PARAMETERS, $expressionData->error);
             }
             if (!isset($expressionData->expressions[0])) {
                 self::exception(ZBX_API_ERROR_PARAMETERS, _('Trigger expression must contain at least one host:key reference.'));
             }
         }
         if ($expressionChanged) {
             DB::delete('functions', array('triggerid' => $trigger['triggerid']));
             try {
                 $trigger['expression'] = implode_exp($expressionFull, $trigger['triggerid'], $hosts);
             } catch (Exception $e) {
                 self::exception(ZBX_API_ERROR_PARAMETERS, _s('Cannot implode expression "%s".', $expressionFull) . ' ' . $e->getMessage());
             }
         }
         $triggerUpdate = $trigger;
         if (!$descriptionChanged) {
             unset($triggerUpdate['description']);
         }
         if (!$expressionChanged) {
             unset($triggerUpdate['expression']);
         }
         // skip updating read only values
         unset($triggerUpdate['state'], $triggerUpdate['value'], $triggerUpdate['lastchange'], $triggerUpdate['error']);
         DB::update('triggers', array('values' => $triggerUpdate, 'where' => array('triggerid' => $trigger['triggerid'])));
         $description = isset($trigger['description']) ? $trigger['description'] : $dbTrigger['description'];
         info(_s('Updated: Trigger prototype "%1$s" on "%2$s".', $description, implode(', ', $hosts)));
     }
     unset($trigger);
 }
$param1_sec = array(array('C' => _('Last of') . ' (T)', 'T' => T_ZBX_INT));
$param1_str = array(array('C' => 'T', 'T' => T_ZBX_STR));
$param2_sec_count = array(array('C' => 'V', 'T' => T_ZBX_STR), array('C' => _('Last of') . ' (T)', 'T' => T_ZBX_INT, 'M' => $metrics));
$param3_sec_val = array(array('C' => _('Last of') . ' (T)', 'T' => T_ZBX_INT, 'M' => $metrics), array('C' => 'V', 'T' => T_ZBX_STR), array('C' => 'O', 'T' => T_ZBX_STR), array('C' => _('Time shift') . ' ', 'T' => T_ZBX_INT));
$allowed_types_any = array(ITEM_VALUE_TYPE_FLOAT => 1, ITEM_VALUE_TYPE_STR => 1, ITEM_VALUE_TYPE_LOG => 1, ITEM_VALUE_TYPE_UINT64 => 1, ITEM_VALUE_TYPE_TEXT => 1);
$allowed_types_numeric = array(ITEM_VALUE_TYPE_FLOAT => 1, ITEM_VALUE_TYPE_UINT64 => 1);
$allowed_types_str = array(ITEM_VALUE_TYPE_STR => 1, ITEM_VALUE_TYPE_LOG => 1, ITEM_VALUE_TYPE_TEXT => 1);
$allowed_types_log = array(ITEM_VALUE_TYPE_LOG => 1);
$functions = array('abschange[<]' => array('description' => _('Absolute difference between last and previous value is < N'), 'allowed_types' => $allowed_types_any), 'abschange[>]' => array('description' => _('Absolute difference between last and previous value is > N'), 'allowed_types' => $allowed_types_any), 'abschange[=]' => array('description' => _('Absolute difference between last and previous value is = N'), 'allowed_types' => $allowed_types_any), 'abschange[#]' => array('description' => _('Absolute difference between last and previous value is NOT N'), 'allowed_types' => $allowed_types_any), 'avg[<]' => array('description' => _('Average value of a period T is < N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'avg[>]' => array('description' => _('Average value of a period T is > N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'avg[=]' => array('description' => _('Average value of a period T is = N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'avg[#]' => array('description' => _('Average value of a period T is NOT N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'delta[<]' => array('description' => _('Difference between MAX and MIN value of a period T is < N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'delta[>]' => array('description' => _('Difference between MAX and MIN value of a period T is > N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'delta[=]' => array('description' => _('Difference between MAX and MIN value of a period T is = N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'delta[#]' => array('description' => _('Difference between MAX and MIN value of a period T is NOT N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'change[<]' => array('description' => _('Difference between last and previous value is < N'), 'allowed_types' => $allowed_types_any), 'change[>]' => array('description' => _('Difference between last and previous value is > N'), 'allowed_types' => $allowed_types_any), 'change[=]' => array('description' => _('Difference between last and previous value is = N'), 'allowed_types' => $allowed_types_any), 'change[#]' => array('description' => _('Difference between last and previous value is NOT N'), 'allowed_types' => $allowed_types_any), 'count[<]' => array('description' => _('Number of successfully retrieved values V (which fulfill operator O) for period T is < N'), 'params' => $param3_sec_val, 'allowed_types' => $allowed_types_any), 'count[>]' => array('description' => _('Number of successfully retrieved values V (which fulfill operator O) for period T is > N'), 'params' => $param3_sec_val, 'allowed_types' => $allowed_types_any), 'count[=]' => array('description' => _('Number of successfully retrieved values V (which fulfill operator O) for period T is = N'), 'params' => $param3_sec_val, 'allowed_types' => $allowed_types_any), 'count[#]' => array('description' => _('Number of successfully retrieved values V (which fulfill operator O) for period T is NOT N'), 'params' => $param3_sec_val, 'allowed_types' => $allowed_types_any), 'diff[=]' => array('description' => _('Difference between last and preceding values, then N = 1, 0 - otherwise'), 'allowed_types' => $allowed_types_any), 'diff[#]' => array('description' => _('Difference between last and preceding values, then N NOT 1, 0 - otherwise'), 'allowed_types' => $allowed_types_any), 'last[<]' => array('description' => _('Last (most recent) T value is < N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_any), 'last[>]' => array('description' => _('Last (most recent) T value is > N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_any), 'last[=]' => array('description' => _('Last (most recent) T value is = N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_any), 'last[#]' => array('description' => _('Last (most recent) T value is NOT N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_any), 'max[<]' => array('description' => _('Maximum value for period T is < N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'max[>]' => array('description' => _('Maximum value for period T is > N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'max[=]' => array('description' => _('Maximum value for period T is = N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'max[#]' => array('description' => _('Maximum value for period T is NOT N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'min[<]' => array('description' => _('Minimum value for period T is < N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'min[>]' => array('description' => _('Minimum value for period T is > N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'min[=]' => array('description' => _('Minimum value for period T is = N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'min[#]' => array('description' => _('Minimum value for period T is NOT N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'prev[<]' => array('description' => _('Previous value is < N'), 'allowed_types' => $allowed_types_any), 'prev[>]' => array('description' => _('Previous value is > N'), 'allowed_types' => $allowed_types_any), 'prev[=]' => array('description' => _('Previous value is = N'), 'allowed_types' => $allowed_types_any), 'prev[#]' => array('description' => _('Previous value is NOT N'), 'allowed_types' => $allowed_types_any), 'str[=]' => array('description' => _('Find string V in last (most recent) value. N = 1 - if found, 0 - otherwise'), 'params' => $param2_sec_count, 'allowed_types' => $allowed_types_any), 'str[#]' => array('description' => _('Find string V in last (most recent) value. N NOT 1 - if found, 0 - otherwise'), 'params' => $param2_sec_count, 'allowed_types' => $allowed_types_any), 'strlen[<]' => array('description' => _('Length of last (most recent) T value in characters is < N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_str), 'strlen[>]' => array('description' => _('Length of last (most recent) T value in characters is > N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_str), 'strlen[=]' => array('description' => _('Length of last (most recent) T value in characters is = N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_str), 'strlen[#]' => array('description' => _('Length of last (most recent) T value in characters is NOT N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_str), 'sum[<]' => array('description' => _('Sum of values of a period T is < N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'sum[>]' => array('description' => _('Sum of values of a period T is > N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'sum[=]' => array('description' => _('Sum of values of a period T is = N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'sum[#]' => array('description' => _('Sum of values of a period T is NOT N'), 'params' => $param1_sec_count, 'allowed_types' => $allowed_types_numeric), 'date[<]' => array('description' => _('Current date is < N'), 'allowed_types' => $allowed_types_any), 'date[>]' => array('description' => _('Current date is > N'), 'allowed_types' => $allowed_types_any), 'date[=]' => array('description' => _('Current date is = N'), 'allowed_types' => $allowed_types_any), 'date[#]' => array('description' => _('Current date is NOT N'), 'allowed_types' => $allowed_types_any), 'dayofweek[<]' => array('description' => _('Day of week is < N'), 'allowed_types' => $allowed_types_any), 'dayofweek[>]' => array('description' => _('Day of week is > N'), 'allowed_types' => $allowed_types_any), 'dayofweek[=]' => array('description' => _('Day of week is = N'), 'allowed_types' => $allowed_types_any), 'dayofweek[#]' => array('description' => _('Day of week is NOT N'), 'allowed_types' => $allowed_types_any), 'dayofmonth[<]' => array('description' => _('Day of month is < N'), 'allowed_types' => $allowed_types_any), 'dayofmonth[>]' => array('description' => _('Day of month is > N'), 'allowed_types' => $allowed_types_any), 'dayofmonth[=]' => array('description' => _('Day of month is = N'), 'allowed_types' => $allowed_types_any), 'dayofmonth[#]' => array('description' => _('Day of month is NOT N'), 'allowed_types' => $allowed_types_any), 'fuzzytime[=]' => array('description' => _('Timestamp not different from Zabbix server time for more than T seconds, then N = 1, 0 - otherwise'), 'params' => $param1_sec, 'allowed_types' => $allowed_types_any), 'fuzzytime[#]' => array('description' => _('Timestamp not different from Zabbix server time for more than T seconds, then N NOT 1, 0 - otherwise'), 'params' => $param1_sec, 'allowed_types' => $allowed_types_any), 'regexp[=]' => array('description' => _('Regular expression V matching last value in period T, then N = 1, 0 - otherwise'), 'params' => $param2_sec_count, 'allowed_types' => $allowed_types_any), 'regexp[#]' => array('description' => _('Regular expression V matching last value in period T, then N NOT 1, 0 - otherwise'), 'params' => $param2_sec_count, 'allowed_types' => $allowed_types_any), 'iregexp[=]' => array('description' => _('Regular expression V matching last value in period T, then N = 1, 0 - otherwise (non case-sensitive)'), 'params' => $param2_sec_count, 'allowed_types' => $allowed_types_any), 'iregexp[#]' => array('description' => _('Regular expression V matching last value in period T, then N NOT 1, 0 - otherwise (non case-sensitive)'), 'params' => $param2_sec_count, 'allowed_types' => $allowed_types_any), 'logeventid[=]' => array('description' => _('Event ID of last log entry matching regular expression T, then N = 1, 0 - otherwise'), 'params' => $param1_str, 'allowed_types' => $allowed_types_log), 'logeventid[#]' => array('description' => _('Event ID of last log entry matching regular expression T, then N NOT 1, 0 - otherwise'), 'params' => $param1_str, 'allowed_types' => $allowed_types_log), 'logseverity[<]' => array('description' => _('Log severity of the last log entry is < N'), 'allowed_types' => $allowed_types_log), 'logseverity[>]' => array('description' => _('Log severity of the last log entry is > N'), 'allowed_types' => $allowed_types_log), 'logseverity[=]' => array('description' => _('Log severity of the last log entry is = N'), 'allowed_types' => $allowed_types_log), 'logseverity[#]' => array('description' => _('Log severity of the last log entry is NOT N'), 'allowed_types' => $allowed_types_log), 'logsource[=]' => array('description' => _('Log source of the last log entry matching parameter T, then N = 1, 0 - otherwise'), 'params' => $param1_str, 'allowed_types' => $allowed_types_log), 'logsource[#]' => array('description' => _('Log source of the last log entry matching parameter T, then N NOT 1, 0 - otherwise'), 'params' => $param1_str, 'allowed_types' => $allowed_types_log), 'now[<]' => array('description' => _('Number of seconds since the Epoch is < N'), 'allowed_types' => $allowed_types_any), 'now[>]' => array('description' => _('Number of seconds since the Epoch is > N'), 'allowed_types' => $allowed_types_any), 'now[=]' => array('description' => _('Number of seconds since the Epoch is = N'), 'allowed_types' => $allowed_types_any), 'now[#]' => array('description' => _('Number of seconds since the Epoch is NOT N'), 'allowed_types' => $allowed_types_any), 'time[<]' => array('description' => _('Current time is < N'), 'allowed_types' => $allowed_types_any), 'time[>]' => array('description' => _('Current time is > N'), 'allowed_types' => $allowed_types_any), 'time[=]' => array('description' => _('Current time is = N'), 'allowed_types' => $allowed_types_any), 'time[#]' => array('description' => _('Current time is NOT N'), 'allowed_types' => $allowed_types_any), 'nodata[=]' => array('description' => _('No data received during period of time T, then N = 1, 0 - otherwise'), 'params' => $param1_sec, 'allowed_types' => $allowed_types_any), 'nodata[#]' => array('description' => _('No data received during period of time T, then N NOT 1, 0 - otherwise'), 'params' => $param1_sec, 'allowed_types' => $allowed_types_any));
//	VAR		TYPE	OPTIONAL FLAGS	VALIDATION	EXCEPTION
$fields = array('dstfrm' => array(T_ZBX_STR, O_MAND, P_SYS, NOT_EMPTY, null), 'dstfld1' => array(T_ZBX_STR, O_MAND, P_SYS, NOT_EMPTY, null), 'expression' => array(T_ZBX_STR, O_OPT, null, null, null), 'itemid' => array(T_ZBX_INT, O_OPT, null, null, 'isset({insert})'), 'parent_discoveryid' => array(T_ZBX_INT, O_OPT, null, null, null), 'expr_type' => array(T_ZBX_STR, O_OPT, null, NOT_EMPTY, 'isset({insert})'), 'param' => array(T_ZBX_STR, O_OPT, null, 0, 'isset({insert})'), 'paramtype' => array(T_ZBX_INT, O_OPT, null, IN(PARAM_TYPE_SECONDS . ',' . PARAM_TYPE_COUNTS), 'isset({insert})'), 'value' => array(T_ZBX_STR, O_OPT, null, NOT_EMPTY, 'isset({insert})'), 'insert' => array(T_ZBX_STR, O_OPT, P_SYS | P_ACT, null, null), 'cancel' => array(T_ZBX_STR, O_OPT, P_SYS, null, null));
check_fields($fields);
if (isset($_REQUEST['expression']) && $_REQUEST['dstfld1'] == 'expr_temp') {
    $_REQUEST['expression'] = utf8RawUrlDecode($_REQUEST['expression']);
    $expressionData = new CTriggerExpression();
    if ($expressionData->parse($_REQUEST['expression']) && count($expressionData->expressions) == 1) {
        $exprPart = reset($expressionData->expressions);
        preg_match('/\\}([=><#]{1})([0-9]+)$/', $_REQUEST['expression'], $exprSymbols);
        if (isset($exprSymbols[1])) {
            $_REQUEST['expr_type'] = $exprPart['functionName'] . '[' . $exprSymbols[1] . ']';
        }
        $_REQUEST['description'] = $exprPart['host'] . ':' . $exprPart['item'];
        $_REQUEST['param'] = $exprPart['functionParamList'];
        $param_no = in_array($exprPart['functionName'], array('regexp', 'iregexp', 'str')) ? 1 : 0;
        if (isset($_REQUEST['param'][$param_no][0]) && $_REQUEST['param'][$param_no][0] == '#') {
            $_REQUEST['paramtype'] = PARAM_TYPE_COUNTS;
            $_REQUEST['param'][$param_no] = substr($_REQUEST['param'][$param_no], 1);
        } else {
            $_REQUEST['paramtype'] = PARAM_TYPE_SECONDS;
        }
        if (isset($exprSymbols[2])) {
Esempio n. 9
0
 /**
  * Expand functional macros in given map label.
  *
  * @param string $label			label to expand
  * @param array  $replaceHosts	list of hosts in order which they appear in trigger expression if trigger label is given,
  * or single host when host label is given
  *
  * @return string
  */
 public function resolveMapLabelMacros($label, $replaceHosts = null)
 {
     $functionsPattern = '(last|max|min|avg)\\(([0-9]+[' . ZBX_TIME_SUFFIXES . ']?)?\\)';
     // Find functional macro pattern.
     $pattern = $replaceHosts === null ? '/{' . ZBX_PREG_HOST_FORMAT . ':.+\\.' . $functionsPattern . '}/Uu' : '/{(' . ZBX_PREG_HOST_FORMAT . '|{HOSTNAME[0-9]?}|{HOST\\.HOST[0-9]?}):.+\\.' . $functionsPattern . '}/Uu';
     preg_match_all($pattern, $label, $matches);
     // For each functional macro.
     foreach ($matches[0] as $expr) {
         $macro = $expr;
         if ($replaceHosts !== null) {
             // Search for macros with all possible indices.
             foreach ($replaceHosts as $i => $host) {
                 $macroTmp = $macro;
                 // Replace only macro in first position.
                 $macro = preg_replace('/{({HOSTNAME' . $i . '}|{HOST\\.HOST' . $i . '}):(.*)}/U', '{' . $host['host'] . ':$2}', $macro);
                 // Only one simple macro possible inside functional macro.
                 if ($macro !== $macroTmp) {
                     break;
                 }
             }
         }
         // Try to create valid expression.
         $expressionData = new CTriggerExpression();
         if (!$expressionData->parse($macro) || !isset($expressionData->expressions[0])) {
             continue;
         }
         // Look in DB for corresponding item.
         $itemHost = $expressionData->expressions[0]['host'];
         $key = $expressionData->expressions[0]['item'];
         $function = $expressionData->expressions[0]['functionName'];
         $item = API::Item()->get(['output' => ['itemid', 'value_type', 'units', 'valuemapid', 'lastvalue', 'lastclock'], 'webitems' => true, 'filter' => ['host' => $itemHost, 'key_' => $key]]);
         $item = reset($item);
         // If no corresponding item found with functional macro key and host.
         if (!$item) {
             $label = str_replace($expr, UNRESOLVED_MACRO_STRING, $label);
             continue;
         }
         // Do function type (last, min, max, avg) related actions.
         if ($function === 'last') {
             $value = $item['lastclock'] ? formatHistoryValue($item['lastvalue'], $item) : UNRESOLVED_MACRO_STRING;
         } else {
             $value = getItemFunctionalValue($item, $function, $expressionData->expressions[0]['functionParamList'][0]);
         }
         if (isset($value)) {
             $label = str_replace($expr, $value, $label);
         }
     }
     return $label;
 }
Esempio n. 10
0
/**
 * Expand functional macros in given map label.
 *
 * @param string $label label to expand
 * @param array $replaceHosts list of hosts in order which they appear in trigger expression if trigger label is given,
 * or single host when host label is given
 *
 * @return string expanded label
 */
function resolveMapLabelMacros($label, $replaceHosts = null)
{
    // find functional macro pattern
    $pattern = null === $replaceHosts ? '/{' . ZBX_PREG_HOST_FORMAT . ":.+\\.(last|max|min|avg)\\([0-9]+[smhdwKMGT]?\\)}/Uu" : '/{(' . ZBX_PREG_HOST_FORMAT . "|{HOSTNAME[0-9]?}|{HOST\\.HOST[0-9]?}):.+\\.(last|max|min|avg)\\([0-9]+[smhdwKMGT]?\\)}/Uu";
    preg_match_all($pattern, $label, $matches);
    // for each functional macro
    foreach ($matches[0] as $expr) {
        $macro = $expr;
        if ($replaceHosts !== null) {
            // search for macros with all possible indecies
            foreach ($replaceHosts as $i => $host) {
                $macroTmp = $macro;
                // repalce only macro in first position
                $macro = preg_replace('/{({HOSTNAME' . $i . '}|{HOST\\.HOST' . $i . '}):(.*)}/U', '{' . $host['host'] . ':$2}', $macro);
                // only one simple macro possible inside functional macro
                if ($macro != $macroTmp) {
                    break;
                }
            }
        }
        // try to create valid expression
        $expressionData = new CTriggerExpression();
        if (!$expressionData->parse($macro) || !isset($expressionData->expressions[0])) {
            continue;
        }
        // look in DB for coressponding item
        $itemHost = $expressionData->expressions[0]['host'];
        $key = $expressionData->expressions[0]['item'];
        $function = $expressionData->expressions[0]['functionName'];
        $parameter = convertFunctionValue($expressionData->expressions[0]['functionParamList'][0]);
        $item = API::Item()->get(array('webitems' => true, 'filter' => array('host' => $itemHost, 'key_' => $key), 'output' => array('lastclock', 'value_type', 'lastvalue', 'units', 'valuemapid')));
        $item = reset($item);
        // if no corresponding item found with functional macro key and host
        if (!$item) {
            $label = str_replace($expr, '???', $label);
            continue;
        }
        // do function type (last, min, max, avg) related actions
        if (0 == strcmp($function, 'last')) {
            $value = $item['lastclock'] ? formatHistoryValue($item['lastvalue'], $item) : UNRESOLVED_MACRO_STRING;
        } elseif (0 == strcmp($function, 'min') || 0 == strcmp($function, 'max') || 0 == strcmp($function, 'avg')) {
            $value = getItemFunctionalValue($item, $function, $parameter);
        }
        if (isset($value)) {
            $label = str_replace($expr, $value, $label);
        }
    }
    return $label;
}
 /**
  * Checks if trigger prototype is in valid state. Checks trigger expression.
  *
  * @param array $triggerPrototype
  *
  * @return void
  */
 protected function validateTriggerPrototypeExpression(array $triggerPrototype)
 {
     $triggerExpression = new CTriggerExpression();
     if (!$triggerExpression->parse($triggerPrototype['expression'])) {
         self::exception(ZBX_API_ERROR_PARAMETERS, $triggerExpression->error);
     }
     $expressionHostnames = $triggerExpression->getHosts();
     $this->checkTemplatesAndHostsTogether($expressionHostnames);
     $triggerExpressionItems = getExpressionItems($triggerExpression);
     $this->checkDiscoveryRuleCount($triggerPrototype, $triggerExpressionItems);
 }
Esempio n. 12
0
 $ctb->setAttribute('id', 'logexpr');
 $cb = new CButton('add_exp', _('Add'), 'javascript: add_logexpr();');
 $cbAdd = new CButton('add_key_and', _('AND'), 'javascript: add_keyword_and();');
 $cbOr = new CButton('add_key_or', _('OR'), 'javascript: add_keyword_or();');
 $cbIregexp = new CCheckBox('iregexp', 'no', null, 1);
 $frmTRLog->addRow(_('Expression'), array($ctb, BR(), $cbIregexp, 'iregexp', SPACE, $cbAdd, SPACE, $cbOr, SPACE, $exp_select, SPACE, $cb));
 $keyTable = new CTableInfo(null);
 $keyTable->setAttribute('id', 'key_list');
 $keyTable->setHeader(array(_('Keyword'), _('Type'), _('Action')));
 $table = new CTableInfo(null);
 $table->setAttribute('id', 'exp_list');
 $table->setHeader(array(_('Expression'), _('Type'), _('Position'), _('Action')));
 $maxid = 0;
 $bExprResult = true;
 $expressionData = new CTriggerExpression();
 if (isset($_REQUEST['triggerid']) && !isset($_REQUEST['save_trigger']) && !$expressionData->parse(empty($expressions) ? '' : construct_expression($itemid, $expressions)) && !isset($_REQUEST['form_refresh'])) {
     info($expressionData->error);
     unset($expressions);
     $expressions[0]['value'] = $expr_incase;
     $expressions[0]['type'] = 0;
     $expressions[0]['view'] = $expr_incase;
     $bExprResult = false;
 }
 foreach ($expressions as $id => $expr) {
     $imgup = new CImg('images/general/arrow_up.png', 'up', 12, 14);
     $imgup->setAttribute('onclick', 'javascript:  element_up("logtr' . $id . '");');
     $imgup->setAttribute('onmouseover', 'javascript: this.style.cursor = "pointer";');
     $imgdn = new CImg('images/general/arrow_down.png', 'down', 12, 14);
     $imgdn->setAttribute('onclick', 'javascript:  element_down("logtr' . $id . '");');
     $imgdn->setAttribute('onmouseover', 'javascript: this.style.cursor = "pointer";');
     $del_url = new CSpan(_('Delete'), 'link');
Esempio n. 13
0
/**
 * Substitute macros in the expression with the given values and evaluate it's result.
 *
 * @param string $expression                a trigger expression
 * @param array  $replaceFunctionMacros     an array of macro - value pairs
 *
 * @return bool     the calculated value of the expression
 */
function evalExpressionData($expression, $replaceFunctionMacros)
{
    // replace function macros with their values
    $expression = str_replace(array_keys($replaceFunctionMacros), array_values($replaceFunctionMacros), $expression);
    $parser = new CTriggerExpression();
    $parseResult = $parser->parse($expression);
    // The $replaceFunctionMacros array may contain string values which after substitution
    // will result in an invalid expression. In such cases we should just return false.
    if (!$parseResult) {
        return false;
    }
    // turn the expression into valid PHP code
    $evStr = '';
    $replaceOperators = array('not' => '!', '=' => '==');
    foreach ($parseResult->getTokens() as $token) {
        $value = $token['value'];
        switch ($token['type']) {
            case CTriggerExpressionParserResult::TOKEN_TYPE_OPERATOR:
                // replace specific operators with their PHP analogues
                if (isset($replaceOperators[$token['value']])) {
                    $value = $replaceOperators[$token['value']];
                }
                break;
            case CTriggerExpressionParserResult::TOKEN_TYPE_NUMBER:
                // convert numeric values with suffixes
                if ($token['data']['suffix'] !== null) {
                    $value = convert($value);
                }
                $value = '((float) "' . $value . '")';
                break;
        }
        $evStr .= ' ' . $value;
    }
    // execute expression
    eval('$result = (' . trim($evStr) . ');');
    return $result;
}
//----------------------------------------------------------------------
// expression analyze
$expression = get_request('expression', '');
define('NO_LINK_IN_TESTING', true);
list($outline, $eHTMLTree) = analyzeExpression($expression);
// test data (create table, create check fields)
$data_table = new CTable(null, 'tableinfo');
$data_table->setAttribute('id', 'data_list');
$data_table->setHeader(array(_('Expression Variable Elements'), _('Result type'), _('Value')));
$octet = false;
$datas = array();
$fields = array();
$rplcts = array();
$allowedTesting = true;
$expressionData = new CTriggerExpression();
if ($expressionData->parse($expression)) {
    $macrosData = array();
    $expressions = array_merge($expressionData->expressions, $expressionData->macros, $expressionData->usermacros);
    foreach ($expressions as $exprPart) {
        if (isset($macrosData[$exprPart['expression']])) {
            continue;
        }
        $fname = 'test_data_' . md5($exprPart['expression']);
        $macrosData[$exprPart['expression']] = get_request($fname, '');
        $info = get_item_function_info($exprPart['expression']);
        if (!is_array($info) && isset($definedErrorPhrases[$info])) {
            $allowedTesting = false;
            $control = new CTextBox($fname, $macrosData[$exprPart['expression']], 30);
            $control->setAttribute('disabled', 'disabled');
        } else {
            $octet = $info['value_type'] == 'HHMMSS';
Esempio n. 15
0
 /**
  * Check if trigger prototype has a correct trigger expression and has at least one item prototype and belongs to
  * one discovery rule, does not belong to a host and a template simultaneously and has permissions to all hosts and
  * templates in the expression.
  *
  * @param array  $triggerPrototype
  * @param string $triggerPrototype['description']
  * @param string $triggerPrototype['expression']
  *
  * @throws APIException
  *
  * @return void
  */
 protected function checkExpression(array $triggerPrototype)
 {
     $triggerExpression = new CTriggerExpression();
     if (!$triggerExpression->parse($triggerPrototype['expression'])) {
         self::exception(ZBX_API_ERROR_PARAMETERS, $triggerExpression->error);
     }
     $lld_rules = [];
     if ($triggerExpression->expressions) {
         $expressions = [];
         $hosts = [];
         $has_host = false;
         $has_template = false;
         foreach ($triggerExpression->expressions as $expression) {
             if (!array_key_exists($expression['host'], $expressions)) {
                 $expressions[$expression['host']] = ['hostid' => null, 'items' => []];
             }
             $expressions[$expression['host']]['items'][$expression['item']] = true;
             $hosts[$expression['host']] = true;
         }
         $db_hosts = API::Host()->get(['output' => ['hostid', 'host'], 'filter' => ['host' => array_keys($hosts)]]);
         foreach ($db_hosts as $db_host) {
             $expressions[$db_host['host']]['hostid'] = $db_host['hostid'];
             $has_host = true;
             unset($hosts[$db_host['host']]);
         }
         if ($hosts) {
             $db_templates = API::Template()->get(['output' => ['templateid', 'host'], 'filter' => ['host' => array_keys($hosts)]]);
             foreach ($db_templates as $db_template) {
                 $expressions[$db_template['host']]['hostid'] = $db_template['templateid'];
                 $has_template = true;
             }
         }
         if ($has_host && $has_template) {
             self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect trigger prototype expression.' . ' Trigger prototype expression elements should not belong to a template and a host simultaneously.'));
         }
         foreach ($expressions as $host => $expression) {
             if ($expression['hostid'] === null) {
                 self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect trigger prototype expression.' . ' Host "%1$s" does not exist or you have no access to this host.', $host));
             }
             $db_item_prototypes = API::ItemPrototype()->get(['output' => [], 'selectDiscoveryRule' => ['itemid'], 'hostids' => [$expression['hostid']], 'filter' => ['key_' => array_keys($expression['items'])], 'nopermissions' => true]);
             foreach ($db_item_prototypes as $db_item_prototype) {
                 $lld_rules[$db_item_prototype['discoveryRule']['itemid']] = true;
             }
         }
         if (count($lld_rules) > 1) {
             self::exception(ZBX_API_ERROR_PARAMETERS, _s('Trigger prototype "%1$s" contains item prototypes from multiple discovery rules.', $triggerPrototype['description']));
         }
     }
     if (!$lld_rules) {
         self::exception(ZBX_API_ERROR_PARAMETERS, _s('Trigger prototype "%1$s" must contain at least one item prototype.', $triggerPrototype['description']));
     }
 }
Esempio n. 16
0
 if ($data['paramtype'] == PARAM_TYPE_COUNTS) {
     $paramNumber = in_array($function, ['regexp', 'iregexp', 'str']) ? 1 : 0;
     $data['params'][$paramNumber] = '#' . $data['params'][$paramNumber];
 }
 if ($data['paramtype'] == PARAM_TYPE_TIME && in_array($function, ['last', 'band', 'strlen'])) {
     $data['params'][0] = '';
 }
 // quote function param
 $quotedParams = [];
 foreach ($data['params'] as $param) {
     $quotedParams[] = quoteFunctionParam($param);
 }
 $data['expression'] = sprintf('{%s:%s.%s(%s)}%s%s', $itemHostData['host'], $data['item_key'], $function, rtrim(implode(',', $quotedParams), ','), $operator, $data['value']);
 // validate trigger expression
 $triggerExpression = new CTriggerExpression();
 if ($triggerExpression->parse($data['expression'])) {
     $expressionData = reset($triggerExpression->expressions);
     // validate trigger function
     $triggerFunctionValidator = new CFunctionValidator();
     $isValid = $triggerFunctionValidator->validate(['function' => $expressionData['function'], 'functionName' => $expressionData['functionName'], 'functionParamList' => $expressionData['functionParamList'], 'valueType' => $data['itemValueType']]);
     if (!$isValid) {
         unset($data['insert']);
         throw new Exception($triggerFunctionValidator->getError());
     }
 } else {
     unset($data['insert']);
     throw new Exception($triggerExpression->error);
 }
 // quote function param
 if (isset($data['insert'])) {
     foreach ($data['params'] as $pnum => $param) {
/**
 * Expand functional macros in given map label.
 *
 * @param string $label label to expand
 * @param array $replaceHosts list of hosts in order which they appear in trigger expression if trigger label is given,
 * or single host when host label is given
 *
 * @return string expanded label
 */
function resolveMapLabelMacros($label, $replaceHosts = null)
{
    // find functional macro pattern
    $pattern = null === $replaceHosts ? '/{' . ZBX_PREG_HOST_FORMAT . ":.+\\.(last|max|min|avg)\\([0-9]+[smhdwKMGT]?\\)}/Uu" : '/{(' . ZBX_PREG_HOST_FORMAT . "|{HOSTNAME[0-9]?}|{HOST.HOST[0-9]?}):.+\\.(last|max|min|avg)\\([0-9]+[smhdwKMGT]?\\)}/Uu";
    preg_match_all($pattern, $label, $matches);
    // for each functional macro
    foreach ($matches[0] as $expr) {
        $macro = $expr;
        if ($replaceHosts !== null) {
            // search for macros with all possible indecies
            foreach ($replaceHosts as $i => $host) {
                $macroTmp = $macro;
                // repalce only macro in first position
                $macro = preg_replace('/{({HOSTNAME' . $i . '}|{HOST.HOST' . $i . '}):(.*)}/U', '{' . $host['host'] . ':$2}', $macro);
                // only one simple macro possible inside functional macro
                if ($macro != $macroTmp) {
                    break;
                }
            }
        }
        // try to create valid expression
        $expressionData = new CTriggerExpression();
        if (!$expressionData->parse($macro) || !isset($expressionData->expressions[0])) {
            continue;
        }
        // look in DB for coressponding item
        $itemHost = $expressionData->expressions[0]['host'];
        $key = $expressionData->expressions[0]['item'];
        $function = $expressionData->expressions[0]['functionName'];
        $parameter = convertFunctionValue($expressionData->expressions[0]['functionParamList'][0]);
        $item = API::Item()->get(array('webitems' => true, 'filter' => array('host' => $itemHost, 'key_' => $key), 'output' => array('lastclock', 'value_type', 'lastvalue', 'units', 'valuemapid')));
        $item = reset($item);
        // if no corresponding item found with functional macro key and host
        if (!$item) {
            $label = str_replace($expr, '???', $label);
            continue;
        }
        // do function type (last, min, max, avg) related actions
        if (0 == strcmp($function, 'last')) {
            if ($item['lastclock'] == 0) {
                $label = str_replace($expr, '(' . _('no data') . ')', $label);
            } else {
                $mapping = false;
                $value = formatItemValueType($item);
                switch ($item['value_type']) {
                    case ITEM_VALUE_TYPE_STR:
                        $mapping = getMappedValue($value, $item['valuemapid']);
                        // break; is not missing here
                    // break; is not missing here
                    case ITEM_VALUE_TYPE_TEXT:
                    case ITEM_VALUE_TYPE_LOG:
                        if ($mapping !== false) {
                            $value = $mapping . ' (' . $value . ')';
                        }
                        break;
                    default:
                        $value = applyValueMap($value, $item['valuemapid']);
                }
            }
            if (isset($value)) {
                $label = str_replace($expr, $value, $label);
            }
        } elseif (0 == strcmp($function, 'min') || 0 == strcmp($function, 'max') || 0 == strcmp($function, 'avg')) {
            // allowed item types for min, max and avg function
            $history_table = array(ITEM_VALUE_TYPE_FLOAT => 'history', ITEM_VALUE_TYPE_UINT64 => 'history_uint');
            if (!isset($history_table[$item['value_type']])) {
                $label = str_replace($expr, '???', $label);
                continue;
            }
            // search for item function data in DB corresponding history tables
            $result = DBselect('SELECT ' . $function . '(value) AS value' . ' FROM ' . $history_table[$item['value_type']] . ' WHERE clock>' . (time() - $parameter) . ' AND itemid=' . zbx_dbstr($item['itemid']));
            if (null === ($row = DBfetch($result))) {
                $label = str_replace($expr, '(' . _('no data') . ')', $label);
            } else {
                $label = str_replace($expr, convert_units($row['value'], $item['units']), $label);
            }
        }
    }
    return $label;
}