1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22function prepareSubfilterOutput($label, $data, $subfilter, $subfilterName) { 23 CArrayHelper::sort($data, ['value', 'name']); 24 25 $output = [new CTag('h3', true, $label)]; 26 27 foreach ($data as $id => $element) { 28 $element['name'] = CHtml::encode($element['name']); 29 30 // is activated 31 if (str_in_array($id, $subfilter)) { 32 $output[] = (new CSpan([ 33 (new CLinkAction($element['name'])) 34 ->onClick(CHtml::encode( 35 'javascript: create_var("zbx_filter", "subfilter_set", "1", false);'. 36 'create_var("zbx_filter", '.json_encode($subfilterName.'['.$id.']').', null, true);' 37 )), 38 ' ', 39 new CSup($element['count']) 40 ])) 41 ->addClass(ZBX_STYLE_NOWRAP) 42 ->addClass(ZBX_STYLE_SUBFILTER) 43 ->addClass(ZBX_STYLE_SUBFILTER_ENABLED); 44 } 45 // isn't activated 46 else { 47 // subfilter has 0 items 48 if ($element['count'] == 0) { 49 $output[] = (new CSpan([ 50 (new CSpan($element['name']))->addClass(ZBX_STYLE_GREY), 51 ' ', 52 new CSup($element['count']) 53 ]))->addClass(ZBX_STYLE_SUBFILTER); 54 } 55 else { 56 $link = (new CLinkAction($element['name'])) 57 ->onClick(CHtml::encode( 58 'javascript: create_var("zbx_filter", "subfilter_set", "1", false);'. 59 'create_var("zbx_filter", '. 60 json_encode($subfilterName.'['.$id.']').', '. 61 json_encode($id).', '. 62 'true'. 63 ');' 64 )); 65 66 $output[] = (new CSpan([ 67 $link, 68 ' ', 69 new CSup(($subfilter ? '+' : '').$element['count']) 70 ])) 71 ->addClass(ZBX_STYLE_NOWRAP) 72 ->addClass(ZBX_STYLE_SUBFILTER); 73 } 74 } 75 } 76 77 return $output; 78} 79 80function getItemFilterForm(&$items) { 81 $filter_groupids = $_REQUEST['filter_groupids']; 82 $filter_hostids = $_REQUEST['filter_hostids']; 83 $filter_application = $_REQUEST['filter_application']; 84 $filter_name = $_REQUEST['filter_name']; 85 $filter_type = $_REQUEST['filter_type']; 86 $filter_key = $_REQUEST['filter_key']; 87 $filter_snmp_oid = $_REQUEST['filter_snmp_oid']; 88 $filter_value_type = $_REQUEST['filter_value_type']; 89 $filter_delay = $_REQUEST['filter_delay']; 90 $filter_history = $_REQUEST['filter_history']; 91 $filter_trends = $_REQUEST['filter_trends']; 92 $filter_status = $_REQUEST['filter_status']; 93 $filter_state = $_REQUEST['filter_state']; 94 $filter_templated_items = $_REQUEST['filter_templated_items']; 95 $filter_with_triggers = $_REQUEST['filter_with_triggers']; 96 $filter_discovery = $_REQUEST['filter_discovery']; 97 $subfilter_hosts = $_REQUEST['subfilter_hosts']; 98 $subfilter_apps = $_REQUEST['subfilter_apps']; 99 $subfilter_types = $_REQUEST['subfilter_types']; 100 $subfilter_value_types = $_REQUEST['subfilter_value_types']; 101 $subfilter_status = $_REQUEST['subfilter_status']; 102 $subfilter_state = $_REQUEST['subfilter_state']; 103 $subfilter_templated_items = $_REQUEST['subfilter_templated_items']; 104 $subfilter_with_triggers = $_REQUEST['subfilter_with_triggers']; 105 $subfilter_discovery = $_REQUEST['subfilter_discovery']; 106 $subfilter_history = $_REQUEST['subfilter_history']; 107 $subfilter_trends = $_REQUEST['subfilter_trends']; 108 $subfilter_interval = $_REQUEST['subfilter_interval']; 109 110 $filter = (new CFilter(new CUrl('items.php'))) 111 ->setProfile('web.items.filter') 112 ->setActiveTab(CProfile::get('web.items.filter.active', 1)) 113 ->addVar('subfilter_hosts', $subfilter_hosts) 114 ->addVar('subfilter_apps', $subfilter_apps) 115 ->addVar('subfilter_types', $subfilter_types) 116 ->addVar('subfilter_value_types', $subfilter_value_types) 117 ->addVar('subfilter_status', $subfilter_status) 118 ->addVar('subfilter_state', $subfilter_state) 119 ->addVar('subfilter_templated_items', $subfilter_templated_items) 120 ->addVar('subfilter_with_triggers', $subfilter_with_triggers) 121 ->addVar('subfilter_discovery', $subfilter_discovery) 122 ->addVar('subfilter_history', $subfilter_history) 123 ->addVar('subfilter_trends', $subfilter_trends) 124 ->addVar('subfilter_interval', $subfilter_interval); 125 126 $filterColumn1 = new CFormList(); 127 $filterColumn2 = new CFormList(); 128 $filterColumn3 = new CFormList(); 129 $filterColumn4 = new CFormList(); 130 131 // type select 132 $fTypeVisibility = []; 133 $type_select = (new CSelect('filter_type')) 134 ->setId('filter_type') 135 ->setValue($filter_type) 136 ->setFocusableElementId('label-filter-type') 137 ->addOption(new CSelectOption(-1, _('all'))); 138 139 zbx_subarray_push($fTypeVisibility, -1, 'filter_delay_row'); 140 141 $item_types = item_type2str(); 142 unset($item_types[ITEM_TYPE_HTTPTEST]); // httptest items are only for internal zabbix logic 143 144 $type_select->addOptions(CSelect::createOptionsFromArray($item_types)); 145 146 foreach ($item_types as $type => $name) { 147 if ($type != ITEM_TYPE_TRAPPER && $type != ITEM_TYPE_SNMPTRAP) { 148 zbx_subarray_push($fTypeVisibility, $type, 'filter_delay_row'); 149 } 150 if ($type == ITEM_TYPE_SNMP) { 151 zbx_subarray_push($fTypeVisibility, $type, 'filter_snmp_oid_row'); 152 } 153 } 154 155 zbx_add_post_js("var filterTypeSwitcher = new CViewSwitcher('filter_type', 'change', ".zbx_jsvalue($fTypeVisibility, true).');'); 156 157 // row 1 158 $group_filter = !empty($filter_groupids) 159 ? CArrayHelper::renameObjectsKeys(API::HostGroup()->get([ 160 'output' => ['groupid', 'name'], 161 'groupids' => $filter_groupids, 162 'editable' => true 163 ]), ['groupid' => 'id']) 164 : []; 165 166 $filterColumn1->addRow((new CLabel(_('Host groups'), 'filter_groupid_ms')), 167 (new CMultiSelect([ 168 'name' => 'filter_groupids[]', 169 'object_name' => 'hostGroup', 170 'data' => $group_filter, 171 'popup' => [ 172 'parameters' => [ 173 'srctbl' => 'host_groups', 174 'srcfld1' => 'groupid', 175 'dstfrm' => $filter->getName(), 176 'dstfld1' => 'filter_groupids_', 177 'editable' => true 178 ] 179 ] 180 ]))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) 181 ); 182 183 $filterColumn2->addRow(new CLabel(_('Type'), $type_select->getFocusableElementId()), $type_select); 184 $filterColumn3->addRow(new CLabel(_('Type of information'), 'label-filter-value-type'), 185 (new CSelect('filter_value_type')) 186 ->setFocusableElementId('label-filter-value-type') 187 ->setValue($filter_value_type) 188 ->addOptions(CSelect::createOptionsFromArray([ 189 -1 => _('all'), 190 ITEM_VALUE_TYPE_UINT64 => _('Numeric (unsigned)'), 191 ITEM_VALUE_TYPE_FLOAT => _('Numeric (float)'), 192 ITEM_VALUE_TYPE_STR => _('Character'), 193 ITEM_VALUE_TYPE_LOG => _('Log'), 194 ITEM_VALUE_TYPE_TEXT => _('Text') 195 ])) 196 ); 197 $filterColumn4->addRow(new CLabel(_('State'), 'label-filter-state'), 198 (new CSelect('filter_state')) 199 ->setId('filter_state') 200 ->setFocusableElementId('label-filter-state') 201 ->setValue($filter_state) 202 ->addOptions(CSelect::createOptionsFromArray([ 203 -1 => _('all'), 204 ITEM_STATE_NORMAL => itemState(ITEM_STATE_NORMAL), 205 ITEM_STATE_NOTSUPPORTED => itemState(ITEM_STATE_NOTSUPPORTED) 206 ])) 207 ); 208 209 // row 2 210 $host_filter = !empty($filter_hostids) 211 ? CArrayHelper::renameObjectsKeys(API::Host()->get([ 212 'output' => ['hostid', 'name'], 213 'hostids' => $filter_hostids, 214 'templated_hosts' => true, 215 'editable' => true 216 ]), ['hostid' => 'id']) 217 : []; 218 219 $filterColumn1->addRow((new CLabel(_('Hosts'), 'filter_hostid_ms')), 220 (new CMultiSelect([ 221 'name' => 'filter_hostids[]', 222 'object_name' => 'host_templates', 223 'data' => $host_filter, 224 'popup' => [ 225 'filter_preselect_fields' => [ 226 'hostgroups' => 'filter_groupids_' 227 ], 228 'parameters' => [ 229 'srctbl' => 'host_templates', 230 'srcfld1' => 'hostid', 231 'dstfrm' => $filter->getName(), 232 'dstfld1' => 'filter_hostids_', 233 'editable' => true 234 ] 235 ] 236 ]))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) 237 ); 238 239 $filterColumn2->addRow(_('Update interval'), 240 (new CTextBox('filter_delay', $filter_delay))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), 241 'filter_delay_row' 242 ); 243 $filterColumn4->addRow(new CLabel(_('Status'), 'label-filter-status'), 244 (new CSelect('filter_status')) 245 ->setId('filter_status') 246 ->setFocusableElementId('label-filter-status') 247 ->setValue($filter_status) 248 ->addOptions(CSelect::createOptionsFromArray([ 249 -1 => _('all'), 250 ITEM_STATUS_ACTIVE => item_status2str(ITEM_STATUS_ACTIVE), 251 ITEM_STATUS_DISABLED => item_status2str(ITEM_STATUS_DISABLED) 252 ])) 253 ); 254 255 // row 3 256 $filterColumn1->addRow(_('Application'), 257 [ 258 (new CTextBox('filter_application', $filter_application))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), 259 (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), 260 (new CButton(null, _('Select'))) 261 ->addClass(ZBX_STYLE_BTN_GREY) 262 ->onClick('return PopUp("popup.generic",jQuery.extend('. 263 json_encode([ 264 'srctbl' => 'applications', 265 'srcfld1' => 'name', 266 'dstfrm' => $filter->getName(), 267 'dstfld1' => 'filter_application', 268 'with_applications' => '1' 269 ]). 270 ', getFirstMultiselectValue("filter_hostids_")), null, this);' 271 ) 272 ] 273 ); 274 275 $filterColumn3->addRow(_('History'), 276 (new CTextBox('filter_history', $filter_history))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) 277 ); 278 $filterColumn4->addRow(new CLabel(_('Triggers'), 'label-filter-with-triggers'), 279 (new CSelect('filter_with_triggers')) 280 ->setFocusableElementId('label-filter-with-triggers') 281 ->setValue($filter_with_triggers) 282 ->addOptions(CSelect::createOptionsFromArray([ 283 -1 => _('all'), 284 1 => _('With triggers'), 285 0 => _('Without triggers') 286 ])) 287 ); 288 289 // row 4 290 $filterColumn1->addRow(_('Name'), 291 (new CTextBox('filter_name', $filter_name))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) 292 ); 293 $filterColumn2->addRow(_('SNMP OID'), 294 (new CTextBox('filter_snmp_oid', $filter_snmp_oid, '', 255))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), 295 'filter_snmp_oid_row' 296 ); 297 $filterColumn3->addRow(_('Trends'), 298 (new CTextBox('filter_trends', $filter_trends))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) 299 ); 300 $filterColumn4->addRow(new CLabel(_('Template'), 'label-filter-templated-items'), 301 (new CSelect('filter_templated_items')) 302 ->setFocusableElementId('label-filter-templated-items') 303 ->setValue($filter_templated_items) 304 ->addOptions(CSelect::createOptionsFromArray([ 305 -1 => _('all'), 306 1 => _('Inherited items'), 307 0 => _('Not inherited items') 308 ])) 309 ); 310 311 // row 5 312 $filterColumn1->addRow(_('Key'), 313 (new CTextBox('filter_key', $filter_key))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) 314 ); 315 $filterColumn4->addRow(new CLabel(_('Discovery'), 'label-filter-discovery'), 316 (new CSelect('filter_discovery')) 317 ->setFocusableElementId('label-filter-discovery') 318 ->setValue($filter_discovery) 319 ->addOptions(CSelect::createOptionsFromArray([ 320 -1 => _('all'), 321 ZBX_FLAG_DISCOVERY_CREATED => _('Discovered items'), 322 ZBX_FLAG_DISCOVERY_NORMAL => _('Regular items') 323 ])) 324 ); 325 326 // subfilters 327 $table_subfilter = (new CTableInfo()) 328 ->addRow([ 329 new CTag('h4', true, [ 330 _('Subfilter'), SPACE, (new CSpan(_('affects only filtered data')))->addClass(ZBX_STYLE_GREY) 331 ]) 332 ]); 333 334 // array contains subfilters and number of items in each 335 $item_params = [ 336 'hosts' => [], 337 'applications' => [], 338 'types' => [], 339 'value_types' => [], 340 'status' => [], 341 'state' => [], 342 'templated_items' => [], 343 'with_triggers' => [], 344 'discovery' => [], 345 'history' => [], 346 'trends' => [], 347 'interval' => [] 348 ]; 349 350 $update_interval_parser = new CUpdateIntervalParser(['usermacros' => true]); 351 $simple_interval_parser = new CSimpleIntervalParser(); 352 353 // generate array with values for subfilters of selected items 354 foreach ($items as $item) { 355 // hosts 356 if ($filter_hostids) { 357 $host = reset($item['hosts']); 358 359 if (!isset($item_params['hosts'][$host['hostid']])) { 360 $item_params['hosts'][$host['hostid']] = ['name' => $host['name'], 'count' => 0]; 361 } 362 $show_item = true; 363 foreach ($item['subfilters'] as $name => $value) { 364 if ($name == 'subfilter_hosts') { 365 continue; 366 } 367 $show_item &= $value; 368 } 369 if ($show_item) { 370 $host = reset($item['hosts']); 371 $item_params['hosts'][$host['hostid']]['count']++; 372 } 373 } 374 375 // applications 376 if (!empty($item['applications'])) { 377 foreach ($item['applications'] as $application) { 378 if (!isset($item_params['applications'][$application['name']])) { 379 $item_params['applications'][$application['name']] = ['name' => $application['name'], 'count' => 0]; 380 } 381 } 382 } 383 $show_item = true; 384 foreach ($item['subfilters'] as $name => $value) { 385 if ($name == 'subfilter_apps') { 386 continue; 387 } 388 $show_item &= $value; 389 } 390 $sel_app = false; 391 if ($show_item) { 392 // if any of item applications are selected 393 foreach ($item['applications'] as $app) { 394 if (str_in_array($app['name'], $subfilter_apps)) { 395 $sel_app = true; 396 break; 397 } 398 } 399 foreach ($item['applications'] as $app) { 400 if (str_in_array($app['name'], $subfilter_apps) || !$sel_app) { 401 $item_params['applications'][$app['name']]['count']++; 402 } 403 } 404 } 405 406 // types 407 if ($filter_type == -1) { 408 if (!isset($item_params['types'][$item['type']])) { 409 $item_params['types'][$item['type']] = ['name' => item_type2str($item['type']), 'count' => 0]; 410 } 411 $show_item = true; 412 foreach ($item['subfilters'] as $name => $value) { 413 if ($name == 'subfilter_types') { 414 continue; 415 } 416 $show_item &= $value; 417 } 418 if ($show_item) { 419 $item_params['types'][$item['type']]['count']++; 420 } 421 } 422 423 // value types 424 if ($filter_value_type == -1) { 425 if (!isset($item_params['value_types'][$item['value_type']])) { 426 $item_params['value_types'][$item['value_type']] = [ 427 'name' => itemValueTypeString($item['value_type']), 428 'count' => 0 429 ]; 430 } 431 432 $show_item = true; 433 foreach ($item['subfilters'] as $name => $value) { 434 if ($name == 'subfilter_value_types') { 435 continue; 436 } 437 $show_item &= $value; 438 } 439 if ($show_item) { 440 $item_params['value_types'][$item['value_type']]['count']++; 441 } 442 } 443 444 // status 445 if ($filter_status == -1) { 446 if (!isset($item_params['status'][$item['status']])) { 447 $item_params['status'][$item['status']] = [ 448 'name' => item_status2str($item['status']), 449 'count' => 0 450 ]; 451 } 452 $show_item = true; 453 foreach ($item['subfilters'] as $name => $value) { 454 if ($name == 'subfilter_status') { 455 continue; 456 } 457 $show_item &= $value; 458 } 459 if ($show_item) { 460 $item_params['status'][$item['status']]['count']++; 461 } 462 } 463 464 // state 465 if ($filter_state == -1) { 466 if (!isset($item_params['state'][$item['state']])) { 467 $item_params['state'][$item['state']] = [ 468 'name' => itemState($item['state']), 469 'count' => 0 470 ]; 471 } 472 $show_item = true; 473 foreach ($item['subfilters'] as $name => $value) { 474 if ($name == 'subfilter_state') { 475 continue; 476 } 477 $show_item &= $value; 478 } 479 if ($show_item) { 480 $item_params['state'][$item['state']]['count']++; 481 } 482 } 483 484 // template 485 if ($filter_templated_items == -1) { 486 if ($item['templateid'] == 0 && !isset($item_params['templated_items'][0])) { 487 $item_params['templated_items'][0] = ['name' => _('Not inherited items'), 'count' => 0]; 488 } 489 elseif ($item['templateid'] > 0 && !isset($item_params['templated_items'][1])) { 490 $item_params['templated_items'][1] = ['name' => _('Inherited items'), 'count' => 0]; 491 } 492 $show_item = true; 493 foreach ($item['subfilters'] as $name => $value) { 494 if ($name == 'subfilter_templated_items') { 495 continue; 496 } 497 $show_item &= $value; 498 } 499 if ($show_item) { 500 if ($item['templateid'] == 0) { 501 $item_params['templated_items'][0]['count']++; 502 } 503 else { 504 $item_params['templated_items'][1]['count']++; 505 } 506 } 507 } 508 509 // with triggers 510 if ($filter_with_triggers == -1) { 511 if (count($item['triggers']) == 0 && !isset($item_params['with_triggers'][0])) { 512 $item_params['with_triggers'][0] = ['name' => _('Without triggers'), 'count' => 0]; 513 } 514 elseif (count($item['triggers']) > 0 && !isset($item_params['with_triggers'][1])) { 515 $item_params['with_triggers'][1] = ['name' => _('With triggers'), 'count' => 0]; 516 } 517 $show_item = true; 518 foreach ($item['subfilters'] as $name => $value) { 519 if ($name == 'subfilter_with_triggers') { 520 continue; 521 } 522 $show_item &= $value; 523 } 524 if ($show_item) { 525 if (count($item['triggers']) == 0) { 526 $item_params['with_triggers'][0]['count']++; 527 } 528 else { 529 $item_params['with_triggers'][1]['count']++; 530 } 531 } 532 } 533 534 // discovery 535 if ($filter_discovery == -1) { 536 if ($item['flags'] == ZBX_FLAG_DISCOVERY_NORMAL && !isset($item_params['discovery'][0])) { 537 $item_params['discovery'][0] = ['name' => _('Regular'), 'count' => 0]; 538 } 539 elseif ($item['flags'] == ZBX_FLAG_DISCOVERY_CREATED && !isset($item_params['discovery'][1])) { 540 $item_params['discovery'][1] = ['name' => _('Discovered'), 'count' => 0]; 541 } 542 $show_item = true; 543 foreach ($item['subfilters'] as $name => $value) { 544 if ($name == 'subfilter_discovery') { 545 continue; 546 } 547 $show_item &= $value; 548 } 549 if ($show_item) { 550 if ($item['flags'] == ZBX_FLAG_DISCOVERY_NORMAL) { 551 $item_params['discovery'][0]['count']++; 552 } 553 else { 554 $item_params['discovery'][1]['count']++; 555 } 556 } 557 } 558 559 // trends 560 if ($filter_trends === '' 561 && !in_array($item['value_type'], [ITEM_VALUE_TYPE_STR, ITEM_VALUE_TYPE_LOG, ITEM_VALUE_TYPE_TEXT])) { 562 $trends = $item['trends']; 563 $value = $trends; 564 565 if ($simple_interval_parser->parse($trends) == CParser::PARSE_SUCCESS) { 566 $value = timeUnitToSeconds($trends); 567 $trends = convertUnitsS($value); 568 } 569 570 if (!array_key_exists($trends, $item_params['trends'])) { 571 $item_params['trends'][$trends] = [ 572 'name' => $trends, 573 'count' => 0, 574 'value' => $value 575 ]; 576 } 577 578 $show_item = true; 579 580 foreach ($item['subfilters'] as $name => $value) { 581 if ($name === 'subfilter_trends') { 582 continue; 583 } 584 $show_item &= $value; 585 } 586 587 if ($show_item) { 588 $item_params['trends'][$trends]['count']++; 589 } 590 } 591 592 // history 593 if ($filter_history === '') { 594 $history = $item['history']; 595 $value = $history; 596 597 if ($simple_interval_parser->parse($history) == CParser::PARSE_SUCCESS) { 598 $value = timeUnitToSeconds($history); 599 $history = convertUnitsS($value); 600 } 601 602 if (!array_key_exists($history, $item_params['history'])) { 603 $item_params['history'][$history] = [ 604 'name' => $history, 605 'count' => 0, 606 'value' => $value 607 ]; 608 } 609 610 $show_item = true; 611 612 foreach ($item['subfilters'] as $name => $value) { 613 if ($name === 'subfilter_history') { 614 continue; 615 } 616 $show_item &= $value; 617 } 618 619 if ($show_item) { 620 $item_params['history'][$history]['count']++; 621 } 622 } 623 624 // interval 625 if ($filter_delay === '' && $filter_type != ITEM_TYPE_TRAPPER && $item['type'] != ITEM_TYPE_TRAPPER 626 && $item['type'] != ITEM_TYPE_SNMPTRAP && $item['type'] != ITEM_TYPE_DEPENDENT) { 627 // Use temporary variable for delay, because the original will be used for sorting later. 628 $delay = $item['delay']; 629 $value = $delay; 630 631 if ($update_interval_parser->parse($delay) == CParser::PARSE_SUCCESS) { 632 $delay = $update_interval_parser->getDelay(); 633 634 // "value" is delay represented in seconds and it is used for sorting the subfilter. 635 if ($delay[0] !== '{') { 636 $value = timeUnitToSeconds($delay); 637 $delay = convertUnitsS($value); 638 } 639 else { 640 $value = $delay; 641 } 642 } 643 644 if (!array_key_exists($delay, $item_params['interval'])) { 645 $item_params['interval'][$delay] = [ 646 'name' => $delay, 647 'count' => 0, 648 'value' => $value 649 ]; 650 } 651 652 $show_item = true; 653 654 foreach ($item['subfilters'] as $name => $value) { 655 if ($name === 'subfilter_interval') { 656 continue; 657 } 658 $show_item &= $value; 659 } 660 661 if ($show_item) { 662 $item_params['interval'][$delay]['count']++; 663 } 664 } 665 } 666 667 // output 668 if ($filter_hostids && count($item_params['hosts']) > 1) { 669 $hosts_output = prepareSubfilterOutput(_('Hosts'), $item_params['hosts'], $subfilter_hosts, 'subfilter_hosts'); 670 $table_subfilter->addRow([$hosts_output]); 671 } 672 673 if (!empty($item_params['applications']) && count($item_params['applications']) > 1) { 674 $application_output = prepareSubfilterOutput(_('Applications'), $item_params['applications'], $subfilter_apps, 'subfilter_apps'); 675 $table_subfilter->addRow([$application_output]); 676 } 677 678 if ($filter_type == -1 && count($item_params['types']) > 1) { 679 $type_output = prepareSubfilterOutput(_('Types'), $item_params['types'], $subfilter_types, 'subfilter_types'); 680 $table_subfilter->addRow([$type_output]); 681 } 682 683 if ($filter_value_type == -1 && count($item_params['value_types']) > 1) { 684 $value_types_output = prepareSubfilterOutput(_('Type of information'), $item_params['value_types'], $subfilter_value_types, 'subfilter_value_types'); 685 $table_subfilter->addRow([$value_types_output]); 686 } 687 688 if ($filter_status == -1 && count($item_params['status']) > 1) { 689 $status_output = prepareSubfilterOutput(_('Status'), $item_params['status'], $subfilter_status, 'subfilter_status'); 690 $table_subfilter->addRow([$status_output]); 691 } 692 693 if ($filter_state == -1 && count($item_params['state']) > 1) { 694 $state_output = prepareSubfilterOutput(_('State'), $item_params['state'], $subfilter_state, 'subfilter_state'); 695 $table_subfilter->addRow([$state_output]); 696 } 697 698 if ($filter_templated_items == -1 && count($item_params['templated_items']) > 1) { 699 $templated_items_output = prepareSubfilterOutput(_('Template'), $item_params['templated_items'], $subfilter_templated_items, 'subfilter_templated_items'); 700 $table_subfilter->addRow([$templated_items_output]); 701 } 702 703 if ($filter_with_triggers == -1 && count($item_params['with_triggers']) > 1) { 704 $with_triggers_output = prepareSubfilterOutput(_('With triggers'), $item_params['with_triggers'], $subfilter_with_triggers, 'subfilter_with_triggers'); 705 $table_subfilter->addRow([$with_triggers_output]); 706 } 707 708 if ($filter_discovery == -1 && count($item_params['discovery']) > 1) { 709 $discovery_output = prepareSubfilterOutput(_('Discovery'), $item_params['discovery'], $subfilter_discovery, 'subfilter_discovery'); 710 $table_subfilter->addRow([$discovery_output]); 711 } 712 713 if (zbx_empty($filter_history) && count($item_params['history']) > 1) { 714 $history_output = prepareSubfilterOutput(_('History'), $item_params['history'], $subfilter_history, 'subfilter_history'); 715 $table_subfilter->addRow([$history_output]); 716 } 717 718 if (zbx_empty($filter_trends) && (count($item_params['trends']) > 1)) { 719 $trends_output = prepareSubfilterOutput(_('Trends'), $item_params['trends'], $subfilter_trends, 'subfilter_trends'); 720 $table_subfilter->addRow([$trends_output]); 721 } 722 723 if (zbx_empty($filter_delay) && $filter_type != ITEM_TYPE_TRAPPER && count($item_params['interval']) > 1) { 724 $interval_output = prepareSubfilterOutput(_('Interval'), $item_params['interval'], $subfilter_interval, 'subfilter_interval'); 725 $table_subfilter->addRow([$interval_output]); 726 } 727 728 $filter->addFilterTab(_('Filter'), [$filterColumn1, $filterColumn2, $filterColumn3, $filterColumn4], 729 $table_subfilter 730 ); 731 732 return $filter; 733} 734 735/** 736 * Prepare ITEM_TYPE_HTTPAGENT type item data for create or update API calls. 737 * - Converts 'query_fields' from array of keys and array of values to array of hash maps for every field. 738 * - Converts 'headers' from array of keys and array of values to hash map. 739 * - For request method HEAD set retrieve mode to retrieve only headers. 740 * 741 * @param array $item Array of form fields data for ITEM_TYPE_HTTPAGENT item. 742 * @param int $item['request_method'] Request method type. 743 * @param array $item['query_fields'] Array of 'name' and 'value' arrays for URL query fields. 744 * @param array $item['headers'] Array of 'name' and 'value' arrays for headers. 745 * 746 * @return array 747 */ 748function prepareItemHttpAgentFormData(array $item) { 749 if ($item['request_method'] == HTTPCHECK_REQUEST_HEAD) { 750 $item['retrieve_mode'] = HTTPTEST_STEP_RETRIEVE_MODE_HEADERS; 751 } 752 753 if ($item['query_fields']) { 754 $query_fields = []; 755 756 foreach ($item['query_fields']['name'] as $index => $key) { 757 $value = $item['query_fields']['value'][$index]; 758 759 if ($key !== '' || $value !== '') { 760 $query_fields[] = [$key => $value]; 761 } 762 } 763 $item['query_fields'] = $query_fields; 764 } 765 766 if ($item['headers']) { 767 $headers = []; 768 769 foreach ($item['headers']['name'] as $index => $key) { 770 $value = $item['headers']['value'][$index]; 771 772 if ($key !== '' || $value !== '') { 773 $headers[$key] = $value; 774 } 775 } 776 777 $item['headers'] = $headers; 778 } 779 780 return $item; 781} 782 783/** 784 * Get data for item edit page. 785 * 786 * @param array $item Item, item prototype, LLD rule or LLD item to take the data from. 787 * @param array $options 788 * @param bool $options['is_discovery_rule'] 789 * 790 * @return array 791 */ 792function getItemFormData(array $item = [], array $options = []) { 793 $data = [ 794 'form' => getRequest('form'), 795 'form_refresh' => getRequest('form_refresh'), 796 'is_discovery_rule' => !empty($options['is_discovery_rule']), 797 'parent_discoveryid' => getRequest('parent_discoveryid', 0), 798 'itemid' => getRequest('itemid'), 799 'limited' => false, 800 'interfaceid' => getRequest('interfaceid', 0), 801 'name' => getRequest('name', ''), 802 'description' => getRequest('description', ''), 803 'key' => getRequest('key', ''), 804 'master_itemid' => getRequest('master_itemid', 0), 805 'hostname' => getRequest('hostname'), 806 'delay' => getRequest('delay', ZBX_ITEM_DELAY_DEFAULT), 807 'history' => getRequest('history', DB::getDefault('items', 'history')), 808 'status' => getRequest('status', isset($_REQUEST['form_refresh']) ? 1 : 0), 809 'type' => getRequest('type', 0), 810 'snmp_oid' => getRequest('snmp_oid', ''), 811 'value_type' => getRequest('value_type', ITEM_VALUE_TYPE_UINT64), 812 'trapper_hosts' => getRequest('trapper_hosts', ''), 813 'units' => getRequest('units', ''), 814 'valuemapid' => getRequest('valuemapid', 0), 815 'params' => getRequest('params', ''), 816 'trends' => getRequest('trends', DB::getDefault('items', 'trends')), 817 'new_application' => getRequest('new_application', ''), 818 'applications' => getRequest('applications', []), 819 'delay_flex' => array_values(getRequest('delay_flex', [])), 820 'ipmi_sensor' => getRequest('ipmi_sensor', ''), 821 'authtype' => getRequest('authtype', 0), 822 'username' => getRequest('username', ''), 823 'password' => getRequest('password', ''), 824 'publickey' => getRequest('publickey', ''), 825 'privatekey' => getRequest('privatekey', ''), 826 'logtimefmt' => getRequest('logtimefmt', ''), 827 'valuemaps' => null, 828 'possibleHostInventories' => null, 829 'alreadyPopulated' => null, 830 'initial_item_type' => null, 831 'templates' => [], 832 'jmx_endpoint' => getRequest('jmx_endpoint', ZBX_DEFAULT_JMX_ENDPOINT), 833 'timeout' => getRequest('timeout', DB::getDefault('items', 'timeout')), 834 'url' => getRequest('url'), 835 'query_fields' => getRequest('query_fields', []), 836 'posts' => getRequest('posts'), 837 'status_codes' => getRequest('status_codes', DB::getDefault('items', 'status_codes')), 838 'follow_redirects' => hasRequest('form_refresh') 839 ? (int) getRequest('follow_redirects') 840 : getRequest('follow_redirects', DB::getDefault('items', 'follow_redirects')), 841 'post_type' => getRequest('post_type', DB::getDefault('items', 'post_type')), 842 'http_proxy' => getRequest('http_proxy'), 843 'headers' => getRequest('headers', []), 844 'retrieve_mode' => getRequest('retrieve_mode', DB::getDefault('items', 'retrieve_mode')), 845 'request_method' => getRequest('request_method', DB::getDefault('items', 'request_method')), 846 'output_format' => getRequest('output_format', DB::getDefault('items', 'output_format')), 847 'allow_traps' => getRequest('allow_traps', DB::getDefault('items', 'allow_traps')), 848 'ssl_cert_file' => getRequest('ssl_cert_file'), 849 'ssl_key_file' => getRequest('ssl_key_file'), 850 'ssl_key_password' => getRequest('ssl_key_password'), 851 'verify_peer' => getRequest('verify_peer', DB::getDefault('items', 'verify_peer')), 852 'verify_host' => getRequest('verify_host', DB::getDefault('items', 'verify_host')), 853 'http_authtype' => getRequest('http_authtype', HTTPTEST_AUTH_NONE), 854 'http_username' => getRequest('http_username', ''), 855 'http_password' => getRequest('http_password', ''), 856 'preprocessing' => getRequest('preprocessing', []), 857 'preprocessing_script_maxlength' => DB::getFieldLength('item_preproc', 'params') 858 ]; 859 860 if ($data['parent_discoveryid'] != 0) { 861 $data['discover'] = hasRequest('form_refresh') 862 ? getRequest('discover', DB::getDefault('items', 'discover')) 863 : (($item && array_key_exists('discover', $item)) 864 ? $item['discover'] 865 : DB::getDefault('items', 'discover') 866 ); 867 } 868 869 if ($data['type'] == ITEM_TYPE_HTTPAGENT) { 870 foreach (['query_fields', 'headers'] as $property) { 871 $values = []; 872 873 if (is_array($data[$property]) && array_key_exists('name', $data[$property]) 874 && array_key_exists('value', $data[$property])) { 875 foreach ($data[$property]['name'] as $index => $key) { 876 if (array_key_exists($index, $data[$property]['value'])) { 877 $values[] = [$key => $data[$property]['value'][$index]]; 878 } 879 } 880 } 881 $data[$property] = $values; 882 } 883 } 884 else { 885 $data['headers'] = []; 886 $data['query_fields'] = []; 887 } 888 889 // Dependent item initialization by master_itemid. 890 if (array_key_exists('master_item', $item)) { 891 $expanded = CMacrosResolverHelper::resolveItemNames([$item['master_item']]); 892 $master_item = reset($expanded); 893 $data['master_itemid'] = $master_item['itemid']; 894 $data['master_itemname'] = $master_item['name_expanded']; 895 // Do not initialize item data if only master_item array was passed. 896 unset($item['master_item']); 897 } 898 899 // hostid 900 if ($data['parent_discoveryid'] != 0) { 901 $discoveryRule = API::DiscoveryRule()->get([ 902 'output' => ['hostid'], 903 'itemids' => $data['parent_discoveryid'], 904 'editable' => true 905 ]); 906 $discoveryRule = reset($discoveryRule); 907 $data['hostid'] = $discoveryRule['hostid']; 908 909 $data['new_application_prototype'] = getRequest('new_application_prototype', ''); 910 $data['application_prototypes'] = getRequest('application_prototypes', []); 911 } 912 else { 913 $data['hostid'] = getRequest('hostid', 0); 914 } 915 916 foreach ($data['preprocessing'] as &$step) { 917 $step += [ 918 'error_handler' => ZBX_PREPROC_FAIL_DEFAULT, 919 'error_handler_params' => '' 920 ]; 921 } 922 unset($step); 923 924 // types, http items only for internal processes 925 $data['types'] = item_type2str(); 926 unset($data['types'][ITEM_TYPE_HTTPTEST]); 927 if ($data['is_discovery_rule']) { 928 unset($data['types'][ITEM_TYPE_AGGREGATE], 929 $data['types'][ITEM_TYPE_CALCULATED], 930 $data['types'][ITEM_TYPE_SNMPTRAP] 931 ); 932 } 933 934 // item 935 if (array_key_exists('itemid', $item)) { 936 $data['item'] = $item; 937 $data['hostid'] = !empty($data['hostid']) ? $data['hostid'] : $data['item']['hostid']; 938 $data['limited'] = ($data['item']['templateid'] != 0); 939 $data['interfaceid'] = $item['interfaceid']; 940 941 // discovery rule 942 if ($data['is_discovery_rule']) { 943 $flag = ZBX_FLAG_DISCOVERY_RULE; 944 } 945 // item prototype 946 elseif ($data['parent_discoveryid'] != 0) { 947 $flag = ZBX_FLAG_DISCOVERY_PROTOTYPE; 948 } 949 // plain item 950 else { 951 $flag = ZBX_FLAG_DISCOVERY_NORMAL; 952 } 953 954 $data['templates'] = makeItemTemplatesHtml($item['itemid'], getItemParentTemplates([$item], $flag), $flag); 955 } 956 957 // caption 958 if ($data['is_discovery_rule']) { 959 $data['caption'] = _('Discovery rule'); 960 } 961 else { 962 $data['caption'] = ($data['parent_discoveryid'] != 0) ? _('Item prototype') : _('Item'); 963 } 964 965 // hostname 966 if (empty($data['is_discovery_rule']) && empty($data['hostname'])) { 967 if (!empty($data['hostid'])) { 968 $hostInfo = API::Host()->get([ 969 'hostids' => $data['hostid'], 970 'output' => ['name'], 971 'templated_hosts' => true 972 ]); 973 $hostInfo = reset($hostInfo); 974 $data['hostname'] = $hostInfo['name']; 975 } 976 else { 977 $data['hostname'] = _('not selected'); 978 } 979 } 980 981 // fill data from item 982 if (!hasRequest('form_refresh') && ($item || $data['limited'])) { 983 $data['name'] = $data['item']['name']; 984 $data['description'] = $data['item']['description']; 985 $data['key'] = $data['item']['key_']; 986 $data['interfaceid'] = $data['item']['interfaceid']; 987 $data['type'] = $data['item']['type']; 988 $data['snmp_oid'] = $data['item']['snmp_oid']; 989 $data['value_type'] = $data['item']['value_type']; 990 $data['trapper_hosts'] = $data['item']['trapper_hosts']; 991 $data['units'] = $data['item']['units']; 992 $data['valuemapid'] = $data['item']['valuemapid']; 993 $data['hostid'] = $data['item']['hostid']; 994 $data['params'] = $data['item']['params']; 995 $data['ipmi_sensor'] = $data['item']['ipmi_sensor']; 996 $data['authtype'] = $data['item']['authtype']; 997 $data['username'] = $data['item']['username']; 998 $data['password'] = $data['item']['password']; 999 $data['publickey'] = $data['item']['publickey']; 1000 $data['privatekey'] = $data['item']['privatekey']; 1001 $data['logtimefmt'] = $data['item']['logtimefmt']; 1002 $data['jmx_endpoint'] = $data['item']['jmx_endpoint']; 1003 $data['new_application'] = getRequest('new_application', ''); 1004 // ITEM_TYPE_HTTPAGENT 1005 $data['timeout'] = $data['item']['timeout']; 1006 $data['url'] = $data['item']['url']; 1007 $data['query_fields'] = $data['item']['query_fields']; 1008 $data['posts'] = $data['item']['posts']; 1009 $data['status_codes'] = $data['item']['status_codes']; 1010 $data['follow_redirects'] = $data['item']['follow_redirects']; 1011 $data['post_type'] = $data['item']['post_type']; 1012 $data['http_proxy'] = $data['item']['http_proxy']; 1013 $data['headers'] = $data['item']['headers']; 1014 $data['retrieve_mode'] = $data['item']['retrieve_mode']; 1015 $data['request_method'] = $data['item']['request_method']; 1016 $data['allow_traps'] = $data['item']['allow_traps']; 1017 $data['ssl_cert_file'] = $data['item']['ssl_cert_file']; 1018 $data['ssl_key_file'] = $data['item']['ssl_key_file']; 1019 $data['ssl_key_password'] = $data['item']['ssl_key_password']; 1020 $data['verify_peer'] = $data['item']['verify_peer']; 1021 $data['verify_host'] = $data['item']['verify_host']; 1022 $data['http_authtype'] = $data['item']['authtype']; 1023 $data['http_username'] = $data['item']['username']; 1024 $data['http_password'] = $data['item']['password']; 1025 1026 if ($data['type'] == ITEM_TYPE_HTTPAGENT) { 1027 // Convert hash to array where every item is hash for single key value pair as it is used by view. 1028 $headers = []; 1029 1030 foreach ($data['headers'] as $key => $value) { 1031 $headers[] = [$key => $value]; 1032 } 1033 1034 $data['headers'] = $headers; 1035 } 1036 1037 $data['preprocessing'] = $data['item']['preprocessing']; 1038 1039 if (!$data['is_discovery_rule']) { 1040 $data['output_format'] = $data['item']['output_format']; 1041 } 1042 1043 if ($data['parent_discoveryid'] != 0) { 1044 $data['new_application_prototype'] = getRequest('new_application_prototype', ''); 1045 } 1046 1047 if (!$data['limited'] || !isset($_REQUEST['form_refresh'])) { 1048 $data['delay'] = $data['item']['delay']; 1049 1050 $update_interval_parser = new CUpdateIntervalParser([ 1051 'usermacros' => true, 1052 'lldmacros' => ($data['parent_discoveryid'] != 0) 1053 ]); 1054 1055 if ($update_interval_parser->parse($data['delay']) == CParser::PARSE_SUCCESS) { 1056 $data['delay'] = $update_interval_parser->getDelay(); 1057 1058 if ($data['delay'][0] !== '{') { 1059 $delay = timeUnitToSeconds($data['delay']); 1060 1061 if ($delay == 0 && ($data['type'] == ITEM_TYPE_TRAPPER || $data['type'] == ITEM_TYPE_SNMPTRAP 1062 || $data['type'] == ITEM_TYPE_DEPENDENT)) { 1063 $data['delay'] = ZBX_ITEM_DELAY_DEFAULT; 1064 } 1065 } 1066 1067 foreach ($update_interval_parser->getIntervals() as $interval) { 1068 if ($interval['type'] == ITEM_DELAY_FLEXIBLE) { 1069 $data['delay_flex'][] = [ 1070 'delay' => $interval['update_interval'], 1071 'period' => $interval['time_period'], 1072 'type' => ITEM_DELAY_FLEXIBLE 1073 ]; 1074 } 1075 else { 1076 $data['delay_flex'][] = [ 1077 'schedule' => $interval['interval'], 1078 'type' => ITEM_DELAY_SCHEDULING 1079 ]; 1080 } 1081 } 1082 } 1083 else { 1084 $data['delay'] = ZBX_ITEM_DELAY_DEFAULT; 1085 } 1086 1087 $data['history'] = $data['item']['history']; 1088 $data['status'] = $data['item']['status']; 1089 $data['trends'] = $data['item']['trends']; 1090 1091 $data['applications'] = array_unique(zbx_array_merge($data['applications'], get_applications_by_itemid($data['itemid']))); 1092 1093 if ($data['parent_discoveryid'] != 0) { 1094 /* 1095 * Get a list of application prototypes assigned to item prototype. Don't select distinct names, 1096 * since database can be accidentally created case insensitive. 1097 */ 1098 $application_prototypes = DBfetchArray(DBselect( 1099 'SELECT ap.name'. 1100 ' FROM application_prototype ap,item_application_prototype iap'. 1101 ' WHERE ap.application_prototypeid=iap.application_prototypeid'. 1102 ' AND ap.itemid='.zbx_dbstr($data['parent_discoveryid']). 1103 ' AND iap.itemid='.zbx_dbstr($data['itemid']) 1104 )); 1105 1106 // Merge form submitted data with data existing in DB to find diff and correctly display ListBox. 1107 $data['application_prototypes'] = array_unique( 1108 zbx_array_merge($data['application_prototypes'], zbx_objectValues($application_prototypes, 'name')) 1109 ); 1110 } 1111 } 1112 } 1113 1114 if (!$data['delay_flex']) { 1115 $data['delay_flex'][] = ['delay' => '', 'period' => '', 'type' => ITEM_DELAY_FLEXIBLE]; 1116 } 1117 1118 // applications 1119 if (count($data['applications']) == 0) { 1120 array_push($data['applications'], 0); 1121 } 1122 $data['db_applications'] = DBfetchArray(DBselect( 1123 'SELECT DISTINCT a.applicationid,a.name'. 1124 ' FROM applications a'. 1125 ' WHERE a.hostid='.zbx_dbstr($data['hostid']). 1126 (($data['parent_discoveryid'] != 0) ? ' AND a.flags='.ZBX_FLAG_DISCOVERY_NORMAL : '') 1127 )); 1128 order_result($data['db_applications'], 'name'); 1129 1130 if ($data['parent_discoveryid'] != 0) { 1131 // Make the application prototype list no appearing empty, but filling it with "-None-" as first element. 1132 if (count($data['application_prototypes']) == 0) { 1133 $data['application_prototypes'][] = 0; 1134 } 1135 1136 // Get a list of application prototypes by discovery rule. 1137 $data['db_application_prototypes'] = DBfetchArray(DBselect( 1138 'SELECT ap.application_prototypeid,ap.name'. 1139 ' FROM application_prototype ap'. 1140 ' WHERE ap.itemid='.zbx_dbstr($data['parent_discoveryid']) 1141 )); 1142 order_result($data['db_application_prototypes'], 'name'); 1143 } 1144 1145 // interfaces 1146 $data['interfaces'] = API::HostInterface()->get([ 1147 'hostids' => $data['hostid'], 1148 'output' => API_OUTPUT_EXTEND 1149 ]); 1150 // Sort interfaces to be listed starting with one selected as 'main'. 1151 CArrayHelper::sort($data['interfaces'], [ 1152 ['field' => 'main', 'order' => ZBX_SORT_DOWN], 1153 ['field' => 'interfaceid','order' => ZBX_SORT_UP] 1154 ]); 1155 1156 if ($data['limited'] || (array_key_exists('item', $data) && $data['parent_discoveryid'] == 0 1157 && $data['item']['flags'] == ZBX_FLAG_DISCOVERY_CREATED)) { 1158 if ($data['valuemapid'] != 0) { 1159 $valuemaps = API::ValueMap()->get([ 1160 'output' => ['name'], 1161 'valuemapids' => [$data['valuemapid']] 1162 ]); 1163 1164 if ($valuemaps) { 1165 $data['valuemaps'] = $valuemaps[0]['name']; 1166 } 1167 } 1168 } 1169 else { 1170 $data['valuemaps'] = API::ValueMap()->get([ 1171 'output' => ['valuemapid', 'name'] 1172 ]); 1173 1174 CArrayHelper::sort($data['valuemaps'], ['name']); 1175 } 1176 1177 // possible host inventories 1178 if ($data['parent_discoveryid'] == 0) { 1179 $data['possibleHostInventories'] = getHostInventories(); 1180 1181 // get already populated fields by other items 1182 $data['alreadyPopulated'] = API::item()->get([ 1183 'output' => ['inventory_link'], 1184 'filter' => ['hostid' => $data['hostid']], 1185 'nopermissions' => true 1186 ]); 1187 $data['alreadyPopulated'] = zbx_toHash($data['alreadyPopulated'], 'inventory_link'); 1188 } 1189 1190 // unset ssh auth fields 1191 if ($data['type'] != ITEM_TYPE_SSH) { 1192 $data['authtype'] = ITEM_AUTHTYPE_PASSWORD; 1193 $data['publickey'] = ''; 1194 $data['privatekey'] = ''; 1195 } 1196 1197 if ($data['type'] != ITEM_TYPE_DEPENDENT) { 1198 $data['master_itemid'] = 0; 1199 } 1200 1201 return $data; 1202} 1203 1204/** 1205 * Get list of item pre-processing data and return a prepared HTML object. 1206 * 1207 * @param CForm $form Form object to where add pre-processing list. 1208 * @param array $preprocessing Array of item pre-processing steps. 1209 * @param string $preprocessing[]['type'] Pre-processing step type. 1210 * @param array $preprocessing[]['params'] Additional parameters used by pre-processing. 1211 * @param string $preprocessing[]['error_handler'] Action type used in case of pre-processing step failure. 1212 * @param string $preprocessing[]['error_handler_params'] Error handler parameters. 1213 * @param bool $readonly True if fields should be read only. 1214 * @param array $types Supported pre-processing types. 1215 * 1216 * @return CList 1217 */ 1218function getItemPreprocessing(CForm $form, array $preprocessing, $readonly, array $types) { 1219 $script_maxlength = DB::getFieldLength('item_preproc', 'params'); 1220 $preprocessing_list = (new CList()) 1221 ->setId('preprocessing') 1222 ->addClass('preprocessing-list') 1223 ->addClass('list-numbered') 1224 ->addItem( 1225 (new CListItem([ 1226 (new CDiv(_('Name')))->addClass('step-name'), 1227 (new CDiv(_('Parameters')))->addClass('step-parameters'), 1228 (new CDiv(_('Custom on fail')))->addClass('step-on-fail'), 1229 (new CDiv(_('Actions')))->addClass('step-action') 1230 ])) 1231 ->addClass('preprocessing-list-head') 1232 ->addStyle(!$preprocessing ? 'display: none;' : null) 1233 ); 1234 1235 $sortable = (count($preprocessing) > 1 && !$readonly); 1236 1237 $i = 0; 1238 1239 foreach ($preprocessing as $step) { 1240 // Create a select with preprocessing types. 1241 $preproc_types_select = (new CSelect('preprocessing['.$i.'][type]')) 1242 ->setId('preprocessing_'.$i.'_type') 1243 ->setValue($step['type']) 1244 ->setReadonly($readonly) 1245 ->setWidthAuto(); 1246 1247 foreach (get_preprocessing_types(null, true, $types) as $group) { 1248 $opt_group = new CSelectOptionGroup($group['label']); 1249 1250 foreach ($group['types'] as $type => $label) { 1251 $opt_group->addOption(new CSelectOption($type, $label)); 1252 } 1253 1254 $preproc_types_select->addOptionGroup($opt_group); 1255 } 1256 1257 // Depending on preprocessing type, display corresponding params field and placeholders. 1258 $params = ''; 1259 1260 // Create a primary param text box, so it can be hidden if necessary. 1261 $step_param_0_value = array_key_exists('params', $step) ? $step['params'][0] : ''; 1262 $step_param_0 = (new CTextBox('preprocessing['.$i.'][params][0]', $step_param_0_value)) 1263 ->setTitle($step_param_0_value) 1264 ->setReadonly($readonly); 1265 1266 // Create a secondary param text box, so it can be hidden if necessary. 1267 $step_param_1_value = (array_key_exists('params', $step) && array_key_exists(1, $step['params'])) 1268 ? $step['params'][1] 1269 : ''; 1270 $step_param_1 = (new CTextBox('preprocessing['.$i.'][params][1]', $step_param_1_value)) 1271 ->setTitle($step_param_1_value) 1272 ->setReadonly($readonly); 1273 1274 // Add corresponding placeholders and show or hide text boxes. 1275 switch ($step['type']) { 1276 case ZBX_PREPROC_MULTIPLIER: 1277 $params = $step_param_0 1278 ->setAttribute('placeholder', _('number')) 1279 ->setWidth(ZBX_TEXTAREA_NUMERIC_BIG_WIDTH); 1280 break; 1281 1282 case ZBX_PREPROC_RTRIM: 1283 case ZBX_PREPROC_LTRIM: 1284 case ZBX_PREPROC_TRIM: 1285 $params = $step_param_0 1286 ->setAttribute('placeholder', _('list of characters')) 1287 ->setWidth(ZBX_TEXTAREA_SMALL_WIDTH); 1288 break; 1289 1290 case ZBX_PREPROC_XPATH: 1291 case ZBX_PREPROC_ERROR_FIELD_XML: 1292 $params = $step_param_0->setAttribute('placeholder', _('XPath')); 1293 break; 1294 1295 case ZBX_PREPROC_JSONPATH: 1296 case ZBX_PREPROC_ERROR_FIELD_JSON: 1297 $params = $step_param_0->setAttribute('placeholder', _('$.path.to.node')); 1298 break; 1299 1300 case ZBX_PREPROC_REGSUB: 1301 case ZBX_PREPROC_ERROR_FIELD_REGEX: 1302 $params = [ 1303 $step_param_0->setAttribute('placeholder', _('pattern')), 1304 $step_param_1->setAttribute('placeholder', _('output')) 1305 ]; 1306 break; 1307 1308 case ZBX_PREPROC_VALIDATE_RANGE: 1309 $params = [ 1310 $step_param_0->setAttribute('placeholder', _('min')), 1311 $step_param_1->setAttribute('placeholder', _('max')) 1312 ]; 1313 break; 1314 1315 case ZBX_PREPROC_VALIDATE_REGEX: 1316 case ZBX_PREPROC_VALIDATE_NOT_REGEX: 1317 $params = $step_param_0->setAttribute('placeholder', _('pattern')); 1318 break; 1319 1320 case ZBX_PREPROC_THROTTLE_TIMED_VALUE: 1321 $params = $step_param_0 1322 ->setAttribute('placeholder', _('seconds')) 1323 ->setWidth(ZBX_TEXTAREA_NUMERIC_BIG_WIDTH); 1324 break; 1325 1326 case ZBX_PREPROC_SCRIPT: 1327 $params = new CMultilineInput($step_param_0->getName(), $step_param_0_value, [ 1328 'title' => _('JavaScript'), 1329 'placeholder' => _('script'), 1330 'placeholder_textarea' => 'return value', 1331 'label_before' => 'function (value) {', 1332 'label_after' => '}', 1333 'grow' => 'auto', 1334 'rows' => 0, 1335 'maxlength' => $script_maxlength, 1336 'readonly' => $readonly 1337 ]); 1338 break; 1339 1340 case ZBX_PREPROC_PROMETHEUS_PATTERN: 1341 $params = [ 1342 $step_param_0->setAttribute('placeholder', 1343 _('<metric name>{<label name>="<label value>", ...} == <value>') 1344 ), 1345 $step_param_1->setAttribute('placeholder', _('<label name>')) 1346 ]; 1347 break; 1348 1349 case ZBX_PREPROC_PROMETHEUS_TO_JSON: 1350 $params = $step_param_0->setAttribute('placeholder', 1351 _('<metric name>{<label name>="<label value>", ...} == <value>') 1352 ); 1353 break; 1354 1355 // ZBX-16642 1356 case ZBX_PREPROC_CSV_TO_JSON: 1357 $step_param_2_value = (array_key_exists('params', $step) && array_key_exists(2, $step['params'])) 1358 ? $step['params'][2] 1359 : ZBX_PREPROC_CSV_NO_HEADER; 1360 1361 $params = [ 1362 $step_param_0 1363 ->setAttribute('placeholder', ',') 1364 ->setWidth(ZBX_TEXTAREA_NUMERIC_STANDARD_WIDTH) 1365 ->setAttribute('maxlength', 1), 1366 $step_param_1 1367 ->setAttribute('placeholder', '"') 1368 ->setWidth(ZBX_TEXTAREA_NUMERIC_STANDARD_WIDTH) 1369 ->setAttribute('maxlength', 1), 1370 (new CCheckBox('preprocessing['.$i.'][params][2]', ZBX_PREPROC_CSV_HEADER)) 1371 ->setLabel(_('With header row')) 1372 ->setChecked($step_param_2_value == ZBX_PREPROC_CSV_HEADER) 1373 ->setReadonly($readonly) 1374 ]; 1375 break; 1376 1377 case ZBX_PREPROC_STR_REPLACE: 1378 $params = [ 1379 $step_param_0->setAttribute('placeholder', _('search string')), 1380 $step_param_1->setAttribute('placeholder', _('replacement')) 1381 ]; 1382 break; 1383 } 1384 1385 // Create checkbox "Custom on fail" and enable or disable depending on preprocessing type. 1386 $on_fail = new CCheckBox('preprocessing['.$i.'][on_fail]'); 1387 1388 switch ($step['type']) { 1389 case ZBX_PREPROC_RTRIM: 1390 case ZBX_PREPROC_LTRIM: 1391 case ZBX_PREPROC_TRIM: 1392 case ZBX_PREPROC_THROTTLE_VALUE: 1393 case ZBX_PREPROC_THROTTLE_TIMED_VALUE: 1394 case ZBX_PREPROC_SCRIPT: 1395 case ZBX_PREPROC_STR_REPLACE: 1396 $on_fail->setEnabled(false); 1397 break; 1398 1399 default: 1400 $on_fail->setEnabled(!$readonly); 1401 1402 if ($step['error_handler'] != ZBX_PREPROC_FAIL_DEFAULT) { 1403 $on_fail->setChecked(true); 1404 } 1405 break; 1406 } 1407 1408 $error_handler = (new CRadioButtonList('preprocessing['.$i.'][error_handler]', 1409 ($step['error_handler'] == ZBX_PREPROC_FAIL_DEFAULT) 1410 ? ZBX_PREPROC_FAIL_DISCARD_VALUE 1411 : (int) $step['error_handler'] 1412 )) 1413 ->addValue(_('Discard value'), ZBX_PREPROC_FAIL_DISCARD_VALUE) 1414 ->addValue(_('Set value to'), ZBX_PREPROC_FAIL_SET_VALUE) 1415 ->addValue(_('Set error to'), ZBX_PREPROC_FAIL_SET_ERROR) 1416 ->setModern(true); 1417 1418 $error_handler_params = (new CTextBox('preprocessing['.$i.'][error_handler_params]', 1419 $step['error_handler_params']) 1420 )->setTitle($step['error_handler_params']); 1421 1422 if ($step['error_handler'] == ZBX_PREPROC_FAIL_DEFAULT) { 1423 $error_handler->setEnabled(false); 1424 } 1425 1426 if ($step['error_handler'] == ZBX_PREPROC_FAIL_DEFAULT 1427 || $step['error_handler'] == ZBX_PREPROC_FAIL_DISCARD_VALUE) { 1428 $error_handler_params 1429 ->setEnabled(false) 1430 ->addStyle('display: none;'); 1431 } 1432 1433 $on_fail_options = (new CDiv([ 1434 new CLabel(_('Custom on fail')), 1435 $error_handler->setReadonly($readonly), 1436 $error_handler_params->setReadonly($readonly) 1437 ]))->addClass('on-fail-options'); 1438 1439 if ($step['error_handler'] == ZBX_PREPROC_FAIL_DEFAULT) { 1440 $on_fail_options->addStyle('display: none;'); 1441 } 1442 1443 $preprocessing_list->addItem( 1444 (new CListItem([ 1445 (new CDiv([ 1446 (new CDiv()) 1447 ->addClass(ZBX_STYLE_DRAG_ICON) 1448 ->addClass(!$sortable ? ZBX_STYLE_DISABLED : null), 1449 (new CDiv($preproc_types_select)) 1450 ->addClass('list-numbered-item') 1451 ->addClass('step-name'), 1452 (new CDiv($params))->addClass('step-parameters'), 1453 (new CDiv($on_fail))->addClass('step-on-fail'), 1454 (new CDiv([ 1455 (new CButton('preprocessing['.$i.'][test]', _('Test'))) 1456 ->addClass(ZBX_STYLE_BTN_LINK) 1457 ->addClass('preprocessing-step-test') 1458 ->removeId(), 1459 (new CButton('preprocessing['.$i.'][remove]', _('Remove'))) 1460 ->addClass(ZBX_STYLE_BTN_LINK) 1461 ->addClass('element-table-remove') 1462 ->setEnabled(!$readonly) 1463 ->removeId() 1464 ]))->addClass('step-action') 1465 ]))->addClass('preprocessing-step'), 1466 $on_fail_options 1467 ])) 1468 ->addClass('preprocessing-list-item') 1469 ->addClass('sortable') 1470 ->setAttribute('data-step', $i) 1471 ); 1472 1473 $i++; 1474 } 1475 1476 $preprocessing_list->addItem( 1477 (new CListItem([ 1478 (new CDiv( 1479 (new CButton('param_add', _('Add'))) 1480 ->addClass(ZBX_STYLE_BTN_LINK) 1481 ->addClass('element-table-add') 1482 ->setEnabled(!$readonly) 1483 ))->addClass('step-action'), 1484 (new CDiv( 1485 (new CButton('preproc_test_all', _('Test all steps'))) 1486 ->addClass(ZBX_STYLE_BTN_LINK) 1487 ->addStyle(($i > 0) ? null : 'display: none') 1488 ))->addClass('step-action') 1489 ]))->addClass('preprocessing-list-foot') 1490 ); 1491 1492 return $preprocessing_list; 1493} 1494 1495/** 1496 * Prepares data to copy items/triggers/graphs. 1497 * 1498 * @param string $elements_field 1499 * @param null|string $title 1500 * 1501 * @return array 1502 */ 1503function getCopyElementsFormData($elements_field, $title = null) { 1504 $data = [ 1505 'title' => $title, 1506 'elements_field' => $elements_field, 1507 'elements' => getRequest($elements_field, []), 1508 'copy_type' => getRequest('copy_type', COPY_TYPE_TO_HOST_GROUP), 1509 'copy_targetids' => getRequest('copy_targetids', []), 1510 'hostid' => getRequest('hostid', 0) 1511 ]; 1512 1513 if (!$data['elements'] || !is_array($data['elements'])) { 1514 show_error_message(_('Incorrect list of items.')); 1515 1516 return $data; 1517 } 1518 1519 if ($data['copy_targetids']) { 1520 switch ($data['copy_type']) { 1521 case COPY_TYPE_TO_HOST_GROUP: 1522 $data['copy_targetids'] = CArrayHelper::renameObjectsKeys(API::HostGroup()->get([ 1523 'output' => ['groupid', 'name'], 1524 'groupids' => $data['copy_targetids'], 1525 'editable' => true 1526 ]), ['groupid' => 'id']); 1527 break; 1528 1529 case COPY_TYPE_TO_HOST: 1530 $data['copy_targetids'] = CArrayHelper::renameObjectsKeys(API::Host()->get([ 1531 'output' => ['hostid', 'name'], 1532 'hostids' => $data['copy_targetids'], 1533 'editable' => true 1534 ]), ['hostid' => 'id']); 1535 break; 1536 1537 case COPY_TYPE_TO_TEMPLATE: 1538 $data['copy_targetids'] = CArrayHelper::renameObjectsKeys(API::Template()->get([ 1539 'output' => ['templateid', 'name'], 1540 'templateids' => $data['copy_targetids'], 1541 'editable' => true 1542 ]), ['templateid' => 'id']); 1543 } 1544 } 1545 1546 return $data; 1547} 1548 1549function getTriggerMassupdateFormData() { 1550 $data = [ 1551 'visible' => getRequest('visible', []), 1552 'dependencies' => getRequest('dependencies', []), 1553 'tags' => getRequest('tags', []), 1554 'mass_update_tags' => getRequest('mass_update_tags', ZBX_ACTION_ADD), 1555 'manual_close' => getRequest('manual_close', ZBX_TRIGGER_MANUAL_CLOSE_NOT_ALLOWED), 1556 'massupdate' => getRequest('massupdate', 1), 1557 'parent_discoveryid' => getRequest('parent_discoveryid'), 1558 'g_triggerid' => getRequest('g_triggerid', []), 1559 'priority' => getRequest('priority', 0), 1560 'config' => select_config(), 1561 'hostid' => getRequest('hostid', 0) 1562 ]; 1563 1564 if ($data['dependencies']) { 1565 $dependencyTriggers = API::Trigger()->get([ 1566 'output' => ['triggerid', 'description', 'flags'], 1567 'selectHosts' => ['hostid', 'name'], 1568 'triggerids' => $data['dependencies'], 1569 'preservekeys' => true 1570 ]); 1571 1572 if ($data['parent_discoveryid']) { 1573 $dependencyTriggerPrototypes = API::TriggerPrototype()->get([ 1574 'output' => ['triggerid', 'description', 'flags'], 1575 'selectHosts' => ['hostid', 'name'], 1576 'triggerids' => $data['dependencies'], 1577 'preservekeys' => true 1578 ]); 1579 $data['dependencies'] = $dependencyTriggers + $dependencyTriggerPrototypes; 1580 } 1581 else { 1582 $data['dependencies'] = $dependencyTriggers; 1583 } 1584 } 1585 1586 foreach ($data['dependencies'] as &$dependency) { 1587 order_result($dependency['hosts'], 'name', ZBX_SORT_UP); 1588 } 1589 unset($dependency); 1590 1591 order_result($data['dependencies'], 'description', ZBX_SORT_UP); 1592 1593 if (!$data['tags']) { 1594 $data['tags'][] = ['tag' => '', 'value' => '']; 1595 } 1596 1597 return $data; 1598} 1599 1600/** 1601 * Generate data for the trigger configuration form. 1602 * 1603 * @param array $data Trigger data array. 1604 * @param string $data['form'] Form action. 1605 * @param string $data['form_refresh'] Form refresh. 1606 * @param null|string $data['parent_discoveryid'] Parent discovery ID. 1607 * @param array $data['dependencies'] Trigger dependencies. 1608 * @param array $data['db_dependencies'] DB trigger dependencies. 1609 * @param string $data['triggerid'] Trigger ID. 1610 * @param string $data['expression'] Trigger expression. 1611 * @param string $data['recovery_expression'] Trigger recovery expression. 1612 * @param string $data['expr_temp'] Trigger temporary expression. 1613 * @param string $data['recovery_expr_temp'] Trigger temporary recovery expression. 1614 * @param string $data['recovery_mode'] Trigger recovery mode. 1615 * @param string $data['description'] Trigger description. 1616 * @param int $data['type'] Trigger problem event generation mode. 1617 * @param string $data['priority'] Trigger severity. 1618 * @param int $data['status'] Trigger status. 1619 * @param string $data['comments'] Trigger description. 1620 * @param string $data['url'] Trigger URL. 1621 * @param string $data['expression_constructor'] Trigger expression constructor mode. 1622 * @param string $data['recovery_expression_constructor'] Trigger recovery expression constructor mode. 1623 * @param bool $data['limited'] Templated trigger. 1624 * @param array $data['templates'] Trigger templates. 1625 * @param string $data['hostid'] Host ID. 1626 * @param string $data['expression_action'] Trigger expression action. 1627 * @param string $data['recovery_expression_action'] Trigger recovery expression action. 1628 * 1629 * @return array 1630 */ 1631function getTriggerFormData(array $data) { 1632 if ($data['triggerid'] !== null) { 1633 // Get trigger. 1634 $options = [ 1635 'output' => API_OUTPUT_EXTEND, 1636 'selectHosts' => ['hostid'], 1637 'triggerids' => $data['triggerid'] 1638 ]; 1639 1640 if (!hasRequest('form_refresh')) { 1641 $options['selectTags'] = ['tag', 'value']; 1642 } 1643 1644 if ($data['show_inherited_tags']) { 1645 $options['selectItems'] = ['itemid', 'templateid', 'flags']; 1646 } 1647 1648 if ($data['parent_discoveryid'] === null) { 1649 $options['selectDiscoveryRule'] = ['itemid', 'name', 'templateid']; 1650 $options['selectTriggerDiscovery'] = ['parent_triggerid']; 1651 $triggers = API::Trigger()->get($options); 1652 $flag = ZBX_FLAG_DISCOVERY_NORMAL; 1653 } 1654 else { 1655 $triggers = API::TriggerPrototype()->get($options); 1656 $flag = ZBX_FLAG_DISCOVERY_PROTOTYPE; 1657 } 1658 1659 $triggers = CMacrosResolverHelper::resolveTriggerExpressions($triggers, 1660 ['sources' => ['expression', 'recovery_expression']] 1661 ); 1662 1663 $trigger = reset($triggers); 1664 1665 if (!hasRequest('form_refresh')) { 1666 $data['tags'] = $trigger['tags']; 1667 } 1668 1669 // Get templates. 1670 $data['templates'] = makeTriggerTemplatesHtml($trigger['triggerid'], 1671 getTriggerParentTemplates([$trigger], $flag), $flag 1672 ); 1673 1674 if ($data['show_inherited_tags']) { 1675 if ($data['parent_discoveryid'] === null) { 1676 if ($trigger['discoveryRule']) { 1677 $item_parent_templates = getItemParentTemplates([$trigger['discoveryRule']], 1678 ZBX_FLAG_DISCOVERY_RULE 1679 )['templates']; 1680 } 1681 else { 1682 $item_parent_templates = getItemParentTemplates($trigger['items'], 1683 ZBX_FLAG_DISCOVERY_NORMAL 1684 )['templates']; 1685 } 1686 } 1687 else { 1688 $items = []; 1689 $item_prototypes = []; 1690 1691 foreach ($trigger['items'] as $item) { 1692 if ($item['flags'] == ZBX_FLAG_DISCOVERY_NORMAL) { 1693 $items[] = $item; 1694 } 1695 else { 1696 $item_prototypes[] = $item; 1697 } 1698 } 1699 1700 $item_parent_templates = getItemParentTemplates($items, ZBX_FLAG_DISCOVERY_NORMAL)['templates'] 1701 + getItemParentTemplates($item_prototypes, ZBX_FLAG_DISCOVERY_PROTOTYPE)['templates']; 1702 } 1703 unset($item_parent_templates[0]); 1704 1705 $db_templates = $item_parent_templates 1706 ? API::Template()->get([ 1707 'output' => ['templateid'], 1708 'selectTags' => ['tag', 'value'], 1709 'templateids' => array_keys($item_parent_templates), 1710 'preservekeys' => true 1711 ]) 1712 : []; 1713 1714 $inherited_tags = []; 1715 1716 foreach ($item_parent_templates as $templateid => $template) { 1717 if (array_key_exists($templateid, $db_templates)) { 1718 foreach ($db_templates[$templateid]['tags'] as $tag) { 1719 if (array_key_exists($tag['tag'], $inherited_tags) 1720 && array_key_exists($tag['value'], $inherited_tags[$tag['tag']])) { 1721 $inherited_tags[$tag['tag']][$tag['value']]['parent_templates'] += [ 1722 $templateid => $template 1723 ]; 1724 } 1725 else { 1726 $inherited_tags[$tag['tag']][$tag['value']] = $tag + [ 1727 'parent_templates' => [$templateid => $template], 1728 'type' => ZBX_PROPERTY_INHERITED 1729 ]; 1730 } 1731 } 1732 } 1733 } 1734 1735 $db_hosts = API::Host()->get([ 1736 'output' => [], 1737 'selectTags' => ['tag', 'value'], 1738 'hostids' => $data['hostid'] 1739 ]); 1740 1741 if ($db_hosts) { 1742 foreach ($db_hosts[0]['tags'] as $tag) { 1743 $inherited_tags[$tag['tag']][$tag['value']] = $tag; 1744 $inherited_tags[$tag['tag']][$tag['value']]['type'] = ZBX_PROPERTY_INHERITED; 1745 } 1746 } 1747 1748 foreach ($data['tags'] as $tag) { 1749 if (array_key_exists($tag['tag'], $inherited_tags) 1750 && array_key_exists($tag['value'], $inherited_tags[$tag['tag']])) { 1751 $inherited_tags[$tag['tag']][$tag['value']]['type'] = ZBX_PROPERTY_BOTH; 1752 } 1753 else { 1754 $inherited_tags[$tag['tag']][$tag['value']] = $tag + ['type' => ZBX_PROPERTY_OWN]; 1755 } 1756 } 1757 1758 $data['tags'] = []; 1759 1760 foreach ($inherited_tags as $tag) { 1761 foreach ($tag as $value) { 1762 $data['tags'][] = $value; 1763 } 1764 } 1765 } 1766 1767 $data['limited'] = ($trigger['templateid'] != 0); 1768 1769 // Select first host from triggers if no matching value is given. 1770 $hosts = $trigger['hosts']; 1771 if (count($hosts) > 0 && !in_array(['hostid' => $data['hostid']], $hosts)) { 1772 $host = reset($hosts); 1773 $data['hostid'] = $host['hostid']; 1774 } 1775 } 1776 1777 // tags 1778 if (!$data['tags']) { 1779 $data['tags'][] = ['tag' => '', 'value' => '']; 1780 } 1781 else { 1782 CArrayHelper::sort($data['tags'], ['tag', 'value']); 1783 } 1784 1785 if ((!empty($data['triggerid']) && !isset($_REQUEST['form_refresh'])) || $data['limited']) { 1786 $data['expression'] = $trigger['expression']; 1787 $data['recovery_expression'] = $trigger['recovery_expression']; 1788 1789 if (!$data['limited'] || !isset($_REQUEST['form_refresh'])) { 1790 $data['description'] = $trigger['description']; 1791 $data['opdata'] = $trigger['opdata']; 1792 $data['type'] = $trigger['type']; 1793 $data['recovery_mode'] = $trigger['recovery_mode']; 1794 $data['correlation_mode'] = $trigger['correlation_mode']; 1795 $data['correlation_tag'] = $trigger['correlation_tag']; 1796 $data['manual_close'] = $trigger['manual_close']; 1797 $data['priority'] = $trigger['priority']; 1798 $data['status'] = $trigger['status']; 1799 $data['comments'] = $trigger['comments']; 1800 $data['url'] = $trigger['url']; 1801 1802 if ($data['parent_discoveryid'] !== null) { 1803 $data['discover'] = $trigger['discover']; 1804 } 1805 1806 $db_triggers = DBselect( 1807 'SELECT t.triggerid,t.description'. 1808 ' FROM triggers t,trigger_depends d'. 1809 ' WHERE t.triggerid=d.triggerid_up'. 1810 ' AND d.triggerid_down='.zbx_dbstr($data['triggerid']) 1811 ); 1812 while ($db_trigger = DBfetch($db_triggers)) { 1813 if (uint_in_array($db_trigger['triggerid'], $data['dependencies'])) { 1814 continue; 1815 } 1816 array_push($data['dependencies'], $db_trigger['triggerid']); 1817 } 1818 } 1819 } 1820 1821 $readonly = false; 1822 if ($data['triggerid'] !== null) { 1823 $data['flags'] = $trigger['flags']; 1824 1825 if ($data['parent_discoveryid'] === null) { 1826 $data['discoveryRule'] = $trigger['discoveryRule']; 1827 $data['triggerDiscovery'] = $trigger['triggerDiscovery']; 1828 } 1829 1830 if ($trigger['flags'] == ZBX_FLAG_DISCOVERY_CREATED || $data['limited']) { 1831 $readonly = true; 1832 } 1833 } 1834 1835 // Trigger expression constructor. 1836 if ($data['expression_constructor'] == IM_TREE) { 1837 $analyze = analyzeExpression($data['expression'], TRIGGER_EXPRESSION); 1838 1839 if ($analyze !== false) { 1840 list($data['expression_formula'], $data['expression_tree']) = $analyze; 1841 1842 if ($data['expression_action'] !== '' && $data['expression_tree'] !== null) { 1843 $new_expr = remakeExpression($data['expression'], $_REQUEST['expr_target_single'], 1844 $data['expression_action'], $data['expr_temp'] 1845 ); 1846 1847 if ($new_expr !== false) { 1848 $data['expression'] = $new_expr; 1849 $analyze = analyzeExpression($data['expression'], TRIGGER_EXPRESSION); 1850 1851 if ($analyze !== false) { 1852 list($data['expression_formula'], $data['expression_tree']) = $analyze; 1853 } 1854 else { 1855 show_messages(false, '', _('Expression syntax error.')); 1856 } 1857 1858 $data['expr_temp'] = ''; 1859 } 1860 else { 1861 show_messages(false, '', _('Expression syntax error.')); 1862 } 1863 } 1864 1865 $data['expression_field_name'] = 'expr_temp'; 1866 $data['expression_field_value'] = $data['expr_temp']; 1867 $data['expression_field_readonly'] = true; 1868 } 1869 else { 1870 show_messages(false, '', _('Expression syntax error.')); 1871 $data['expression_field_name'] = 'expression'; 1872 $data['expression_field_value'] = $data['expression']; 1873 $data['expression_field_readonly'] = $readonly; 1874 $data['expression_constructor'] = IM_ESTABLISHED; 1875 } 1876 } 1877 elseif ($data['expression_constructor'] != IM_TREE) { 1878 $data['expression_field_name'] = 'expression'; 1879 $data['expression_field_value'] = $data['expression']; 1880 $data['expression_field_readonly'] = $readonly; 1881 } 1882 1883 // Trigger recovery expression constructor. 1884 if ($data['recovery_expression_constructor'] == IM_TREE) { 1885 $analyze = analyzeExpression($data['recovery_expression'], TRIGGER_RECOVERY_EXPRESSION); 1886 1887 if ($analyze !== false) { 1888 list($data['recovery_expression_formula'], $data['recovery_expression_tree']) = $analyze; 1889 1890 if ($data['recovery_expression_action'] !== '' && $data['recovery_expression_tree'] !== null) { 1891 $new_expr = remakeExpression($data['recovery_expression'], $_REQUEST['recovery_expr_target_single'], 1892 $data['recovery_expression_action'], $data['recovery_expr_temp'] 1893 ); 1894 1895 if ($new_expr !== false) { 1896 $data['recovery_expression'] = $new_expr; 1897 $analyze = analyzeExpression($data['recovery_expression'], TRIGGER_RECOVERY_EXPRESSION); 1898 1899 if ($analyze !== false) { 1900 list($data['recovery_expression_formula'], $data['recovery_expression_tree']) = $analyze; 1901 } 1902 else { 1903 show_messages(false, '', _('Recovery expression syntax error.')); 1904 } 1905 1906 $data['recovery_expr_temp'] = ''; 1907 } 1908 else { 1909 show_messages(false, '', _('Recovery expression syntax error.')); 1910 } 1911 } 1912 1913 $data['recovery_expression_field_name'] = 'recovery_expr_temp'; 1914 $data['recovery_expression_field_value'] = $data['recovery_expr_temp']; 1915 $data['recovery_expression_field_readonly'] = true; 1916 } 1917 else { 1918 show_messages(false, '', _('Recovery expression syntax error.')); 1919 $data['recovery_expression_field_name'] = 'recovery_expression'; 1920 $data['recovery_expression_field_value'] = $data['recovery_expression']; 1921 $data['recovery_expression_field_readonly'] = $readonly; 1922 $data['recovery_expression_constructor'] = IM_ESTABLISHED; 1923 } 1924 } 1925 elseif ($data['recovery_expression_constructor'] != IM_TREE) { 1926 $data['recovery_expression_field_name'] = 'recovery_expression'; 1927 $data['recovery_expression_field_value'] = $data['recovery_expression']; 1928 $data['recovery_expression_field_readonly'] = $readonly; 1929 } 1930 1931 if ($data['dependencies']) { 1932 $dependencyTriggers = API::Trigger()->get([ 1933 'output' => ['triggerid', 'description', 'flags'], 1934 'selectHosts' => ['hostid', 'name'], 1935 'triggerids' => $data['dependencies'], 1936 'preservekeys' => true 1937 ]); 1938 1939 if ($data['parent_discoveryid']) { 1940 $dependencyTriggerPrototypes = API::TriggerPrototype()->get([ 1941 'output' => ['triggerid', 'description', 'flags'], 1942 'selectHosts' => ['hostid', 'name'], 1943 'triggerids' => $data['dependencies'], 1944 'preservekeys' => true 1945 ]); 1946 1947 $data['db_dependencies'] = $dependencyTriggers + $dependencyTriggerPrototypes; 1948 } 1949 else { 1950 $data['db_dependencies'] = $dependencyTriggers; 1951 } 1952 } 1953 1954 foreach ($data['db_dependencies'] as &$dependency) { 1955 order_result($dependency['hosts'], 'name', ZBX_SORT_UP); 1956 } 1957 unset($dependency); 1958 1959 order_result($data['db_dependencies'], 'description'); 1960 1961 return $data; 1962} 1963 1964/** 1965 * Renders tag table row. 1966 * 1967 * @param int|string $index 1968 * @param string $tag (optional) 1969 * @param string $value (optional) 1970 * @param array $options (optional) 1971 * 1972 * @return CRow 1973 */ 1974function renderTagTableRow($index, $tag = '', $value = '', array $options = []) { 1975 $options = array_merge([ 1976 'readonly' => false, 1977 'field_name' => 'tags' 1978 ], $options); 1979 1980 return (new CRow([ 1981 (new CCol( 1982 (new CTextAreaFlexible($options['field_name'].'['.$index.'][tag]', $tag, $options)) 1983 ->setWidth(ZBX_TEXTAREA_TAG_WIDTH) 1984 ->setAttribute('placeholder', _('tag')) 1985 ))->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_PARENT), 1986 (new CCol( 1987 (new CTextAreaFlexible($options['field_name'].'['.$index.'][value]', $value, $options)) 1988 ->setWidth(ZBX_TEXTAREA_TAG_VALUE_WIDTH) 1989 ->setAttribute('placeholder', _('value')) 1990 ))->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_PARENT), 1991 (new CButton($options['field_name'].'['.$index.'][remove]', _('Remove'))) 1992 ->addClass(ZBX_STYLE_BTN_LINK) 1993 ->addClass('element-table-remove') 1994 ->setEnabled(!$options['readonly']) 1995 ]))->addClass('form_row'); 1996} 1997 1998/** 1999 * Renders tag table. 2000 * 2001 * @param array $tags 2002 * @param array $tags[]['tag'] 2003 * @param array $tags[]['value'] 2004 * @param bool $readonly (optional) 2005 * 2006 * @return CTable 2007 */ 2008function renderTagTable(array $tags, $readonly = false, array $options = []) { 2009 $table = (new CTable())->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_CONTAINER); 2010 2011 $row_options = ['readonly' => $readonly]; 2012 2013 if (array_key_exists('field_name', $options)) { 2014 $row_options['field_name'] = $options['field_name']; 2015 } 2016 2017 foreach ($tags as $index => $tag) { 2018 $table->addRow(renderTagTableRow($index, $tag['tag'], $tag['value'], $row_options)); 2019 } 2020 2021 return $table->setFooter(new CCol( 2022 (new CButton('tag_add', _('Add'))) 2023 ->addClass(ZBX_STYLE_BTN_LINK) 2024 ->addClass('element-table-add') 2025 ->setEnabled(!$readonly) 2026 )); 2027} 2028