public function checkExpression($expression)
 {
     $length = zbx_strlen($expression);
     $symbolNum = 0;
     try {
         if (zbx_empty(trim($expression))) {
             throw new Exception('Empty expression.');
         }
         // Check expr start symbol
         $startSymbol = zbx_substr(trim($expression), 0, 1);
         if ($startSymbol != '(' && $startSymbol != '{' && $startSymbol != '-' && !zbx_ctype_digit($startSymbol)) {
             throw new Exception('Incorrect trigger expression.');
         }
         for ($symbolNum = 0; $symbolNum < $length; $symbolNum++) {
             $symbol = zbx_substr($expression, $symbolNum, 1);
             // SDI($symbol);
             $this->parseOpenParts($this->previous['last']);
             $this->parseCloseParts($symbol);
             // SDII($this->currExpr);
             if ($this->inParameter($symbol)) {
                 $this->setPreviousSymbol($symbol);
                 continue;
             }
             $this->checkSymbolSequence($symbol);
             $this->setPreviousSymbol($symbol);
             // SDII($this->symbols);
         }
         $symbolNum = 0;
         $simpleExpression = $expression;
         $this->checkBraces();
         $this->checkParts($simpleExpression);
         $this->checkSimpleExpression($simpleExpression);
     } catch (Exception $e) {
         $symbolNum = $symbolNum > 0 ? --$symbolNum : $symbolNum;
         $this->errors[] = $e->getMessage();
         $this->errors[] = 'Check expression part starting from " ' . zbx_substr($expression, $symbolNum) . ' "';
     }
 }
