/** * 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; }
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; }
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 {
/** * 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'])); } } }
/** * 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; }
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])) {
/** * 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; }
/** * 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); }
$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');
/** * 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';
/** * 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'])); } }
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; }