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 italic($str) { 23 if (is_array($str)) { 24 foreach ($str as $key => $val) { 25 if (is_string($val)) { 26 $em = new CTag('em', true); 27 $em->addItem($val); 28 $str[$key] = $em; 29 } 30 } 31 } 32 elseif (is_string($str)) { 33 $em = new CTag('em', true, ''); 34 $em->addItem($str); 35 $str = $em; 36 } 37 return $str; 38} 39 40function bold($str) { 41 if (is_array($str)) { 42 foreach ($str as $key => $val) { 43 if (is_string($val)) { 44 $str[$key] = new CTag('b', true, $val); 45 } 46 } 47 48 return $str; 49 } 50 51 return new CTag('b', true, $str); 52} 53 54function make_decoration($haystack, $needle, $class = null) { 55 $result = $haystack; 56 57 $tmpHaystack = mb_strtolower($haystack); 58 $tmpNeedle = mb_strtolower($needle); 59 $pos = mb_strpos($tmpHaystack, $tmpNeedle); 60 61 if ($pos !== false) { 62 $start = CHtml::encode(mb_substr($haystack, 0, $pos)); 63 $end = CHtml::encode(mb_substr($haystack, $pos + mb_strlen($needle))); 64 $found = CHtml::encode(mb_substr($haystack, $pos, mb_strlen($needle))); 65 66 if (is_null($class)) { 67 $result = [$start, bold($found), $end]; 68 } 69 else { 70 $result = [$start, (new CSpan($found))->addClass($class), $end]; 71 } 72 } 73 74 return $result; 75} 76 77function prepareUrlParam($value, $name = null) { 78 if (is_array($value)) { 79 $result = ''; 80 81 foreach ($value as $key => $param) { 82 $result .= prepareUrlParam($param, isset($name) ? $name.'['.$key.']' : $key); 83 } 84 } 85 else { 86 $result = '&'.$name.'='.urlencode($value); 87 } 88 89 return $result; 90} 91 92/** 93 * Get ready for url params. 94 * 95 * @param mixed $param param name or array with data depend from $getFromRequest 96 * @param bool $getFromRequest detect data source - input array or $_REQUEST variable 97 * @param string $name if $_REQUEST variable is used this variable not used 98 * 99 * @return string 100 */ 101function url_param($param, $getFromRequest = true, $name = null) { 102 if (is_array($param)) { 103 if ($getFromRequest) { 104 fatal_error(_('URL parameter cannot be array.')); 105 } 106 } 107 else { 108 if (is_null($name)) { 109 if (!$getFromRequest) { 110 fatal_error(_('URL parameter name is empty.')); 111 } 112 113 $name = $param; 114 } 115 } 116 117 if ($getFromRequest) { 118 $value =& $_REQUEST[$param]; 119 } 120 else { 121 $value =& $param; 122 } 123 124 return isset($value) ? prepareUrlParam($value, $name) : ''; 125} 126 127function url_params(array $params) { 128 $result = ''; 129 130 foreach ($params as $param) { 131 $result .= url_param($param); 132 } 133 134 return $result; 135} 136 137function BR() { 138 return new CTag('br'); 139} 140 141function get_icon($type, $params = []) { 142 switch ($type) { 143 case 'favourite': 144 if (CFavorite::exists($params['fav'], $params['elid'], $params['elname'])) { 145 $icon = (new CRedirectButton(SPACE, null)) 146 ->addClass(ZBX_STYLE_BTN_REMOVE_FAV) 147 ->setTitle(_('Remove from favourites')) 148 ->onClick('rm4favorites("'.$params['elname'].'", "'.$params['elid'].'");'); 149 } 150 else { 151 $icon = (new CRedirectButton(SPACE, null)) 152 ->addClass(ZBX_STYLE_BTN_ADD_FAV) 153 ->setTitle(_('Add to favourites')) 154 ->onClick('add2favorites("'.$params['elname'].'", "'.$params['elid'].'");'); 155 } 156 $icon->setId('addrm_fav'); 157 158 return $icon; 159 160 case 'kioskmode': 161 if ($params['mode'] == ZBX_LAYOUT_KIOSKMODE) { 162 $icon = (new CButton(null, ' ')) 163 ->setTitle(_('Normal view')) 164 ->setAttribute('data-layout-mode', ZBX_LAYOUT_NORMAL) 165 ->addClass(ZBX_LAYOUT_MODE) 166 ->addClass(ZBX_STYLE_BTN_DASHBOARD_NORMAL) 167 ->addClass(ZBX_STYLE_BTN_MIN); 168 } 169 else { 170 $icon = (new CButton(null, ' ')) 171 ->setTitle(_('Kiosk mode')) 172 ->setAttribute('data-layout-mode', ZBX_LAYOUT_KIOSKMODE) 173 ->addClass(ZBX_LAYOUT_MODE) 174 ->addClass(ZBX_STYLE_BTN_KIOSK); 175 } 176 177 return $icon; 178 179 case 'overviewhelp': 180 return (new CRedirectButton(SPACE, null)) 181 ->addClass(ZBX_STYLE_BTN_INFO); 182 } 183} 184 185/** 186 * Get host/template configuration navigation. 187 * 188 * @param string $current_element 189 * @param int $hostid 190 * @param int $lld_ruleid 191 * 192 * @return CList|null 193 */ 194function getHostNavigation($current_element, $hostid, $lld_ruleid = 0) { 195 $options = [ 196 'output' => [ 197 'hostid', 'status', 'name', 'maintenance_status', 'flags' 198 ], 199 'selectHostDiscovery' => ['ts_delete'], 200 'selectInterfaces' => ['type', 'useip', 'ip', 'dns', 'port', 'version', 'details', 'available', 'error'], 201 'hostids' => [$hostid], 202 'editable' => true 203 ]; 204 if ($lld_ruleid == 0) { 205 $options['selectItems'] = API_OUTPUT_COUNT; 206 $options['selectTriggers'] = API_OUTPUT_COUNT; 207 $options['selectGraphs'] = API_OUTPUT_COUNT; 208 $options['selectDiscoveries'] = API_OUTPUT_COUNT; 209 $options['selectHttpTests'] = API_OUTPUT_COUNT; 210 } 211 212 // get hosts 213 $db_host = API::Host()->get($options); 214 215 if (!$db_host) { 216 $options = [ 217 'output' => ['templateid', 'name', 'flags'], 218 'templateids' => [$hostid], 219 'editable' => true 220 ]; 221 if ($lld_ruleid == 0) { 222 $options['selectItems'] = API_OUTPUT_COUNT; 223 $options['selectTriggers'] = API_OUTPUT_COUNT; 224 $options['selectGraphs'] = API_OUTPUT_COUNT; 225 $options['selectDashboards'] = API_OUTPUT_COUNT; 226 $options['selectDiscoveries'] = API_OUTPUT_COUNT; 227 $options['selectHttpTests'] = API_OUTPUT_COUNT; 228 } 229 230 // get templates 231 $db_host = API::Template()->get($options); 232 233 $is_template = true; 234 } 235 else { 236 $is_template = false; 237 } 238 239 if (!$db_host) { 240 return null; 241 } 242 243 $db_host = reset($db_host); 244 245 // get lld-rules 246 if ($lld_ruleid != 0) { 247 $db_discovery_rule = API::DiscoveryRule()->get([ 248 'output' => ['name'], 249 'selectItems' => API_OUTPUT_COUNT, 250 'selectTriggers' => API_OUTPUT_COUNT, 251 'selectGraphs' => API_OUTPUT_COUNT, 252 'selectHostPrototypes' => API_OUTPUT_COUNT, 253 'itemids' => [$lld_ruleid], 254 'editable' => true 255 ]); 256 $db_discovery_rule = reset($db_discovery_rule); 257 } 258 259 $list = new CList(); 260 261 if ($is_template) { 262 $template = new CSpan( 263 new CLink($db_host['name'], 'templates.php?form=update&templateid='.$db_host['templateid']) 264 ); 265 266 if ($current_element === '') { 267 $template->addClass(ZBX_STYLE_SELECTED); 268 } 269 270 $list->addItem(new CBreadcrumbs([ 271 new CSpan(new CLink(_('All templates'), new CUrl('templates.php'))), 272 $template 273 ])); 274 275 $db_host['hostid'] = $db_host['templateid']; 276 } 277 else { 278 switch ($db_host['status']) { 279 case HOST_STATUS_MONITORED: 280 if ($db_host['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) { 281 $status = (new CSpan(_('In maintenance')))->addClass(ZBX_STYLE_ORANGE); 282 } 283 else { 284 $status = (new CSpan(_('Enabled')))->addClass(ZBX_STYLE_GREEN); 285 } 286 break; 287 case HOST_STATUS_NOT_MONITORED: 288 $status = (new CSpan(_('Disabled')))->addClass(ZBX_STYLE_RED); 289 break; 290 default: 291 $status = (new CSpan(_('Unknown')))->addClass(ZBX_STYLE_GREY); 292 break; 293 } 294 295 $host = new CSpan(new CLink(CHtml::encode($db_host['name']), 296 'hosts.php?form=update&hostid='.$db_host['hostid'] 297 )); 298 299 if ($current_element === '') { 300 $host->addClass(ZBX_STYLE_SELECTED); 301 } 302 303 $list 304 ->addItem(new CBreadcrumbs([new CSpan(new CLink(_('All hosts'), new CUrl('hosts.php'))), $host])) 305 ->addItem($status) 306 ->addItem(getHostAvailabilityTable($db_host['interfaces'])); 307 308 if ($db_host['flags'] == ZBX_FLAG_DISCOVERY_CREATED && $db_host['hostDiscovery']['ts_delete'] != 0) { 309 $info_icons = [getHostLifetimeIndicator(time(), $db_host['hostDiscovery']['ts_delete'])]; 310 $list->addItem(makeInformationList($info_icons)); 311 } 312 } 313 314 $content_menu = (new CList()) 315 ->setAttribute('role', 'navigation') 316 ->setAttribute('aria-label', _('Content menu')); 317 318 $context = $is_template ? 'template' : 'host'; 319 320 /* 321 * the count of rows 322 */ 323 if ($lld_ruleid == 0) { 324 // items 325 $items = new CSpan([ 326 new CLink(_('Items'), 327 (new CUrl('items.php')) 328 ->setArgument('filter_set', '1') 329 ->setArgument('filter_hostids', [$db_host['hostid']]) 330 ->setArgument('context', $context) 331 ), 332 CViewHelper::showNum($db_host['items']) 333 ]); 334 if ($current_element == 'items') { 335 $items->addClass(ZBX_STYLE_SELECTED); 336 } 337 $content_menu->addItem($items); 338 339 // triggers 340 $triggers = new CSpan([ 341 new CLink(_('Triggers'), 342 (new CUrl('triggers.php')) 343 ->setArgument('filter_set', '1') 344 ->setArgument('filter_hostids', [$db_host['hostid']]) 345 ->setArgument('context', $context) 346 ), 347 CViewHelper::showNum($db_host['triggers']) 348 ]); 349 if ($current_element == 'triggers') { 350 $triggers->addClass(ZBX_STYLE_SELECTED); 351 } 352 $content_menu->addItem($triggers); 353 354 // graphs 355 $graphs = new CSpan([ 356 new CLink(_('Graphs'), (new CUrl('graphs.php')) 357 ->setArgument('filter_set', '1') 358 ->setArgument('filter_hostids', [$db_host['hostid']]) 359 ->setArgument('context', $context) 360 ), 361 CViewHelper::showNum($db_host['graphs']) 362 ]); 363 if ($current_element == 'graphs') { 364 $graphs->addClass(ZBX_STYLE_SELECTED); 365 } 366 $content_menu->addItem($graphs); 367 368 // Dashboards 369 if ($is_template) { 370 $dashboards = new CSpan([ 371 new CLink(_('Dashboards'), 372 (new CUrl('zabbix.php')) 373 ->setArgument('action', 'template.dashboard.list') 374 ->setArgument('templateid', $db_host['hostid']) 375 ), 376 CViewHelper::showNum($db_host['dashboards']) 377 ]); 378 if ($current_element == 'dashboards') { 379 $dashboards->addClass(ZBX_STYLE_SELECTED); 380 } 381 $content_menu->addItem($dashboards); 382 } 383 384 // discovery rules 385 $lld_rules = new CSpan([ 386 new CLink(_('Discovery rules'), (new CUrl('host_discovery.php')) 387 ->setArgument('filter_set', '1') 388 ->setArgument('filter_hostids', [$db_host['hostid']]) 389 ->setArgument('context', $context) 390 ), 391 CViewHelper::showNum($db_host['discoveries']) 392 ]); 393 if ($current_element == 'discoveries') { 394 $lld_rules->addClass(ZBX_STYLE_SELECTED); 395 } 396 $content_menu->addItem($lld_rules); 397 398 // web scenarios 399 $http_tests = new CSpan([ 400 new CLink(_('Web scenarios'), 401 (new CUrl('httpconf.php')) 402 ->setArgument('filter_set', '1') 403 ->setArgument('filter_hostids', [$db_host['hostid']]) 404 ->setArgument('context', $context) 405 ), 406 CViewHelper::showNum($db_host['httpTests']) 407 ]); 408 if ($current_element == 'web') { 409 $http_tests->addClass(ZBX_STYLE_SELECTED); 410 } 411 $content_menu->addItem($http_tests); 412 } 413 else { 414 $discovery_rule = (new CSpan())->addItem( 415 new CLink( 416 CHtml::encode($db_discovery_rule['name']), 417 (new CUrl('host_discovery.php')) 418 ->setArgument('form', 'update') 419 ->setArgument('itemid', $db_discovery_rule['itemid']) 420 ->setArgument('context', $context) 421 ) 422 ); 423 424 if ($current_element == 'discoveries') { 425 $discovery_rule->addClass(ZBX_STYLE_SELECTED); 426 } 427 428 $list->addItem(new CBreadcrumbs([ 429 (new CSpan())->addItem(new CLink(_('Discovery list'), 430 (new CUrl('host_discovery.php')) 431 ->setArgument('filter_set', '1') 432 ->setArgument('filter_hostids', [$db_host['hostid']]) 433 ->setArgument('context', $context) 434 )), 435 $discovery_rule 436 ])); 437 438 // item prototypes 439 $item_prototypes = new CSpan([ 440 new CLink(_('Item prototypes'), 441 (new CUrl('disc_prototypes.php')) 442 ->setArgument('parent_discoveryid', $db_discovery_rule['itemid']) 443 ->setArgument('context', $context) 444 ), 445 CViewHelper::showNum($db_discovery_rule['items']) 446 ]); 447 if ($current_element == 'items') { 448 $item_prototypes->addClass(ZBX_STYLE_SELECTED); 449 } 450 $content_menu->addItem($item_prototypes); 451 452 // trigger prototypes 453 $trigger_prototypes = new CSpan([ 454 new CLink(_('Trigger prototypes'), 455 (new CUrl('trigger_prototypes.php')) 456 ->setArgument('parent_discoveryid', $db_discovery_rule['itemid']) 457 ->setArgument('context', $context) 458 ), 459 CViewHelper::showNum($db_discovery_rule['triggers']) 460 ]); 461 if ($current_element == 'triggers') { 462 $trigger_prototypes->addClass(ZBX_STYLE_SELECTED); 463 } 464 $content_menu->addItem($trigger_prototypes); 465 466 // graph prototypes 467 $graph_prototypes = new CSpan([ 468 new CLink(_('Graph prototypes'), 469 (new CUrl('graphs.php')) 470 ->setArgument('parent_discoveryid', $db_discovery_rule['itemid']) 471 ->setArgument('context', $context) 472 ), 473 CViewHelper::showNum($db_discovery_rule['graphs']) 474 ]); 475 if ($current_element === 'graphs') { 476 $graph_prototypes->addClass(ZBX_STYLE_SELECTED); 477 } 478 $content_menu->addItem($graph_prototypes); 479 480 // host prototypes 481 if ($db_host['flags'] == ZBX_FLAG_DISCOVERY_NORMAL) { 482 $host_prototypes = new CSpan([ 483 new CLink(_('Host prototypes'), 484 (new CUrl('host_prototypes.php')) 485 ->setArgument('parent_discoveryid', $db_discovery_rule['itemid']) 486 ->setArgument('context', $context) 487 ), 488 CViewHelper::showNum($db_discovery_rule['hostPrototypes']) 489 ]); 490 if ($current_element == 'hosts') { 491 $host_prototypes->addClass(ZBX_STYLE_SELECTED); 492 } 493 $content_menu->addItem($host_prototypes); 494 } 495 } 496 497 $list->addItem($content_menu); 498 499 return $list; 500} 501 502/** 503 * Get map navigation. 504 * 505 * @param int $sysmapid Used as value for sysmaid in map link generation. 506 * @param string $name Used as label for map link generation. 507 * @param int $severity_min Used as value for severity_min in map link generation. 508 * 509 * @return CList 510 */ 511function getSysmapNavigation($sysmapid, $name, $severity_min) { 512 $list = (new CList())->addItem(new CBreadcrumbs([ 513 (new CSpan())->addItem(new CLink(_('All maps'), new CUrl('sysmaps.php'))), 514 (new CSpan()) 515 ->addClass(ZBX_STYLE_SELECTED) 516 ->addItem(new CLink($name, 517 (new CUrl('zabbix.php')) 518 ->setArgument('action', 'map.view') 519 ->setArgument('sysmapid', $sysmapid) 520 ->setArgument('severity_min', $severity_min) 521 )) 522 ])); 523 524 // get map parent maps 525 $parent_sysmaps = get_parent_sysmaps($sysmapid); 526 if ($parent_sysmaps) { 527 $parent_maps = (new CList()) 528 ->setAttribute('aria-label', _('Upper level maps')) 529 ->addItem((new CSpan())->addItem(_('Upper level maps').':')); 530 531 foreach ($parent_sysmaps as $parent_sysmap) { 532 $parent_maps->addItem((new CSpan())->addItem(new CLink($parent_sysmap['name'], 533 (new CUrl('zabbix.php')) 534 ->setArgument('action', 'map.view') 535 ->setArgument('sysmapid', $parent_sysmap['sysmapid']) 536 ->setArgument('severity_min', $severity_min) 537 ))); 538 } 539 540 $list->addItem($parent_maps); 541 } 542 543 return $list; 544} 545 546/** 547 * Renders a form footer with the given buttons. 548 * 549 * @param CButtonInterface $main_button main button that will be displayed on the left 550 * @param CButtonInterface[] $other_buttons 551 * 552 * @return CDiv 553 * 554 * @throws InvalidArgumentException if an element of $other_buttons contain something other than CButtonInterface 555 */ 556function makeFormFooter(CButtonInterface $main_button = null, array $other_buttons = []) { 557 foreach ($other_buttons as $other_button) { 558 $other_button->addClass(ZBX_STYLE_BTN_ALT); 559 } 560 561 if ($main_button !== null) { 562 array_unshift($other_buttons, $main_button); 563 } 564 565 return (new CList()) 566 ->addClass(ZBX_STYLE_TABLE_FORMS) 567 ->addItem([ 568 (new CDiv())->addClass(ZBX_STYLE_TABLE_FORMS_TD_LEFT), 569 (new CDiv($other_buttons)) 570 ->addClass(ZBX_STYLE_TABLE_FORMS_TD_RIGHT) 571 ->addClass('tfoot-buttons') 572 ]); 573} 574 575/** 576 * Create HTML helper element for host interfaces availability. 577 * 578 * @param array $host_interfaces Array of arrays of host interfaces. 579 * @param int $host_interfaces[]['type'] Interface type. 580 * @param int $host_interfaces[]['available'] Interface availability. 581 * @param int $host_interfaces[]['useip'] Interface use IP or DNS. 582 * @param int $host_interfaces[]['ip'] Interface IP address. 583 * @param int $host_interfaces[]['dns'] Interface domain name. 584 * @param int $host_interfaces[]['port'] Interface port. 585 * @param int $host_interfaces[]['details']['version'] Interface SNMP version. 586 * @param int $host_interfaces[]['details']['contextname'] Interface context name for SNMP version 3. 587 * @param int $host_interfaces[]['details']['community'] Interface community for SNMP non version 3 interface. 588 * @param int $host_interfaces[]['details']['securitylevel'] Security level for SNMP version 3 interface. 589 * @param int $host_interfaces[]['details']['authprotocol'] Authentication protocol for SNMP version 3 interface. 590 * @param int $host_interfaces[]['details']['privprotocol'] Privacy protocol for SNMP version 3 interface. 591 * @param int $host_interfaces[]['error'] Interface error message. 592 * 593 * @return CHostAvailability 594 */ 595function getHostAvailabilityTable($host_interfaces): CHostAvailability { 596 $interfaces = []; 597 598 foreach ($host_interfaces as $interface) { 599 $description = null; 600 601 if ($interface['type'] == INTERFACE_TYPE_SNMP) { 602 $description = getSnmpInterfaceDescription($interface); 603 } 604 605 $interfaces[] = [ 606 'type' => $interface['type'], 607 'available' => $interface['available'], 608 'interface' => getHostInterface($interface), 609 'description' => $description, 610 'error' => ($interface['available'] == INTERFACE_AVAILABLE_TRUE) ? '' : $interface['error'] 611 ]; 612 } 613 614 return (new CHostAvailability())->setInterfaces($interfaces); 615} 616 617/** 618 * Returns the discovered host group lifetime indicator. 619 * 620 * @param string $current_time current Unix timestamp 621 * @param array $ts_delete deletion timestamp of the host group 622 * 623 * @return CDiv 624 */ 625function getHostGroupLifetimeIndicator($current_time, $ts_delete) { 626 // Check if the element should've been deleted in the past. 627 if ($current_time > $ts_delete) { 628 $warning = _( 629 'The host group is not discovered anymore and will be deleted the next time discovery rule is processed.' 630 ); 631 } 632 else { 633 $warning = _s( 634 'The host group is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 635 zbx_date2age($current_time, $ts_delete), 636 zbx_date2str(DATE_FORMAT, $ts_delete), 637 zbx_date2str(TIME_FORMAT, $ts_delete) 638 ); 639 } 640 641 return makeWarningIcon($warning); 642} 643 644/** 645 * Returns the discovered host lifetime indicator. 646 * 647 * @param string $current_time current Unix timestamp 648 * @param array $ts_delete deletion timestamp of the host 649 * 650 * @return CDiv 651 */ 652function getHostLifetimeIndicator($current_time, $ts_delete) { 653 // Check if the element should've been deleted in the past. 654 if ($current_time > $ts_delete) { 655 $warning = _( 656 'The host is not discovered anymore and will be deleted the next time discovery rule is processed.' 657 ); 658 } 659 else { 660 $warning = _s( 661 'The host is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 662 zbx_date2age($current_time, $ts_delete), 663 zbx_date2str(DATE_FORMAT, $ts_delete), 664 zbx_date2str(TIME_FORMAT, $ts_delete) 665 ); 666 } 667 668 return makeWarningIcon($warning); 669} 670 671/** 672 * Returns the discovered graph lifetime indicator. 673 * 674 * @param string $current_time current Unix timestamp 675 * @param array $ts_delete deletion timestamp of the graph 676 * 677 * @return CDiv 678 */ 679function getGraphLifetimeIndicator($current_time, $ts_delete) { 680 // Check if the element should've been deleted in the past. 681 if ($current_time > $ts_delete) { 682 $warning = _( 683 'The graph is not discovered anymore and will be deleted the next time discovery rule is processed.' 684 ); 685 } 686 else { 687 $warning = _s( 688 'The graph is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 689 zbx_date2age($current_time, $ts_delete), 690 zbx_date2str(DATE_FORMAT, $ts_delete), 691 zbx_date2str(TIME_FORMAT, $ts_delete) 692 ); 693 } 694 695 return makeWarningIcon($warning); 696} 697 698/** 699 * Returns the discovered trigger lifetime indicator. 700 * 701 * @param string $current_time current Unix timestamp 702 * @param array $ts_delete deletion timestamp of the trigger 703 * 704 * @return CDiv 705 */ 706function getTriggerLifetimeIndicator($current_time, $ts_delete) { 707 // Check if the element should've been deleted in the past. 708 if ($current_time > $ts_delete) { 709 $warning = _( 710 'The trigger is not discovered anymore and will be deleted the next time discovery rule is processed.' 711 ); 712 } 713 else { 714 $warning = _s( 715 'The trigger is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 716 zbx_date2age($current_time, $ts_delete), 717 zbx_date2str(DATE_FORMAT, $ts_delete), 718 zbx_date2str(TIME_FORMAT, $ts_delete) 719 ); 720 } 721 722 return makeWarningIcon($warning); 723} 724 725/** 726 * Returns the discovered item lifetime indicator. 727 * 728 * @param string $current_time current Unix timestamp 729 * @param array $ts_delete deletion timestamp of the item 730 * 731 * @return CDiv 732 */ 733function getItemLifetimeIndicator($current_time, $ts_delete) { 734 // Check if the element should've been deleted in the past. 735 if ($current_time > $ts_delete) { 736 $warning = _( 737 'The item is not discovered anymore and will be deleted the next time discovery rule is processed.' 738 ); 739 } 740 else { 741 $warning = _s( 742 'The item is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 743 zbx_date2age($current_time, $ts_delete), 744 zbx_date2str(DATE_FORMAT, $ts_delete), 745 zbx_date2str(TIME_FORMAT, $ts_delete) 746 ); 747 } 748 749 return makeWarningIcon($warning); 750} 751 752function makeServerStatusOutput() { 753 return (new CTag('output', true)) 754 ->setId('msg-global-footer') 755 ->addClass(ZBX_STYLE_MSG_GLOBAL_FOOTER) 756 ->addClass(ZBX_STYLE_MSG_WARNING); 757} 758 759/** 760* Make logo of the specified type. 761* 762* @param int $type LOGO_TYPE_NORMAL | LOGO_TYPE_SIDEBAR | LOGO_TYPE_SIDEBAR_COMPACT. 763* 764* @return CTag 765*/ 766function makeLogo(int $type): ?CTag { 767 static $zabbix_logo_classes = [ 768 LOGO_TYPE_NORMAL => ZBX_STYLE_ZABBIX_LOGO, 769 LOGO_TYPE_SIDEBAR => ZBX_STYLE_ZABBIX_SIDEBAR_LOGO, 770 LOGO_TYPE_SIDEBAR_COMPACT => ZBX_STYLE_ZABBIX_SIDEBAR_LOGO_COMPACT 771 ]; 772 773 $brand_logo = CBrandHelper::getLogo($type); 774 775 if ($brand_logo !== null) { 776 return (new CImg($brand_logo)); 777 } 778 else { 779 return (new CDiv())->addClass($zabbix_logo_classes[$type]); 780 } 781} 782 783/** 784 * Renders a page footer. 785 * 786 * @param bool $with_version 787 * 788 * @return CDiv 789 */ 790function makePageFooter($with_version = true) { 791 return (new CTag('footer', true, CBrandHelper::getFooterContent($with_version))) 792 ->setAttribute('role', 'contentinfo'); 793} 794 795/** 796 * Get drop-down submenu item list for the User settings section. 797 * 798 * @return array|null Menu definition for CWidget::setTitleSubmenu. 799 */ 800function getUserSettingsSubmenu(): ?array { 801 if (!CWebUser::checkAccess(CRoleHelper::ACTIONS_MANAGE_API_TOKENS)) { 802 return null; 803 } 804 805 $profile_url = (new CUrl('zabbix.php')) 806 ->setArgument('action', 'userprofile.edit') 807 ->getUrl(); 808 809 $tokens_url = (new CUrl('zabbix.php')) 810 ->setArgument('action', 'user.token.list') 811 ->getUrl(); 812 813 return [ 814 'main_section' => [ 815 'items' => array_filter([ 816 $profile_url => _('User profile'), 817 $tokens_url => _('API tokens') 818 ]) 819 ] 820 ]; 821} 822 823/** 824 * Get drop-down submenu item list for the Administration->General section. 825 * 826 * @return array Menu definition for CWidget::setTitleSubmenu. 827 */ 828function getAdministrationGeneralSubmenu() { 829 $gui_url = (new CUrl('zabbix.php')) 830 ->setArgument('action', 'gui.edit') 831 ->getUrl(); 832 833 $autoreg_url = (new CUrl('zabbix.php')) 834 ->setArgument('action', 'autoreg.edit') 835 ->getUrl(); 836 837 $housekeeping_url = (new CUrl('zabbix.php')) 838 ->setArgument('action', 'housekeeping.edit') 839 ->getUrl(); 840 841 $image_url = (new CUrl('zabbix.php')) 842 ->setArgument('action', 'image.list') 843 ->getUrl(); 844 845 $iconmap_url = (new CUrl('zabbix.php')) 846 ->setArgument('action', 'iconmap.list') 847 ->getUrl(); 848 849 $regex_url = (new CUrl('zabbix.php')) 850 ->setArgument('action', 'regex.list') 851 ->getUrl(); 852 853 $macros_url = (new CUrl('zabbix.php')) 854 ->setArgument('action', 'macros.edit') 855 ->getUrl(); 856 857 $trigdisplay_url = (new CUrl('zabbix.php')) 858 ->setArgument('action', 'trigdisplay.edit') 859 ->getUrl(); 860 861 $modules_url = (new CUrl('zabbix.php')) 862 ->setArgument('action', 'module.list') 863 ->getUrl(); 864 865 $tokens_url = (new CUrl('zabbix.php')) 866 ->setArgument('action', 'token.list') 867 ->getUrl(); 868 869 $miscconfig_url = (new CUrl('zabbix.php')) 870 ->setArgument('action', 'miscconfig.edit') 871 ->getUrl(); 872 873 $can_access_tokens = (!CWebUser::isGuest() && CWebUser::checkAccess(CRoleHelper::ACTIONS_MANAGE_API_TOKENS)); 874 875 return [ 876 'main_section' => [ 877 'items' => array_filter([ 878 $gui_url => _('GUI'), 879 $autoreg_url => _('Autoregistration'), 880 $housekeeping_url => _('Housekeeping'), 881 $image_url => _('Images'), 882 $iconmap_url => _('Icon mapping'), 883 $regex_url => _('Regular expressions'), 884 $macros_url => _('Macros'), 885 $trigdisplay_url => _('Trigger displaying options'), 886 $modules_url => _('Modules'), 887 $tokens_url => $can_access_tokens ? _('API tokens') : null, 888 $miscconfig_url => _('Other') 889 ]) 890 ] 891 ]; 892} 893 894/** 895 * Renders an icon list. 896 * 897 * @param array $info_icons The list of information icons. 898 * 899 * @return CDiv|string 900 */ 901function makeInformationList($info_icons) { 902 return $info_icons ? (new CDiv($info_icons))->addClass(ZBX_STYLE_REL_CONTAINER) : ''; 903} 904 905/** 906 * Renders an information icon like green [i] with message. 907 * 908 * @param string $message 909 * 910 * @return CSpan 911 */ 912function makeInformationIcon($message) { 913 return (new CSpan()) 914 ->addClass(ZBX_STYLE_ICON_INFO) 915 ->addClass(ZBX_STYLE_STATUS_GREEN) 916 ->setHint($message, ZBX_STYLE_HINTBOX_WRAP); 917} 918 919/** 920 * Renders an icon for host in maintenance. 921 * 922 * @param int $type Type of the maintenance. 923 * @param string $name Name of the maintenance. 924 * @param string $description Description of the maintenance. 925 * 926 * @return CSpan 927 */ 928function makeMaintenanceIcon($type, $name, $description) { 929 $hint = $name.' ['.($type 930 ? _('Maintenance without data collection') 931 : _('Maintenance with data collection')).']'; 932 933 if ($description !== '') { 934 $hint .= "\n".$description; 935 } 936 937 return (new CSpan()) 938 ->addClass(ZBX_STYLE_ICON_MAINT) 939 ->addClass(ZBX_STYLE_CURSOR_POINTER) 940 ->setHint($hint); 941} 942 943/** 944 * Renders an icon for suppressed problem. 945 * 946 * @param array $icon_data 947 * @param string $icon_data[]['suppress_until'] Time until the problem is suppressed. 948 * @param string $icon_data[]['maintenance_name'] Name of the maintenance. 949 * 950 * @return CSpan 951 */ 952function makeSuppressedProblemIcon(array $icon_data) { 953 $suppress_until = max(zbx_objectValues($icon_data, 'suppress_until')); 954 955 CArrayHelper::sort($icon_data, ['maintenance_name']); 956 $maintenance_names = implode(', ', zbx_objectValues($icon_data, 'maintenance_name')); 957 958 return (new CSpan()) 959 ->addClass(ZBX_STYLE_ICON_INVISIBLE) 960 ->addClass(ZBX_STYLE_CURSOR_POINTER) 961 ->setHint( 962 _s('Suppressed till: %1$s', ($suppress_until < strtotime('tomorrow')) 963 ? zbx_date2str(TIME_FORMAT, $suppress_until) 964 : zbx_date2str(DATE_TIME_FORMAT, $suppress_until) 965 ). 966 "\n". 967 _s('Maintenance: %1$s', $maintenance_names) 968 ); 969} 970 971/** 972 * Renders an action icon. 973 * 974 * @param array $icon_data 975 * @param string $icon_data[icon] Icon style. 976 * @param array $icon_data[hint] Hintbox content (optional). 977 * @param bool $icon_data[button] Use button element (optional). 978 * @param int $icon_data[num] Number displayed over the icon (optional). 979 * 980 * @return CTag Returns CSpan or CButton depending on boolean $icon_data['button'] parameter 981 */ 982function makeActionIcon(array $icon_data): CTag { 983 984 if (array_key_exists('button', $icon_data) && $icon_data['button']) { 985 $icon = (new CButton(null))->addClass($icon_data['icon']); 986 } 987 else { 988 $icon = (new CSpan())->addClass($icon_data['icon']); 989 } 990 991 if (array_key_exists('num', $icon_data)) { 992 if ($icon_data['num'] > 99) { 993 $icon_data['num'] = '99+'; 994 } 995 $icon->setAttribute('data-count', $icon_data['num']); 996 } 997 998 if (array_key_exists('hint', $icon_data)) { 999 $icon 1000 ->addClass(ZBX_STYLE_CURSOR_POINTER) 1001 ->setHint($icon_data['hint'], '', true, 'max-width: '.ZBX_ACTIONS_POPUP_MAX_WIDTH.'px;'); 1002 } 1003 elseif (array_key_exists('title', $icon_data)) { 1004 $icon->setTitle($icon_data['title']); 1005 } 1006 1007 if (array_key_exists('aria-label', $icon_data)) { 1008 $icon 1009 ->addItem($icon_data['aria-label']) 1010 ->addClass(ZBX_STYLE_INLINE_SR_ONLY); 1011 } 1012 1013 return $icon; 1014} 1015 1016/** 1017 * Renders an icon for a description. 1018 * 1019 * @param string $description 1020 * 1021 * @return CSpan 1022 */ 1023function makeDescriptionIcon($description) { 1024 return (new CSpan()) 1025 ->addClass(ZBX_STYLE_ICON_DESCRIPTION) 1026 ->addClass(ZBX_STYLE_CURSOR_POINTER) 1027 ->setHint(zbx_str2links($description), ZBX_STYLE_HINTBOX_WRAP); 1028} 1029 1030/** 1031 * Renders an error icon like red [i] with error message 1032 * 1033 * @param string $error 1034 * 1035 * @return CSpan 1036 */ 1037function makeErrorIcon($error) { 1038 return (new CSpan()) 1039 ->addClass(ZBX_STYLE_ICON_INFO) 1040 ->addClass(ZBX_STYLE_STATUS_RED) 1041 ->setHint($error, ZBX_STYLE_HINTBOX_WRAP." ".ZBX_STYLE_RED); 1042} 1043 1044/** 1045 * Renders an unknown icon like grey [i] with error message 1046 * 1047 * @param string $error 1048 * 1049 * @return CSpan 1050 */ 1051function makeUnknownIcon($error) { 1052 return (new CSpan()) 1053 ->addClass(ZBX_STYLE_ICON_INFO) 1054 ->addClass(ZBX_STYLE_STATUS_DARK_GREY) 1055 ->setHint($error, ZBX_STYLE_HINTBOX_WRAP." ".ZBX_STYLE_RED); 1056} 1057 1058/** 1059 * Renders a warning icon like yellow [i] with error message 1060 * 1061 * @param string $error 1062 * 1063 * @return CSpan 1064 */ 1065function makeWarningIcon($error) { 1066 return (new CSpan()) 1067 ->addClass(ZBX_STYLE_ICON_INFO) 1068 ->addClass(ZBX_STYLE_STATUS_YELLOW) 1069 ->setHint($error, ZBX_STYLE_HINTBOX_WRAP); 1070} 1071 1072/** 1073 * Returns css for trigger severity backgrounds. 1074 * 1075 * @return string 1076 */ 1077function getTriggerSeverityCss() { 1078 $css = ''; 1079 1080 $severities = [ 1081 ZBX_STYLE_NA_BG => CSettingsHelper::getGlobal(CSettingsHelper::SEVERITY_COLOR_0), 1082 ZBX_STYLE_INFO_BG => CSettingsHelper::getGlobal(CSettingsHelper::SEVERITY_COLOR_1), 1083 ZBX_STYLE_WARNING_BG => CSettingsHelper::getGlobal(CSettingsHelper::SEVERITY_COLOR_2), 1084 ZBX_STYLE_AVERAGE_BG => CSettingsHelper::getGlobal(CSettingsHelper::SEVERITY_COLOR_3), 1085 ZBX_STYLE_HIGH_BG => CSettingsHelper::getGlobal(CSettingsHelper::SEVERITY_COLOR_4), 1086 ZBX_STYLE_DISASTER_BG => CSettingsHelper::getGlobal(CSettingsHelper::SEVERITY_COLOR_5) 1087 ]; 1088 1089 foreach ($severities as $class => $color) { 1090 $css .= '.'.$class.', .'.$class.' input[type="radio"]:checked + label, .'.$class.':before, .flh-'.$class. 1091 ', .status-'.$class.', .status-'.$class.':before { background-color: #'.$color.' }'."\n"; 1092 } 1093 1094 return $css; 1095} 1096 1097/** 1098 * Returns css for trigger status colors, if those are customized. 1099 * 1100 * @return string 1101 */ 1102function getTriggerStatusCss() { 1103 $css = ''; 1104 1105 if (CSettingsHelper::getGlobal(CSettingsHelper::CUSTOM_COLOR) == EVENT_CUSTOM_COLOR_ENABLED) { 1106 $event_statuses = [ 1107 ZBX_STYLE_PROBLEM_UNACK_FG => CSettingsHelper::get(CSettingsHelper::PROBLEM_UNACK_COLOR), 1108 ZBX_STYLE_PROBLEM_ACK_FG => CSettingsHelper::get(CSettingsHelper::PROBLEM_ACK_COLOR), 1109 ZBX_STYLE_OK_UNACK_FG => CSettingsHelper::get(CSettingsHelper::OK_UNACK_COLOR), 1110 ZBX_STYLE_OK_ACK_FG => CSettingsHelper::get(CSettingsHelper::OK_ACK_COLOR) 1111 ]; 1112 1113 foreach ($event_statuses as $class => $color) { 1114 $css .= '.' . $class . ' {color: #' . $color . ';}' . "\n"; 1115 } 1116 } 1117 1118 return $css; 1119} 1120