Exemple #2
0
function zbx_str2links($text)
{
    $result = array();
    if (zbx_empty($text)) {
        return $result;
    }
    preg_match_all('#https?://[^\\n\\t\\r ]+#u', $text, $matches, PREG_OFFSET_CAPTURE);
    $start = 0;
    foreach ($matches[0] as $match) {
        $result[] = zbx_substr($text, $start, $match[1] - $start);
        $result[] = new CLink($match[0], $match[0], null, null, true);
        $start = $match[1] + zbx_strlen($match[0]);
    }
    $result[] = zbx_substr($text, $start, zbx_strlen($text));
    return $result;
}
$itemFormList->addRow(_('Flexible intervals'), new CDiv($delayFlexTable, 'objectgroup inlineblock border_dotted ui-corner-all'), false, 'row_flex_intervals');
// append new flexible interval to form list
$newFlexInt = new CSpan(array(_('Interval (in sec)'), SPACE, new CNumericBox('new_delay_flex[delay]', $this->data['new_delay_flex']['delay'], 5, 'no', false, false), SPACE, _('Period'), SPACE, new CTextBox('new_delay_flex[period]', $this->data['new_delay_flex']['period'], 20), SPACE, new CButton('add_delay_flex', _('Add'), null, 'formlist')));
$newFlexInt->setAttribute('id', 'row-new-delay-flex-fields');
$maxFlexMsg = new CSpan(_('Maximum number of flexible intervals added'), 'red');
$maxFlexMsg->setAttribute('id', 'row-new-delay-flex-max-reached');
$maxFlexMsg->setAttribute('style', 'display: none;');
$itemFormList->addRow(_('New flexible interval'), array($newFlexInt, $maxFlexMsg), false, 'row_new_delay_flex', 'new');
if ($this->data['is_discovery_rule']) {
    $itemFormList->addRow(_('Keep lost resources period (in days)'), new CTextBox('lifetime', $this->data['lifetime'], ZBX_TEXTBOX_SMALL_SIZE, false, 64));
    // append filter to formlist
    if (!empty($this->data['filter'])) {
        // exploding filter to two parts: before first ':' and after
        $pos = zbx_strpos($this->data['filter'], ':');
        $filter_macro = zbx_substr($this->data['filter'], 0, $pos);
        $filter_value = zbx_substr($this->data['filter'], $pos + 1);
    } else {
        $filter_macro = '';
        $filter_value = '';
    }
    $itemFormList->addRow(_('Filter'), array(_('Macro'), SPACE, new CTextBox('filter_macro', $filter_macro, 13), SPACE, _('Regexp'), SPACE, new CTextBox('filter_value', $filter_value, 20)));
    $itemFormList->addRow(_('Allowed hosts'), new CTextBox('trapper_hosts', $this->data['trapper_hosts'], ZBX_TEXTBOX_STANDARD_SIZE), false, 'row_trapper_hosts');
} else {
    $dataConfig = select_config();
    $keepHistory = array();
    $keepHistory[] = new CNumericBox('history', $this->data['history'], 8);
    if ($dataConfig['hk_history_global'] && !$data['parent_discoveryid'] && !$data['is_template']) {
        $keepHistory[] = SPACE;
        if (CWebUser::getType() == USER_TYPE_SUPER_ADMIN) {
            $keepHistory[] = new CSpan(_x('Overridden by', 'item_form'));
            $keepHistory[] = SPACE;
/**
 * Format item lastvalue depending on it's value type.
 *
 * @param array $item
 *
 * @return string
 */
function formatItemValueType(array $item)
{
    if ($item['value_type'] == ITEM_VALUE_TYPE_FLOAT || $item['value_type'] == ITEM_VALUE_TYPE_UINT64) {
        $value = convert_units($item['lastvalue'], $item['units']);
    } elseif ($item['value_type'] == ITEM_VALUE_TYPE_STR || $item['value_type'] == ITEM_VALUE_TYPE_TEXT || $item['value_type'] == ITEM_VALUE_TYPE_LOG) {
        $value = $item['lastvalue'];
        if (zbx_strlen($value) > 20) {
            $value = zbx_substr($value, 0, 20) . ' ...';
        }
    } else {
        $value = _('Unknown value type');
    }
    return $value;
}
Exemple #5
0
/**
 * Format history value.
 * First format the value according to the configuration of the item. Then apply the value mapping to the formatted (!)
 * value.
 *
 * @param mixed     $value
 * @param array     $item
 * @param int       $item['value_type']     type of the value: ITEM_VALUE_TYPE_FLOAT, ITEM_VALUE_TYPE_UINT64, ...
 * @param string    $item['units']          units of item
 * @param int       $item['valuemapid']     id of mapping set of values
 * @param bool      $trim
 *
 * @return string
 */
function formatHistoryValue($value, array $item, $trim = true)
{
    $mapping = false;
    // format value
    if ($item['value_type'] == ITEM_VALUE_TYPE_FLOAT || $item['value_type'] == ITEM_VALUE_TYPE_UINT64) {
        $value = convert_units(array('value' => $value, 'units' => $item['units']));
    } elseif ($item['value_type'] != ITEM_VALUE_TYPE_STR && $item['value_type'] != ITEM_VALUE_TYPE_TEXT && $item['value_type'] != ITEM_VALUE_TYPE_LOG) {
        $value = _('Unknown value type');
    }
    // apply value mapping
    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 ($trim && zbx_strlen($value) > 20) {
                $value = zbx_substr($value, 0, 20) . '...';
            }
            if ($mapping !== false) {
                $value = $mapping . ' (' . $value . ')';
            }
            break;
        default:
            $value = applyValueMap($value, $item['valuemapid']);
    }
    return $value;
}
/**
 * Creates and returns a trigger status cell for the trigger overview table.
 *
 * @see get_triggers_overview()
 *
 * @param array $triggerHosts	an array with the data about the trigger for each host
 * @param string $hostName		the name of the cells corresponding host
 * @param string $screenId
 *
 * @return CCol
 */
function get_trigger_overview_cells($triggerHosts, $hostName, $screenId = null)
{
    $ack = null;
    $css_class = null;
    $desc = array();
    $config = select_config();
    // for how long triggers should blink on status change (set by user in administration->general)
    if (isset($triggerHosts[$hostName])) {
        // problem trigger
        if ($triggerHosts[$hostName]['value'] == TRIGGER_VALUE_TRUE) {
            $css_class = getSeverityStyle($triggerHosts[$hostName]['priority']);
            $ack = null;
            if ($config['event_ack_enable'] == 1) {
                $event = get_last_event_by_triggerid($triggerHosts[$hostName]['triggerid']);
                if ($event) {
                    if ($screenId) {
                        global $page;
                        $ack_menu = array(_('Acknowledge'), 'acknow.php?eventid=' . $event['eventid'] . '&screenid=' . $screenId . '&backurl=' . $page['file']);
                    } else {
                        $ack_menu = array(_('Acknowledge'), 'acknow.php?eventid=' . $event['eventid'] . '&backurl=overview.php', array('tw' => '_blank'));
                    }
                    if ($event['acknowledged'] == 1) {
                        $ack = new CImg('images/general/tick.png', 'ack');
                    }
                }
            }
        } else {
            $css_class = 'normal';
        }
        $style = 'cursor: pointer; ';
        // set blinking gif as background if trigger age is less then $config['blink_period']
        if ($config['blink_period'] > 0 && time() - $triggerHosts[$hostName]['lastchange'] < $config['blink_period']) {
            $style .= 'background-image: url(images/gradients/blink.gif); background-position: top left; background-repeat: repeat;';
        }
        unset($item_menu);
        $tr_ov_menu = array(array(_('Trigger'), null, null, array('outer' => array('pum_oheader'), 'inner' => array('pum_iheader'))), array(_('Events'), 'events.php?triggerid=' . $triggerHosts[$hostName]['triggerid'], array('tw' => '_blank')));
        if (isset($ack_menu)) {
            $tr_ov_menu[] = $ack_menu;
        }
        $dbItems = DBselect('SELECT DISTINCT i.itemid,i.name,i.key_,i.value_type' . ' FROM items i,functions f' . ' WHERE f.itemid=i.itemid' . ' AND f.triggerid=' . $triggerHosts[$hostName]['triggerid']);
        while ($item = DBfetch($dbItems)) {
            $description = itemName($item);
            switch ($item['value_type']) {
                case ITEM_VALUE_TYPE_UINT64:
                case ITEM_VALUE_TYPE_FLOAT:
                    $action = 'showgraph';
                    $status_bar = _('Show graph of item') . ' \'' . $description . '\'';
                    break;
                case ITEM_VALUE_TYPE_LOG:
                case ITEM_VALUE_TYPE_STR:
                case ITEM_VALUE_TYPE_TEXT:
                default:
                    $action = 'showlatest';
                    $status_bar = _('Show values of item') . ' \'' . $description . '\'';
                    break;
            }
            if (zbx_strlen($description) > 25) {
                $description = zbx_substr($description, 0, 22) . '...';
            }
            $item_menu[$action][] = array($description, 'history.php?action=' . $action . '&itemid=' . $item['itemid'] . '&period=3600', array('tw' => '', 'sb' => $status_bar));
        }
        if (isset($item_menu['showgraph'])) {
            $tr_ov_menu[] = array(_('Graphs'), null, null, array('outer' => array('pum_oheader'), 'inner' => array('pum_iheader')));
            $tr_ov_menu = array_merge($tr_ov_menu, $item_menu['showgraph']);
        }
        if (isset($item_menu['showlatest'])) {
            $tr_ov_menu[] = array(_('Values'), null, null, array('outer' => array('pum_oheader'), 'inner' => array('pum_iheader')));
            $tr_ov_menu = array_merge($tr_ov_menu, $item_menu['showlatest']);
        }
        unset($item_menu);
        // dependency: triggers on which depends this
        $triggerid = !empty($triggerHosts[$hostName]['triggerid']) ? $triggerHosts[$hostName]['triggerid'] : 0;
        $dep_table = new CTableInfo();
        $dep_table->setAttribute('style', 'width: 200px;');
        $dep_table->addRow(bold(_('Depends on') . ':'));
        $dependency = false;
        $dep_res = DBselect('SELECT td.* FROM trigger_depends td WHERE td.triggerid_down=' . $triggerid);
        while ($dep_row = DBfetch($dep_res)) {
            $dep_table->addRow(SPACE . '-' . SPACE . CTriggerHelper::expandDescriptionById($dep_row['triggerid_up']));
            $dependency = true;
        }
        if ($dependency) {
            $img = new Cimg('images/general/arrow_down2.png', 'DEP_DOWN');
            $img->setAttribute('style', 'vertical-align: middle; border: 0px;');
            $img->setHint($dep_table, '', '', false);
            array_push($desc, $img);
        }
        unset($img, $dep_table, $dependency);
        // triggers that depend on this
        $dep_table = new CTableInfo();
        $dep_table->setAttribute('style', 'width: 200px;');
        $dep_table->addRow(bold(_('Dependent') . ':'));
        $dependency = false;
        $dep_res = DBselect('SELECT td.* FROM trigger_depends td WHERE td.triggerid_up=' . $triggerid);
        while ($dep_row = DBfetch($dep_res)) {
            $dep_table->addRow(SPACE . '-' . SPACE . CTriggerHelper::expandDescriptionById($dep_row['triggerid_down']));
            $dependency = true;
        }
        if ($dependency) {
            $img = new Cimg('images/general/arrow_up2.png', 'DEP_UP');
            $img->setAttribute('style', 'vertical-align: middle; border: 0px;');
            $img->setHint($dep_table, '', '', false);
            array_push($desc, $img);
        }
        unset($img, $dep_table, $dependency);
    }
    if (is_array($desc) && count($desc) > 0 || $ack) {
        $tableColumn = new CCol(array($desc, $ack), $css_class . ' hosts');
    } else {
        $tableColumn = new CCol(SPACE, $css_class . ' hosts');
    }
    if (isset($style)) {
        $tableColumn->setAttribute('style', $style);
    }
    if (isset($tr_ov_menu)) {
        $tr_ov_menu = new CPUMenu($tr_ov_menu, 170);
        $tableColumn->onClick($tr_ov_menu->getOnActionJS());
        $tableColumn->addAction('onmouseover', 'jQuery(this).css({border: "1px dotted #0C0CF0", padding: "0 2px"})');
        $tableColumn->addAction('onmouseout', 'jQuery(this).css({border: "", padding: "1px 3px"})');
    }
    return $tableColumn;
}
if (uint_in_array(CWebUser::$data['type'], array(USER_TYPE_ZABBIX_ADMIN, USER_TYPE_SUPER_ADMIN))) {
    $userMediaFormList = new CFormList('userMediaFormList');
    $userForm->addVar('user_medias', $this->data['user_medias']);
    $mediaTableInfo = new CTableInfo(_('No media found.'));
    foreach ($this->data['user_medias'] as $id => $media) {
        if (!isset($media['active']) || !$media['active']) {
            $status = new CLink(_('Enabled'), '#', 'enabled');
            $status->onClick('return create_var("' . $userForm->getName() . '","disable_media",' . $id . ', true);');
        } else {
            $status = new CLink(_('Disabled'), '#', 'disabled');
            $status->onClick('return create_var("' . $userForm->getName() . '","enable_media",' . $id . ', true);');
        }
        $mediaUrl = '?dstfrm=' . $userForm->getName() . '&media=' . $id . '&mediatypeid=' . $media['mediatypeid'] . '&sendto=' . urlencode($media['sendto']) . '&period=' . $media['period'] . '&severity=' . $media['severity'] . '&active=' . $media['active'];
        foreach (getSeverityCaption() as $key => $caption) {
            $mediaActive = $media['severity'] & 1 << $key;
            $mediaSeverity[$key] = new CSpan(zbx_substr($caption, 0, 1), $mediaActive ? 'enabled' : null);
            $mediaSeverity[$key]->setHint($caption . ($mediaActive ? ' (on)' : ' (off)'));
        }
        $mediaTableInfo->addRow(array(new CCheckBox('user_medias_to_del[' . $id . ']', null, null, $id), new CSpan($media['description'], 'nowrap'), new CSpan($media['sendto'], 'nowrap'), new CSpan($media['period'], 'nowrap'), $mediaSeverity, $status, new CButton('edit_media', _('Edit'), 'return PopUp("popup_media.php' . $mediaUrl . '", 550, 400);', 'link_menu')));
    }
    $userMediaFormList->addRow(_('Media'), array($mediaTableInfo, new CButton('add_media', _('Add'), 'return PopUp("popup_media.php?dstfrm=' . $userForm->getName() . '", 550, 400);', 'link_menu'), SPACE, SPACE, count($this->data['user_medias']) > 0 ? new CSubmit('del_user_media', _('Delete selected'), null, 'link_menu') : null));
}
/*
 * Profile fields
 */
if ($this->data['is_profile']) {
    $zbxSounds = getSounds();
    $userMessagingFormList = new CFormList('userMessagingFormList');
    $userMessagingFormList->addRow(_('Frontend messaging'), new CCheckBox('messages[enabled]', $this->data['messages']['enabled'], null, 1));
    $userMessagingFormList->addRow(_('Message timeout (seconds)'), new CNumericBox('messages[timeout]', $this->data['messages']['timeout'], 5), false, 'timeout_row');
    $repeatSound = new CComboBox('messages[sounds.repeat]', $this->data['messages']['sounds.repeat'], 'javascript: if (IE) { submit(); }');
Exemple #8
0
function add_audit_details($action, $resourcetype, $resourceid, $resourcename, $details = null)
{
    if (zbx_strlen($resourcename) > 255) {
        $resourcename = zbx_substr($resourcename, 0, 252) . '...';
    }
    $ip = !empty($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
    $values = array('userid' => CWebUser::$data['userid'], 'clock' => time(), 'ip' => substr($ip, 0, 39), 'action' => $action, 'resourcetype' => $resourcetype, 'resourceid' => $resourceid, 'resourcename' => $resourcename, 'details' => $details);
    try {
        DB::insert('auditlog', array($values));
        return true;
    } catch (DBException $e) {
        return false;
    }
}
function zbx_str2links($text)
{
    // $value = preg_replace('#(https?|ftp|file)://[^\n\t\r ]+#u', '<a href="$0">$0</a>', $value);
    $result = array();
    if (empty($text)) {
        return $result;
    }
    preg_match_all('#https?://[^\\n\\t\\r ]+#u', $text, $matches, PREG_OFFSET_CAPTURE);
    $start = 0;
    foreach ($matches[0] as $match) {
        $result[] = zbx_substr($text, $start, $match[1] - $start);
        $result[] = new CLink($match[0], $match[0], null, null, true);
        $start = $match[1] + zbx_strlen($match[0]);
    }
    $result[] = zbx_substr($text, $start, zbx_strlen($text));
    return $result;
}
 /**
  * Replace macros in trigger description by values.
  * All macros are resolved in one go.
  *
  * @param array $trigger
  * @param array $macroValues
  *
  * @return array
  */
 protected function replaceMacroValues(array $trigger, array $macroValues)
 {
     $macroBegin = false;
     for ($i = 0; $i < zbx_strlen($trigger['description']); $i++) {
         $c = zbx_substr($trigger['description'], $i, 1);
         switch ($c) {
             case '{':
                 $macroBegin = $i;
                 break;
             case '}':
                 if ($macroBegin !== false) {
                     $macro = zbx_substr($trigger['description'], $macroBegin, $i - $macroBegin + 1);
                     if (isset($macroValues[$macro])) {
                         $replace = $macroValues[$macro];
                     } elseif ($this->isAllowedMacro($macro)) {
                         $replace = UNRESOLVED_MACRO_STRING;
                     } else {
                         $replace = false;
                     }
                     if ($replace !== false) {
                         $trigger['description'] = zbx_substr_replace($trigger['description'], $replace, $macroBegin, zbx_strlen($macro));
                         // - 1 because for loop adds 1 on next iteration
                         $i = $macroBegin + zbx_strlen($replace) - 1;
                         $macroBegin = false;
                     }
                 }
                 break;
         }
     }
     return $trigger;
 }
/**
 * Check item key and return info about an error if one is present
 *
 * @param string $key item key, e.g. system.run[cat /etc/passwd | awk -F: '{ print $1 }']
 * @return array
 *
 */
function check_item_key($key)
{
    $key_strlen = zbx_strlen($key);
    //empty string
    if ($key_strlen == 0) {
        return array(false, S_KEY_CANNOT_BE_EMPTY);
    }
    //key is larger then 255 chars
    if ($key_strlen > 255) {
        return array(false, sprintf(S_KEY_TOO_LARGE, 255));
    }
    $characters = array();
    //gathering characters into array, because we can't just work with them ar one if it's a unicode string
    for ($i = 0; $i < $key_strlen; $i++) {
        $characters[] = zbx_substr($key, $i, 1);
    }
    //checking every character, one by one
    for ($current_char = 0; $current_char < $key_strlen; $current_char++) {
        if (!preg_match("/" . ZBX_PREG_KEY_NAME . "/", $characters[$current_char])) {
            break;
            //$current_char now points to a first 'not a key name' char
        }
    }
    //no function specified?
    if ($current_char == $key_strlen) {
        return array('valid' => true, 'description' => S_KEY_IS_VALID);
    } else {
        if ($characters[$current_char] == '[') {
            $state = 0;
            //0 - initial, 1 - inside quoted param, 2 - inside unquoted param
            $nest_level = 0;
            //for every char, starting after '['
            for ($i = $current_char + 1; $i < $key_strlen; $i++) {
                switch ($state) {
                    //initial state
                    case 0:
                        if ($characters[$i] == ',') {
                            //do nothing
                        } else {
                            if ($characters[$i] == ']' && isset($characters[$i + 1]) && $characters[$i + 1] == '[' && $nest_level == 0) {
                                $i++;
                            } else {
                                if ($characters[$i] == '"') {
                                    $state = 1;
                                } else {
                                    if ($characters[$i] == '[') {
                                        $nest_level++;
                                    } else {
                                        if ($characters[$i] == ']' && $nest_level != 0) {
                                            $nest_level--;
                                            //skipping spaces
                                            while (isset($characters[$i + 1]) && $characters[$i + 1] == ' ') {
                                                $i++;
                                            }
                                            //all nestings are closed correctly
                                            if ($nest_level == 0 && isset($characters[$i + 1]) && $characters[$i + 1] == ']' && !isset($characters[$i + 2])) {
                                                return array('valid' => true, 'description' => S_KEY_IS_VALID);
                                            }
                                            if ((!isset($characters[$i + 1]) || $characters[$i + 1] != ',') && !($nest_level != 0 && isset($characters[$i + 1]) && $characters[$i + 1] == ']')) {
                                                return array('valid' => false, 'description' => sprintf(S_INCORRECT_SYNTAX_NEAR, $characters[$current_char], $current_char));
                                            }
                                        } else {
                                            if ($characters[$i] == ']' && $nest_level == 0) {
                                                if (isset($characters[$i + 1])) {
                                                    return array('valid' => false, 'description' => sprintf(S_INCORRECT_USAGE_OF_BRACKETS, $characters[$i + 1]));
                                                } else {
                                                    return array('valid' => true, 'description' => S_KEY_IS_VALID);
                                                }
                                            } else {
                                                if ($characters[$i] != ' ') {
                                                    $state = 2;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        break;
                        //quoted
                    //quoted
                    case 1:
                        //ending quote is reached
                        if ($characters[$i] == '"') {
                            //skipping spaces
                            while (isset($characters[$i + 1]) && $characters[$i + 1] == ' ') {
                                $i++;
                            }
                            //Zapcat
                            if ($nest_level == 0 && isset($characters[$i + 1]) && isset($characters[$i + 2]) && $characters[$i + 1] == ']' && $characters[$i + 2] == '[') {
                                $state = 0;
                                break;
                            }
                            if ($nest_level == 0 && isset($characters[$i + 1]) && $characters[$i + 1] == ']' && !isset($characters[$i + 2])) {
                                return array('valid' => true, 'description' => S_KEY_IS_VALID);
                            } else {
                                if ($nest_level == 0 && $characters[$i + 1] == ']' && isset($characters[$i + 2])) {
                                    return array('valid' => false, 'description' => sprintf(S_INCORRECT_USAGE_OF_BRACKETS, $characters[$i + 2]));
                                }
                            }
                            if ((!isset($characters[$i + 1]) || $characters[$i + 1] != ',') && !($nest_level != 0 && isset($characters[$i + 1]) && $characters[$i + 1] == ']')) {
                                return array('valid' => false, 'description' => sprintf(S_INCORRECT_SYNTAX_NEAR, $characters[$current_char], $current_char));
                            }
                            $state = 0;
                        } else {
                            if ($characters[$i] == '\\' && isset($characters[$i + 1]) && $characters[$i + 1] == '"') {
                                $i++;
                            }
                        }
                        break;
                        //unquoted
                    //unquoted
                    case 2:
                        //Zapcat
                        if ($nest_level == 0 && $characters[$i] == ']' && isset($characters[$i + 1]) && $characters[$i + 1] == '[') {
                            $i--;
                            $state = 0;
                        } else {
                            if ($characters[$i] == ',' || $characters[$i] == ']' && $nest_level != 0) {
                                $i--;
                                $state = 0;
                            } else {
                                if ($characters[$i] == ']' && $nest_level == 0) {
                                    if (isset($characters[$i + 1])) {
                                        return array('valid' => false, 'description' => sprintf(S_INCORRECT_USAGE_OF_BRACKETS, $characters[$i + 1]));
                                    } else {
                                        return array('valid' => true, 'description' => S_KEY_IS_VALID);
                                    }
                                }
                            }
                        }
                        break;
                }
            }
            return array('valid' => false, 'description' => S_INVALID_KEY_FORMAT);
        } else {
            return array('valid' => false, 'description' => sprintf(S_INVALID_CHARACTER_AT_POSITION, $characters[$current_char], $current_char));
        }
    }
}
function rebuild_expression_tree($expression, &$treeLevel, $action, $actionid, $newPart)
{
    $newExp = '';
    $lastLevel = true;
    if ($actionid != $treeLevel['openSymbolNum'] . '_' . $treeLevel['closeSymbolNum'] && ($treeLevel['levelType'] == 'independent' || $treeLevel['levelType'] == 'grouping')) {
        $sStart = !isset($treeLevel['openSymbol']) ? $treeLevel['openSymbolNum'] : $treeLevel['openSymbolNum'] + zbx_strlen($treeLevel['openSymbol']);
        $sEnd = !isset($treeLevel['closeSymbol']) ? $treeLevel['closeSymbolNum'] : $treeLevel['closeSymbolNum'] - zbx_strlen($treeLevel['closeSymbol']);
        /*$sStart = $treeLevel['levelType'] == 'independent' ? $treeLevel['openSymbolNum'] : $treeLevel['openSymbolNum']+(isset($treeLevel['openSymbol']) ? zbx_strlen($treeLevel['openSymbol']) : 0);
        		$sEnd = $treeLevel['levelType'] == 'independent' ? $treeLevel['closeSymbolNum']+1 : $treeLevel['closeSymbolNum'];*/
        //			SDI("Total start: {$sStart}; Total end: {$sEnd};");
        if (isset($treeLevel['parts'])) {
            $parts =& $treeLevel['parts'];
        } else {
            $parts = array();
        }
        $fPart = reset($parts);
        if (count($parts) == 1 && $sStart == $fPart['openSymbolNum'] && $sEnd == $fPart['closeSymbolNum']) {
            return (isset($fPart['openSymbol']) && $fPart['levelType'] == 'grouping' ? $fPart['openSymbol'] : '') . trim(rebuild_expression_tree($expression, $fPart, $action, $actionid, $newPart)) . (isset($fPart['closeSymbol']) && $fPart['levelType'] == 'grouping' ? $fPart['closeSymbol'] : '');
        }
        $operand = '|';
        reset($parts);
        $bParts = array();
        $opPos = find_next_operand($expression, $sStart, $sEnd, $parts, $bParts, $operand);
        if (!is_int($opPos) || $opPos >= $sEnd) {
            $operand = '&';
            reset($parts);
            $bParts = array();
            $opPos = find_next_operand($expression, $sStart, $sEnd, $parts, $bParts, $operand);
        }
        if (is_int($opPos) && $opPos < $sEnd) {
            $lastLevel = false;
            $prev = $sStart;
            $levelNewExpression = array();
            while (is_int($opPos) && $opPos < $sEnd || $prev < $sEnd) {
                unset($newTreeLevel);
                if (count($bParts) == 1) {
                    $fbPart = reset($bParts);
                }
                if (count($bParts) == 1 && zbx_substr($expression, $fbPart['openSymbolNum'], $fbPart['closeSymbolNum'] - $fbPart['openSymbolNum'] + (isset($fbPart['closeSymbol']) ? zbx_strlen($fbPart['closeSymbol']) : 0)) == trim(zbx_substr($expression, $prev + ($prev > $sStart ? zbx_strlen($operand) : 0), (is_int($opPos) && $opPos < $sEnd ? $opPos - zbx_strlen($operand) : $sEnd) - $prev))) {
                    $newTreeLevel =& $bParts[key($bParts)];
                } else {
                    $newTreeLevel = array('levelType' => 'grouping', 'openSymbolNum' => $prev + ($prev > $sStart ? zbx_strlen($operand) : 0), 'closeSymbolNum' => is_int($opPos) && $opPos < $sEnd ? $opPos - zbx_strlen($operand) : $sEnd);
                    if (is_array($bParts) && count($bParts) > 0) {
                        $newTreeLevel['parts'] =& $bParts;
                    }
                }
                //					SDI("{$treeLevel['levelType']} parts:".count($treeLevel['parts']));
                unset($bParts);
                $bParts = array();
                $prev = is_int($opPos) && $opPos < $sEnd ? $opPos : $sEnd;
                $opPos = find_next_operand($expression, $prev + zbx_strlen($operand), $sEnd, $parts, $bParts, $operand);
                //					SDI('>>>>>>>>>>>>>>>>>>>newTreeLevel parts count:'.(isset($newTreeLevel['parts']) ? count($newTreeLevel['parts']): 0));
                //					if(isset($newTreeLevel['parts'])) SDII($newTreeLevel['parts']);
                $newLevelExpression = rebuild_expression_tree($expression, $newTreeLevel, $action, $actionid, $newPart);
                if ($newLevelExpression) {
                    $levelNewExpression[] = (isset($newTreeLevel['openSymbol']) && $newTreeLevel['levelType'] == 'grouping' ? $newTreeLevel['openSymbol'] : '') . trim($newLevelExpression) . (isset($newTreeLevel['closeSymbol']) && $newTreeLevel['levelType'] == 'grouping' ? $newTreeLevel['closeSymbol'] : '');
                }
                //					SDI("After {$treeLevel['levelType']} parts:".count($treeLevel['parts']));
            }
            $newExp .= implode(' ' . $operand . ' ', $levelNewExpression);
        }
    }
    if ($lastLevel) {
        $curLevelVal = trim(zbx_substr($expression, $treeLevel['openSymbolNum'], $treeLevel['closeSymbolNum'] - $treeLevel['openSymbolNum'] + 1));
        if ($actionid == $treeLevel['openSymbolNum'] . '_' . $treeLevel['closeSymbolNum']) {
            switch ($action) {
                case 'R':
                    /* remove */
                    break;
                case 'r':
                    /* Replace */
                    $newExp .= $newPart;
                    break;
                case '&':
                    /* add */
                /* add */
                case '|':
                    /* add */
                    $newExp .= $curLevelVal . ' ' . $action . ' ' . $newPart;
                    break;
            }
        } else {
            $newExp .= $curLevelVal;
        }
    }
    //		SDI("<<<<<<<<<<<<<<<<<<<<<<<<< New expression return: {$newExp}");
    return $newExp;
}