disableCsrfValidation(); } protected function checkInput() { $fields = [ 'type' => 'required|in history,host,item,item_prototype,map_element,trigger,trigger_macro', 'data' => 'array' ]; $ret = $this->validateInput($fields) && $this->validateInputData(); if (!$ret) { $this->setResponse( new CControllerResponseData(['main_block' => json_encode([ 'error' => [ 'messages' => array_column(get_and_clear_messages(), 'message') ] ])]) ); } return $ret; } protected function validateInputData(): bool { $type = $this->getInput('type'); switch ($type) { case 'host': $rules = [ 'hostid' => 'required|db hosts.hostid', 'has_goto' => 'in 0' ]; break; case 'history': $rules = [ 'itemid' => 'required|db items.itemid' ]; break; case 'item': case 'item_prototype': $rules = [ 'itemid' => 'required|db items.itemid', 'backurl' => 'required|string' ]; break; case 'map_element': $rules = [ 'sysmapid' => 'required|db sysmaps.sysmapid', 'selementid' => 'required|db sysmaps_elements.selementid', 'unique_id' => 'string', 'severity_min' => 'in '.implode(',', [TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_INFORMATION, TRIGGER_SEVERITY_WARNING, TRIGGER_SEVERITY_AVERAGE, TRIGGER_SEVERITY_HIGH, TRIGGER_SEVERITY_DISASTER]), 'hostid' => 'db hosts.hostid' ]; break; case 'trigger': $rules = [ 'triggerid' => 'required|db triggers.triggerid', 'backurl' => 'required|string', 'eventid' => 'db events.eventid', 'show_update_problem' => 'in 0,1', 'show_rank_change_cause' => 'in 0,1', 'show_rank_change_symptom' => 'in 0,1', 'ids' => 'array_db events.eventid' ]; break; case 'trigger_macro': $rules = []; break; } $this->input['data'] = array_intersect_key($this->getInput('data', []), $rules); $validator = new CNewValidator($this->input['data'], $rules); array_map('error', $validator->getAllErrors()); return !$validator->isError() && !$validator->isErrorFatal(); } protected function checkPermissions() { return true; } /** * Prepare data for history context menu popup. * * @param array $data * @param string $data['itemid'] * * @return mixed */ private static function getMenuDataHistory(array $data) { $db_items = API::Item()->get([ 'output' => ['value_type'], 'itemids' => $data['itemid'], 'webitems' => true ]); if ($db_items) { $db_item = $db_items[0]; return [ 'type' => 'history', 'itemid' => $data['itemid'], 'hasLatestGraphs' => in_array($db_item['value_type'], [ITEM_VALUE_TYPE_UINT64, ITEM_VALUE_TYPE_FLOAT]), 'allowed_ui_latest_data' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_LATEST_DATA) ]; } error(_('No permissions to referred object or it does not exist!')); return null; } /** * Prepare data for host context menu popup. * * @param array $data * @param string $data['hostid'] * @param bool $data['has_goto'] (optional) Can be used to hide "GO TO" menu section. Default: true. * @param int $data['severity_min'] (optional) * @param bool $data['show_suppressed'] (optional) * @param array $data['tags'] (optional) * @param array $data['evaltype'] (optional) * @param array $data['urls'] (optional) * @param string $data['urls']['label'] * @param string $data['urls']['url'] * * @return mixed */ private static function getMenuDataHost(array $data) { $has_goto = !array_key_exists('has_goto', $data) || $data['has_goto']; $db_hosts = $has_goto ? API::Host()->get([ 'output' => ['hostid', 'status'], 'selectGraphs' => API_OUTPUT_COUNT, 'selectHttpTests' => API_OUTPUT_COUNT, 'hostids' => $data['hostid'] ]) : API::Host()->get([ 'output' => ['hostid'], 'hostids' => $data['hostid'] ]); if ($db_hosts) { $db_host = $db_hosts[0]; $rw_hosts = false; if ($has_goto && CWebUser::getType() > USER_TYPE_ZABBIX_USER) { $rw_hosts = (bool) API::Host()->get([ 'output' => [], 'hostids' => $db_host['hostid'], 'editable' => true ]); } $all_scripts = CWebUser::checkAccess(CRoleHelper::ACTIONS_EXECUTE_SCRIPTS) ? API::Script()->getScriptsByHosts([$data['hostid']])[$data['hostid']] : []; $scripts = []; $urls = []; if (array_key_exists('urls', $data)) { foreach ($data['urls'] as &$url) { $url['new_window'] = ZBX_SCRIPT_URL_NEW_WINDOW_YES; $url['confirmation'] = ''; $url['menu_path'] = ''; $url['name'] = $url['label']; unset($url['label']); } unset($url); $urls = $data['urls']; } if ($all_scripts) { foreach ($all_scripts as $num => $script) { // Filter only host scope scripts, get rid of excess spaces and unify slashes in menu path. if ($script['scope'] != ZBX_SCRIPT_SCOPE_HOST) { unset($all_scripts[$num]); continue; } // Split scripts and URLs. if ($script['type'] == ZBX_SCRIPT_TYPE_URL) { $urls[] = $script; } else { $scripts[] = $script; } } $scripts = self::sortEntitiesByMenuPath($scripts); $urls = self::sortEntitiesByMenuPath($urls); } $menu_data = [ 'type' => 'host', 'hostid' => $data['hostid'], 'hasGoTo' => (bool) $has_goto, 'allowed_ui_inventory' => CWebUser::checkAccess(CRoleHelper::UI_INVENTORY_HOSTS), 'allowed_ui_latest_data' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_LATEST_DATA), 'allowed_ui_problems' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_PROBLEMS), 'allowed_ui_hosts' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_HOSTS), 'allowed_ui_conf_hosts' => CWebUser::checkAccess(CRoleHelper::UI_CONFIGURATION_HOSTS), 'csrf_token' => CCsrfTokenHelper::get('scriptexec') ]; if ($has_goto) { $menu_data['showGraphs'] = (bool) $db_host['graphs']; $menu_data['showDashboards'] = (bool) getHostDashboards($data['hostid']); $menu_data['showWeb'] = (bool) $db_host['httpTests']; $menu_data['isWriteable'] = $rw_hosts; $menu_data['showTriggers'] = ($db_host['status'] == HOST_STATUS_MONITORED); if (array_key_exists('severity_min', $data)) { $menu_data['severities'] = array_column( CSeverityHelper::getSeverities((int) $data['severity_min']), 'value' ); } if (array_key_exists('show_suppressed', $data)) { $menu_data['show_suppressed'] = $data['show_suppressed']; } } foreach (array_values($scripts) as $script) { $menu_data['scripts'][] = [ 'name' => $script['name'], 'menu_path' => $script['menu_path'], 'scriptid' => $script['scriptid'], 'confirmation' => $script['confirmation'] ]; } foreach (array_values($urls) as $url) { $menu_data['urls'][] = [ 'label' => $url['name'], 'menu_path' => $url['menu_path'], 'url' => $url['url'], 'target' => $url['new_window'] == ZBX_SCRIPT_URL_NEW_WINDOW_YES ? '_blank' : '', 'confirmation' => $url['confirmation'], 'rel' => 'noopener'.(ZBX_NOREFERER ? ' noreferrer' : '') ]; } if (array_key_exists('urls', $menu_data)) { foreach ($menu_data['urls'] as &$url) { if (!CHtmlUrlValidator::validate($url['url'], ['allow_user_macro' => false])) { $url['url'] = 'javascript: alert('. json_encode(_s('Provided URL "%1$s" is invalid.', $url['url'])). ');'; unset($url['target'], $url['rel']); } } unset($url); } if (array_key_exists('tags', $data)) { $menu_data['tags'] = $data['tags']; $menu_data['evaltype'] = $data['evaltype']; } return $menu_data; } error(_('No permissions to referred object or it does not exist!')); return null; } /** * Prepare data for item latest data context menu popup. * * @param array $data * @param string $data['itemid'] * * @return mixed */ private static function getMenuDataItem(array $data) { $db_items = API::Item()->get([ 'output' => ['hostid', 'key_', 'name', 'flags', 'type', 'value_type', 'history', 'trends'], 'selectHosts' => ['host'], 'selectTriggers' => ['triggerid', 'description'], 'itemids' => $data['itemid'], 'webitems' => true ]); if ($db_items) { $db_item = $db_items[0]; $is_writable = false; $is_executable = false; if ($db_item['type'] != ITEM_TYPE_HTTPTEST) { if (CWebUser::getType() == USER_TYPE_SUPER_ADMIN) { $is_writable = true; } elseif (CWebUser::getType() == USER_TYPE_ZABBIX_ADMIN) { $is_writable = (bool) API::Host()->get([ 'output' => ['hostid'], 'hostids' => $db_item['hostid'], 'editable' => true ]); } } if (in_array($db_item['type'], checkNowAllowedTypes())) { $is_executable = $is_writable ? true : CWebUser::checkAccess(CRoleHelper::ACTIONS_INVOKE_EXECUTE_NOW); } return [ 'type' => 'item', 'backurl' => $data['backurl'], 'itemid' => $data['itemid'], 'name' => $db_item['name'], 'key' => $db_item['key_'], 'hostid' => $db_item['hostid'], 'host' => $db_item['hosts'][0]['host'], 'triggers' => $db_item['triggers'], 'showGraph' => ($db_item['value_type'] == ITEM_VALUE_TYPE_FLOAT || $db_item['value_type'] == ITEM_VALUE_TYPE_UINT64 ), 'history' => $db_item['history'] != 0, 'trends' => $db_item['trends'] != 0, 'isDiscovery' => $db_item['flags'] == ZBX_FLAG_DISCOVERY_CREATED, 'isExecutable' => $is_executable, 'isWriteable' => $is_writable, 'allowed_ui_latest_data' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_LATEST_DATA), 'allowed_ui_conf_hosts' => CWebUser::checkAccess(CRoleHelper::UI_CONFIGURATION_HOSTS), 'binary_value_type' => $db_item['value_type'] == ITEM_VALUE_TYPE_BINARY ]; } error(_('No permissions to referred object or it does not exist!')); return null; } /** * Prepare data for item prototype configuration context menu popup. * * @param array $data * @param string $data['itemid'] * @param string $data['backurl'] * * @return mixed */ private static function getMenuDataItemPrototype(array $data) { $db_item_prototypes = API::ItemPrototype()->get([ 'output' => ['name', 'key_'], 'selectDiscoveryRule' => ['itemid'], 'selectHosts' => ['host'], 'selectTriggers' => ['triggerid', 'description'], 'itemids' => $data['itemid'] ]); if ($db_item_prototypes) { $db_item_prototype = $db_item_prototypes[0]; $menu_data = [ 'type' => 'item_prototype', 'backurl' => $data['backurl'], 'itemid' => $data['itemid'], 'name' => $db_item_prototype['name'], 'key' => $db_item_prototype['key_'], 'host' => $db_item_prototype['hosts'][0]['host'], 'parent_discoveryid' => $db_item_prototype['discoveryRule']['itemid'], 'trigger_prototypes' => $db_item_prototype['triggers'] ]; return $menu_data; } error(_('No permissions to referred object or it does not exist!')); return null; } /** * Validates URLs for supported schemes. * * @param array $urls * @param array $urls[]['url'] * * @return array */ private static function sanitizeMapElementUrls(array $urls): array { foreach ($urls as &$url) { if (CHtmlUrlValidator::validate($url['url'], ['allow_user_macro' => false]) === false) { $url['url'] = 'javascript: alert('.json_encode(_s('Provided URL "%1$s" is invalid.', $url['url'])).');'; } } unset($url); return $urls; } /** * Combines map URLs with element's URLs and performs other modifications with the URLs. * * @param array $selement * @param array $map_urls * * @return array */ private static function prepareMapElementUrls(array $selement, array $map_urls) { // Remove unused selement url data. foreach ($selement['urls'] as &$url) { unset($url['sysmapelementurlid'], $url['selementid']); } unset($url); // Add map urls to element's urls based on their type. foreach ($map_urls as $map_url) { if ($selement['elementtype'] == $map_url['elementtype']) { unset($map_url['elementtype']); $selement['urls'][] = $map_url; } } $selement = CMacrosResolverHelper::resolveMacrosInMapElements([$selement], ['resolve_element_urls' => true])[0]; // Unset URLs with empty name or value. foreach ($selement['urls'] as $url_nr => $url) { if ($url['name'] === '' || $url['url'] === '') { unset($selement['urls'][$url_nr]); } } CArrayHelper::sort($selement['urls'], ['name']); $selement['urls'] = array_values($selement['urls']); // Prepare urls for processing in menupopup.js. $selement['urls'] = CArrayHelper::renameObjectsKeys($selement['urls'], ['name' => 'label']); return $selement; } /** * Prepare data for map element context menu popup. * * @param array $data * @param string $data['sysmapid'] * @param string $data['selementid'] * @param int $data['severity_min'] (optional) * @param int $data['unique_id'] (optional) * @param string $data['hostid'] (optional) * * @return mixed */ private static function getMenuDataMapElement(array $data) { $db_maps = API::Map()->get([ 'output' => ['show_suppressed'], 'selectSelements' => ['selementid', 'elementtype', 'elementsubtype', 'elements', 'urls', 'tags', 'evaltype' ], 'selectUrls' => ['name', 'url', 'elementtype'], 'sysmapids' => $data['sysmapid'] ]); if ($db_maps) { $db_map = $db_maps[0]; $selement = null; foreach ($db_map['selements'] as $db_selement) { if (bccomp($db_selement['selementid'], $data['selementid']) == 0) { $selement = $db_selement; break; } } if ($selement !== null) { if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST_GROUP && $selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS && array_key_exists('hostid', $data) && $data['hostid'] != 0) { $selement['elementtype'] = SYSMAP_ELEMENT_TYPE_HOST; $selement['elementsubtype'] = SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP; $selement['elements'][0]['hostid'] = $data['hostid']; } $selement = self::prepareMapElementUrls($selement, $db_map['urls']); switch ($selement['elementtype']) { case SYSMAP_ELEMENT_TYPE_MAP: $menu_data = [ 'type' => 'map_element_submap', 'sysmapid' => $selement['elements'][0]['sysmapid'], 'allowed_ui_maps' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_MAPS) ]; if (array_key_exists('severity_min', $data)) { $menu_data['severity_min'] = $data['severity_min']; } if (array_key_exists('unique_id', $data)) { $menu_data['unique_id'] = $data['unique_id']; } if ($selement['urls']) { $menu_data['urls'] = self::sanitizeMapElementUrls($selement['urls']); } return $menu_data; case SYSMAP_ELEMENT_TYPE_HOST_GROUP: $menu_data = [ 'type' => 'map_element_group', 'groupid' => $selement['elements'][0]['groupid'], 'allowed_ui_problems' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_PROBLEMS) ]; if (array_key_exists('severity_min', $data)) { $menu_data['severities'] = array_column( CSeverityHelper::getSeverities((int) $data['severity_min']), 'value' ); } if ($db_map['show_suppressed']) { $menu_data['show_suppressed'] = true; } if ($selement['urls']) { $menu_data['urls'] = self::sanitizeMapElementUrls($selement['urls']); } if ($selement['tags']) { $menu_data['evaltype'] = $selement['evaltype']; $menu_data['tags'] = $selement['tags']; } return $menu_data; case SYSMAP_ELEMENT_TYPE_HOST: $host_data = [ 'hostid' => $selement['elements'][0]['hostid'] ]; if (array_key_exists('severity_min', $data)) { $host_data['severity_min'] = $data['severity_min']; } if ($db_map['show_suppressed']) { $host_data['show_suppressed'] = true; } if ($selement['urls']) { $host_data['urls'] = $selement['urls']; } if ($selement['tags']) { $host_data['evaltype'] = $selement['evaltype']; $host_data['tags'] = $selement['tags']; } return self::getMenuDataHost($host_data); case SYSMAP_ELEMENT_TYPE_TRIGGER: $items = []; $triggers = []; $hosts = []; $show_events = true; $unique_itemids = []; $db_triggers = API::Trigger()->get([ 'output' => ['triggerid', 'description'], 'selectHosts' => ['hostid', 'name', 'status'], 'selectItems' => ['itemid', 'hostid', 'name', 'value_type', 'type'], 'triggerids' => array_column($selement['elements'], 'triggerid'), 'preservekeys' => true ]); foreach ($db_triggers as $db_trigger) { foreach ($db_trigger['hosts'] as $host) { $hosts[$host['hostid']] = $host['name']; } foreach ($db_trigger['items'] as &$item) { $item['hostname'] = $hosts[$item['hostid']]; if ($host['status'] != HOST_STATUS_MONITORED) { $show_events = false; } } unset($item); CArrayHelper::sort($db_trigger['items'], ['name', 'hostname', 'itemid']); $with_hostname = count($hosts) > 1; foreach ($db_trigger['items'] as $item) { if (in_array($item['itemid'], $unique_itemids)) { continue; } $items[] = [ 'name' => $with_hostname ? $item['hostname'].NAME_DELIMITER.$item['name'] : $item['name'], 'params' => [ 'itemid' => $item['itemid'], 'action' => in_array( $item['value_type'], [ITEM_VALUE_TYPE_FLOAT, ITEM_VALUE_TYPE_UINT64] ) ? HISTORY_GRAPH : HISTORY_VALUES, 'is_webitem' => $item['type'] == ITEM_TYPE_HTTPTEST ] ]; $unique_itemids[] = $item['itemid']; } $triggers[] = [ 'triggerid' => $db_trigger['triggerid'], 'description' => $db_trigger['description'] ]; } $menu_data = [ 'type' => 'map_element_trigger', 'triggers' => $triggers, 'items' => $items, 'show_events' => $show_events, 'allowed_ui_problems' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_PROBLEMS), 'allowed_ui_conf_hosts' => CWebUser::checkAccess(CRoleHelper::UI_CONFIGURATION_HOSTS), 'allowed_ui_latest_data' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_LATEST_DATA) ]; if (array_key_exists('severity_min', $data)) { $menu_data['severities'] = array_column( CSeverityHelper::getSeverities((int) $data['severity_min']), 'value' ); } if ($db_map['show_suppressed']) { $menu_data['show_suppressed'] = true; } if ($selement['urls']) { $menu_data['urls'] = self::sanitizeMapElementUrls($selement['urls']); } return $menu_data; case SYSMAP_ELEMENT_TYPE_IMAGE: $menu_data = [ 'type' => 'map_element_image' ]; if ($selement['urls']) { $menu_data['urls'] = self::sanitizeMapElementUrls($selement['urls']); } return $menu_data; } } } error(_('No permissions to referred object or it does not exist!')); return null; } /** * Prepare data for trigger context menu popup. * * @param array $data * string $data['triggerid'] Trigger ID. * string $data['backurl'] URL from where the menu popup was called. * string $data['eventid'] (optional) Mandatory for "Update problem", "Mark as cause" * and "Mark selected as symptoms" context menus. * array $data['ids'] (optional) Event IDs that are used in event rank change to * symptom. * bool $data['show_update_problem'] (optional) Whether to show "Update problem". * bool $data['show_rank_change_cause'] (optional) Whether to show "Mark as cause". * bool $data['show_rank_change_symptom'] (optional) Whether to show "Mark selected as symptoms". * * @return array|null */ private static function getMenuDataTrigger(array $data): ?array { $db_triggers = API::Trigger()->get([ 'output' => ['expression', 'url_name', 'url', 'comments', 'manual_close'], 'selectHosts' => ['hostid', 'name', 'status'], 'selectItems' => ['itemid', 'hostid', 'name', 'value_type', 'type'], 'triggerids' => $data['triggerid'], 'preservekeys' => true ]); if ($db_triggers) { $db_trigger = reset($db_triggers); if (array_key_exists('eventid', $data)) { $db_trigger['eventid'] = $data['eventid']; } $db_trigger['url'] = CMacrosResolverHelper::resolveTriggerUrl($db_trigger, $url) ? $url : ''; if ($db_trigger['url'] !== '') { $db_trigger['url_name'] = CMacrosResolverHelper::resolveTriggerUrlName($db_trigger, $url_name) ? $url_name : ''; } $hosts = []; $show_events = true; foreach ($db_trigger['hosts'] as $host) { $hosts[$host['hostid']] = $host['name']; if ($host['status'] != HOST_STATUS_MONITORED) { $show_events = false; } } foreach ($db_trigger['items'] as &$item) { $item['hostname'] = $hosts[$item['hostid']]; } unset($item); CArrayHelper::sort($db_trigger['items'], ['name', 'hostname', 'itemid']); $with_hostname = count($hosts) > 1; $items = []; foreach ($db_trigger['items'] as $item) { $items[] = [ 'name' => $with_hostname ? $item['hostname'].NAME_DELIMITER.$item['name'] : $item['name'], 'params' => [ 'itemid' => $item['itemid'], 'action' => in_array($item['value_type'], [ITEM_VALUE_TYPE_FLOAT, ITEM_VALUE_TYPE_UINT64]) ? HISTORY_GRAPH : HISTORY_VALUES, 'is_webitem' => $item['type'] == ITEM_TYPE_HTTPTEST ] ]; } $menu_data = [ 'type' => 'trigger', 'triggerid' => $data['triggerid'], 'backurl' => $data['backurl'], 'items' => $items, 'show_events' => $show_events, 'allowed_ui_problems' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_PROBLEMS), 'allowed_ui_conf_hosts' => CWebUser::checkAccess(CRoleHelper::UI_CONFIGURATION_HOSTS), 'allowed_ui_latest_data' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_LATEST_DATA), 'allowed_actions_change_problem_ranking' => CWebUser::checkAccess(CRoleHelper::ACTIONS_CHANGE_PROBLEM_RANKING) ]; $can_be_closed = ($db_trigger['manual_close'] == ZBX_TRIGGER_MANUAL_CLOSE_ALLOWED && CWebUser::checkAccess(CRoleHelper::ACTIONS_CLOSE_PROBLEMS) ); $event = []; if (array_key_exists('eventid', $data)) { $menu_data['eventid'] = $data['eventid']; $events = API::Event()->get([ 'output' => ['eventid', 'r_eventid', 'urls', 'cause_eventid'], 'selectAcknowledges' => ['action'], 'eventids' => $data['eventid'] ]); if ($events) { $event = $events[0]; if ($can_be_closed) { $can_be_closed = !isEventClosed($event); } if (CWebUser::checkAccess(CRoleHelper::ACTIONS_CHANGE_PROBLEM_RANKING)) { // Can change rank to cause if event is not already cause. $menu_data['mark_as_cause'] = ($event['cause_eventid'] != 0); // Check if selected events can change rank to symptom for given cause. $menu_data['mark_selected_as_symptoms'] = array_key_exists('ids', $data) && $data['ids'] ? (bool) validateEventRankChangeToSymptom($data['ids'], $data['eventid']) : false; $menu_data['eventids'] = array_key_exists('ids', $data) ? $data['ids'] : []; // Show individual menus depending on location. $menu_data['show_rank_change_cause'] = array_key_exists('show_rank_change_cause', $data) && $data['show_rank_change_cause']; $menu_data['show_rank_change_symptom'] = array_key_exists('show_rank_change_symptom', $data) && $data['show_rank_change_symptom']; $menu_data['csrf_tokens']['acknowledge'] = CCsrfTokenHelper::get('acknowledge'); } } } if (array_key_exists('show_update_problem', $data)) { $menu_data['show_update_problem'] = $data['show_update_problem'] && (CWebUser::checkAccess(CRoleHelper::ACTIONS_ADD_PROBLEM_COMMENTS) || CWebUser::checkAccess(CRoleHelper::ACTIONS_CHANGE_SEVERITY) || CWebUser::checkAccess(CRoleHelper::ACTIONS_ACKNOWLEDGE_PROBLEMS) || $can_be_closed || CWebUser::checkAccess(CRoleHelper::ACTIONS_SUPPRESS_PROBLEMS) ); } $scripts_by_events = []; if (CWebUser::checkAccess(CRoleHelper::ACTIONS_EXECUTE_SCRIPTS) && $event) { $scripts_by_events = API::Script()->getScriptsByEvents([$event['eventid']]); } // Filter only event scope scripts and get rid of excess spaces and create full name with menu path included. $scripts = []; $urls = []; foreach ($scripts_by_events as &$event_scripts) { foreach ($event_scripts as $num => &$event_script) { if ($event_script['scope'] != ZBX_SCRIPT_SCOPE_EVENT) { unset($event_script[$num]); continue; } $scriptid = $event_script['scriptid']; // Split scripts and URLs. if ($event_script['type'] == ZBX_SCRIPT_TYPE_URL) { if (!array_key_exists($scriptid, $urls)) { $urls[$scriptid] = $event_script; } } else { if (!array_key_exists($scriptid, $scripts)) { $scripts[$scriptid] = $event_script; } } } unset($event_script); } unset($event_scripts); if ($event) { foreach ($event['urls'] as &$url) { $url['new_window'] = ZBX_SCRIPT_URL_NEW_WINDOW_YES; $url['confirmation'] = ''; $url['menu_path'] = ''; } unset($url); $urls = array_merge($urls, $event['urls']); } if ($db_trigger['url'] !== '') { $urls = array_merge($urls, [[ 'name' => $db_trigger['url_name'] !== '' ? $db_trigger['url_name'] : _('Trigger URL'), 'url' => $db_trigger['url'], 'menu_path' => '', 'new_window' => ZBX_SCRIPT_URL_NEW_WINDOW_NO, 'confirmation' => '' ]]); } $scripts = self::sortEntitiesByMenuPath($scripts); $urls = self::sortEntitiesByMenuPath($urls); foreach (array_values($scripts) as $script) { $menu_data['scripts'][] = [ 'name' => $script['name'], 'menu_path' => $script['menu_path'], 'scriptid' => $script['scriptid'], 'confirmation' => $script['confirmation'] ]; } if ($scripts) { $menu_data['csrf_tokens']['scriptexec'] = CCsrfTokenHelper::get('scriptexec'); } foreach (array_values($urls) as $url) { $menu_data['urls'][] = [ 'label' => $url['name'], 'menu_path' => $url['menu_path'], 'url' => $url['url'], 'target' => $url['new_window'] == ZBX_SCRIPT_URL_NEW_WINDOW_YES ? '_blank' : '', 'confirmation' => $url['confirmation'], 'rel' => 'noopener'.(ZBX_NOREFERER ? ' noreferrer' : '') ]; } if (array_key_exists('urls', $menu_data)) { foreach ($menu_data['urls'] as &$url) { if (!CHtmlUrlValidator::validate($url['url'], ['allow_user_macro' => false])) { $url['url'] = 'javascript: alert('. json_encode(_s('Provided URL "%1$s" is invalid.', $url['url'])). ');'; unset($url['target'], $url['rel']); } } unset($url); } return $menu_data; } error(_('No permissions to referred object or it does not exist!')); return null; } /** * Process menu path and sort scripts or URLs according to it. * * @param array $entities Scripts and URLs. * @param string $entities[]['name'] Name of the ccript or URL. * @param string $entities[]['menu_path'] Menu path of the ccript or URL. * * @return array */ private static function sortEntitiesByMenuPath(array $entities): array { if ($entities) { foreach ($entities as &$entity) { $entity['menu_path'] = trimPath($entity['menu_path']); $entity['sort'] = ''; if (strlen($entity['menu_path']) > 0) { // First or only slash from beginning is trimmed. if (substr($entity['menu_path'], 0, 1) === '/') { $entity['menu_path'] = substr($entity['menu_path'], 1); } $entity['sort'] = $entity['menu_path']; // If there is something more, check if last slash is present. if (strlen($entity['menu_path']) > 0) { if (substr($entity['menu_path'], -1) !== '/' && substr($entity['menu_path'], -2) === '\\/') { $entity['sort'] = $entity['menu_path'].'/'; } else { $entity['sort'] = $entity['menu_path']; } if (substr($entity['menu_path'], -1) === '/' && substr($entity['menu_path'], -2) !== '\\/') { $entity['menu_path'] = substr($entity['menu_path'], 0, -1); } } } $entity['sort'] = $entity['sort'].$entity['name']; } unset($entity); CArrayHelper::sort($entities, ['sort']); } return $entities; } /** * Prepare data for trigger macro context menu popup. * * @return array */ private static function getMenuDataTriggerMacro() { return ['type' => 'trigger_macro']; } protected function doAction() { $data = $this->hasInput('data') ? $this->getInput('data') : []; switch ($this->getInput('type')) { case 'history': $menu_data = self::getMenuDataHistory($data); break; case 'host': $menu_data = self::getMenuDataHost($data); break; case 'item': $menu_data = self::getMenuDataItem($data); break; case 'item_prototype': $menu_data = self::getMenuDataItemPrototype($data); break; case 'map_element': $menu_data = self::getMenuDataMapElement($data); break; case 'trigger': $menu_data = self::getMenuDataTrigger($data); break; case 'trigger_macro': $menu_data = self::getMenuDataTriggerMacro(); break; } $output = []; if ($menu_data !== null) { $output['data'] = $menu_data; } if ($messages = get_and_clear_messages()) { $output['error']['messages'] = array_column($messages, 'message'); } $this->setResponse(new CControllerResponseData(['main_block' => json_encode($output)])); } }