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 sysmap_element_types($type = null) { 23 $types = [ 24 SYSMAP_ELEMENT_TYPE_HOST => _('Host'), 25 SYSMAP_ELEMENT_TYPE_HOST_GROUP => _('Host group'), 26 SYSMAP_ELEMENT_TYPE_TRIGGER => _('Trigger'), 27 SYSMAP_ELEMENT_TYPE_MAP => _('Map'), 28 SYSMAP_ELEMENT_TYPE_IMAGE => _('Image') 29 ]; 30 31 if (is_null($type)) { 32 natsort($types); 33 return $types; 34 } 35 elseif (isset($types[$type])) { 36 return $types[$type]; 37 } 38 else { 39 return _('Unknown'); 40 } 41} 42 43function sysmapElementLabel($label = null) { 44 $labels = [ 45 MAP_LABEL_TYPE_LABEL => _('Label'), 46 MAP_LABEL_TYPE_IP => _('IP address'), 47 MAP_LABEL_TYPE_NAME => _('Element name'), 48 MAP_LABEL_TYPE_STATUS => _('Status only'), 49 MAP_LABEL_TYPE_NOTHING => _('Nothing'), 50 MAP_LABEL_TYPE_CUSTOM => _('Custom label') 51 ]; 52 53 if (is_null($label)) { 54 return $labels; 55 } 56 elseif (isset($labels[$label])) { 57 return $labels[$label]; 58 } 59 else { 60 return false; 61 } 62} 63 64/** 65 * Create map area with submenu for sysmap elements. 66 * In submenu gathered information about urls, scripts and submaps. 67 * 68 * @param array $sysmap 69 * @param array $options 70 * @param int $options['severity_min'] 71 * 72 * @return CAreaMap 73 */ 74function getActionMapBySysmap($sysmap, array $options = []) { 75 $sysmap['selements'] = zbx_toHash($sysmap['selements'], 'selementid'); 76 $sysmap['links'] = zbx_toHash($sysmap['links'], 'linkid'); 77 78 $actionMap = new CAreaMap('links'.$sysmap['sysmapid']); 79 80 $areas = populateFromMapAreas($sysmap); 81 $mapInfo = getSelementsInfo($sysmap, $options); 82 processAreasCoordinates($sysmap, $areas, $mapInfo); 83 84 $hostIds = []; 85 $triggerIds = []; 86 $host_groupids = []; 87 88 foreach ($sysmap['selements'] as $id => &$selement) { 89 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST) { 90 $hostIds[$selement['elementid']] = $selement['elementid']; 91 92 // expanding host URL macros again as some hosts were added from hostgroup areas 93 // and automatic expanding only happens for elements that are defined for map in db 94 foreach ($selement['urls'] as $urlId => $url) { 95 $selement['urls'][$urlId]['url'] = str_replace('{HOST.ID}', $selement['elementid'], $url['url']); 96 } 97 } 98 elseif ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 99 $triggerIds[$selement['elementid']] = $selement['elementid']; 100 } 101 elseif ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST_GROUP) { 102 $host_groupids[$selement['elementid']] = $selement['elementid']; 103 } 104 105 if ($selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS) { 106 unset($sysmap['selements'][$id]); 107 } 108 } 109 unset($selement); 110 111 $hostScripts = API::Script()->getScriptsByHosts($hostIds); 112 113 $hosts = API::Host()->get([ 114 'hostids' => $hostIds, 115 'output' => ['hostid', 'status'], 116 'nopermissions' => true, 117 'preservekeys' => true, 118 'selectGraphs' => API_OUTPUT_COUNT, 119 'selectScreens' => API_OUTPUT_COUNT 120 ]); 121 122 $monitored_triggers_hosts = API::Host()->get([ 123 'output' => ['hostid'], 124 'hostids' => $hostIds, 125 'with_monitored_triggers' => true, 126 'preservekeys' => true, 127 'nopermissions' => true 128 ]); 129 130 $triggers = API::Trigger()->get([ 131 'output' => [], 132 'triggerids' => $triggerIds, 133 'preservekeys' => true, 134 'nopermissions' => true 135 ]); 136 137 $moniored_triggers = API::Trigger()->get([ 138 'output' => [], 139 'triggerids' => array_keys($triggers), 140 'monitored' => true, 141 'nopermissions' => true, 142 'preservekeys' => true 143 ]); 144 145 $host_groups = API::HostGroup()->get([ 146 'output' => ['groupid'], 147 'groupids' => $host_groupids, 148 'with_monitored_triggers' => true, 149 'preservekeys' => true, 150 'nopermissions' => true 151 ]); 152 153 foreach ($sysmap['selements'] as $elem) { 154 $back = get_png_by_selement($mapInfo[$elem['selementid']]); 155 $area = new CArea( 156 [ 157 $elem['x'], 158 $elem['y'], 159 $elem['x'] + imagesx($back), 160 $elem['y'] + imagesy($back) 161 ], 162 '', '', 'rect' 163 ); 164 $area->addClass('menu-map'); 165 166 $hostId = null; 167 $scripts = null; 168 $gotos = null; 169 170 switch ($elem['elementtype']) { 171 case SYSMAP_ELEMENT_TYPE_HOST: 172 $host = $hosts[$elem['elementid']]; 173 174 if ($hostScripts[$elem['elementid']]) { 175 $hostId = $elem['elementid']; 176 $scripts = $hostScripts[$elem['elementid']]; 177 } 178 179 $gotos['triggerStatus'] = [ 180 'hostid' => $elem['elementid'], 181 'show_severity' => isset($options['severity_min']) ? $options['severity_min'] : null 182 ]; 183 $gotos['showTriggers'] = ($host['status'] == HOST_STATUS_MONITORED 184 && array_key_exists($elem['elementid'], $monitored_triggers_hosts)); 185 186 $gotos['graphs'] = ['hostid' => $host['hostid']]; 187 $gotos['showGraphs'] = (bool) $host['graphs']; 188 189 $gotos['screens'] = ['hostid' => $host['hostid']]; 190 $gotos['showScreens'] = (bool) $host['screens']; 191 192 $gotos['inventory'] = ['hostid' => $host['hostid']]; 193 194 $gotos['latestData'] = ['hostids' => [$host['hostid']]]; 195 break; 196 197 case SYSMAP_ELEMENT_TYPE_MAP: 198 $gotos['submap'] = [ 199 'sysmapid' => $elem['elementid'], 200 'severity_min' => isset($options['severity_min']) ? $options['severity_min'] : null, 201 'fullscreen' => array_key_exists('fullscreen', $options) ? $options['fullscreen'] : 0 202 ]; 203 break; 204 205 case SYSMAP_ELEMENT_TYPE_TRIGGER: 206 $gotos['showEvents'] = false; 207 208 if (array_key_exists($elem['elementid'], $triggers)) { 209 if (array_key_exists($elem['elementid'], $moniored_triggers)) { 210 $gotos['showEvents'] = true; 211 } 212 213 $gotos['events']['triggerid'] = $elem['elementid']; 214 } 215 break; 216 217 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 218 $gotos['triggerStatus'] = [ 219 'groupid' => $elem['elementid'], 220 'hostid' => 0, 221 'show_severity' => isset($options['severity_min']) ? $options['severity_min'] : null 222 ]; 223 224 // always show active trigger link for host group map elements 225 $gotos['showTriggers'] = array_key_exists($elem['elementid'], $host_groups); 226 break; 227 } 228 229 order_result($elem['urls'], 'name'); 230 231 $area->setMenuPopup(CMenuPopupHelper::getMap($hostId, $scripts, $gotos, $elem['urls'])); 232 233 $actionMap->addItem($area); 234 } 235 236 return $actionMap; 237} 238 239function get_icon_center_by_selement($element, $info, $map) { 240 $x = $element['x']; 241 $y = $element['y']; 242 243 if (isset($element['elementsubtype']) && $element['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS) { 244 if ($element['areatype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 245 $w = $element['width']; 246 $h = $element['height']; 247 } 248 else { 249 $w = $map['width']; 250 $h = $map['height']; 251 } 252 } 253 else { 254 $image = get_png_by_selement($info); 255 $w = imagesx($image); 256 $h = imagesy($image); 257 } 258 259 $x += $w / 2; 260 $y += $h / 2; 261 262 return [$x, $y]; 263} 264 265function myDrawLine($image, $x1, $y1, $x2, $y2, $color, $drawtype) { 266 if ($drawtype == MAP_LINK_DRAWTYPE_BOLD_LINE) { 267 zbx_imagealine($image, $x1, $y1, $x2, $y2, $color, LINE_TYPE_BOLD); 268 } 269 elseif ($drawtype == MAP_LINK_DRAWTYPE_DASHED_LINE) { 270 if (function_exists('imagesetstyle')) { 271 // use imagesetstyle + imageline instead of bugged ImageDashedLine 272 $style = [ 273 $color, $color, $color, $color, 274 IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT 275 ]; 276 imagesetstyle($image, $style); 277 zbx_imageline($image, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); 278 } 279 else { 280 imagedashedline($image, $x1, $y1, $x2, $y2, $color); 281 } 282 } 283 elseif ($drawtype == MAP_LINK_DRAWTYPE_DOT && function_exists('imagesetstyle')) { 284 $style = [$color, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT]; 285 imagesetstyle($image, $style); 286 zbx_imageline($image, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); 287 } 288 else { 289 zbx_imagealine($image, $x1, $y1, $x2, $y2, $color); 290 } 291} 292 293function get_png_by_selement($info) { 294 $image = get_image_by_imageid($info['iconid']); 295 296 return $image['image'] ? imagecreatefromstring($image['image']) : get_default_image(); 297} 298 299function get_map_elements($db_element, &$elements) { 300 switch ($db_element['elementtype']) { 301 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 302 $elements['hosts_groups'][] = $db_element['elementid']; 303 break; 304 case SYSMAP_ELEMENT_TYPE_HOST: 305 $elements['hosts'][] = $db_element['elementid']; 306 break; 307 case SYSMAP_ELEMENT_TYPE_TRIGGER: 308 $elements['triggers'][] = $db_element['elementid']; 309 break; 310 case SYSMAP_ELEMENT_TYPE_MAP: 311 $db_mapselements = DBselect( 312 'SELECT DISTINCT se.elementtype,se.elementid'. 313 ' FROM sysmaps_elements se'. 314 ' WHERE se.sysmapid='.zbx_dbstr($db_element['elementid']) 315 ); 316 while ($db_mapelement = DBfetch($db_mapselements)) { 317 get_map_elements($db_mapelement, $elements); 318 } 319 break; 320 } 321} 322 323/** 324 * Adds names to elements. Adds expression for SYSMAP_ELEMENT_TYPE_TRIGGER elements. 325 * 326 * @param type $selements 327 */ 328function add_elementNames(&$selements) { 329 $hostids = []; 330 $triggerids = []; 331 $mapids = []; 332 $hostgroupids = []; 333 $imageids = []; 334 335 foreach ($selements as $selement) { 336 switch ($selement['elementtype']) { 337 case SYSMAP_ELEMENT_TYPE_HOST: 338 $hostids[$selement['elementid']] = $selement['elementid']; 339 break; 340 case SYSMAP_ELEMENT_TYPE_MAP: 341 $mapids[$selement['elementid']] = $selement['elementid']; 342 break; 343 case SYSMAP_ELEMENT_TYPE_TRIGGER: 344 $triggerids[$selement['elementid']] = $selement['elementid']; 345 break; 346 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 347 $hostgroupids[$selement['elementid']] = $selement['elementid']; 348 break; 349 case SYSMAP_ELEMENT_TYPE_IMAGE: 350 $imageids[$selement['iconid_off']] = $selement['iconid_off']; 351 break; 352 } 353 } 354 355 $hosts = API::Host()->get([ 356 'hostids' => $hostids, 357 'output' => ['name'], 358 'nopermissions' => true, 359 'preservekeys' => true 360 ]); 361 362 $maps = API::Map()->get([ 363 'mapids' => $mapids, 364 'output' => ['name'], 365 'nopermissions' => true, 366 'preservekeys' => true 367 ]); 368 369 $triggers = API::Trigger()->get([ 370 'triggerids' => $triggerids, 371 'output' => API_OUTPUT_EXTEND, 372 'selectHosts' => ['hostid', 'name'], 373 'nopermissions' => true, 374 'preservekeys' => true 375 ]); 376 377 $hostgroups = API::HostGroup()->get([ 378 'hostgroupids' => $hostgroupids, 379 'output' => ['name'], 380 'nopermissions' => true, 381 'preservekeys' => true 382 ]); 383 384 $images = API::image()->get([ 385 'imageids' => $imageids, 386 'output' => API_OUTPUT_EXTEND, 387 'nopermissions' => true, 388 'preservekeys' => true 389 ]); 390 391 foreach ($selements as $snum => $selement) { 392 switch ($selement['elementtype']) { 393 case SYSMAP_ELEMENT_TYPE_HOST: 394 $selements[$snum]['elementName'] = $hosts[$selement['elementid']]['name']; 395 break; 396 case SYSMAP_ELEMENT_TYPE_MAP: 397 $selements[$snum]['elementName'] = $maps[$selement['elementid']]['name']; 398 break; 399 case SYSMAP_ELEMENT_TYPE_TRIGGER: 400 $hostname = reset($triggers[$selement['elementid']]['hosts']); 401 $selements[$snum]['elementName'] = $hostname['name'].NAME_DELIMITER. 402 CMacrosResolverHelper::resolveTriggerName($triggers[$selement['elementid']]); 403 break; 404 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 405 $selements[$snum]['elementName'] = $hostgroups[$selement['elementid']]['name']; 406 break; 407 case SYSMAP_ELEMENT_TYPE_IMAGE: 408 if (isset($images[$selement['iconid_off']]['name'])) { 409 $selements[$snum]['elementName'] = $images[$selement['iconid_off']]['name']; 410 } 411 break; 412 } 413 } 414 415 if (!empty($triggers)) { 416 add_triggerExpressions($selements, $triggers); 417 } 418} 419 420function add_triggerExpressions(&$selements, $triggers = []) { 421 if (empty($triggers)) { 422 $triggerIds = []; 423 424 foreach ($selements as $selement) { 425 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 426 $triggerIds[] = $selement['elementid']; 427 } 428 } 429 430 $triggers = API::Trigger()->get([ 431 'triggerids' => $triggerIds, 432 'output' => API_OUTPUT_EXTEND, 433 'selectHosts' => ['name'], 434 'nopermissions' => true, 435 'preservekeys' => true 436 ]); 437 } 438 439 foreach ($selements as $snum => $selement) { 440 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 441 $selements[$snum]['elementExpressionTrigger'] = $triggers[$selement['elementid']]['expression']; 442 } 443 } 444} 445 446/** 447 * Returns trigger element icon rendering parameters. 448 * 449 * @param $selement 450 * @param $i 451 * @param $showUnack map "problem display" parameter 452 * 453 * @return array 454 */ 455function getTriggersInfo($selement, $i, $showUnack) { 456 $info = [ 457 'latelyChanged' => $i['latelyChanged'], 458 'ack' => $i['ack'], 459 'priority' => $i['priority'], 460 'info' => [], 461 'iconid' => $selement['iconid_off'] 462 ]; 463 464 if ($i['problem'] && ($i['problem_unack'] && $showUnack == EXTACK_OPTION_UNACK 465 || in_array($showUnack, [EXTACK_OPTION_ALL, EXTACK_OPTION_BOTH]))) { 466 $info['info']['unack'] = [ 467 'msg' => _('PROBLEM'), 468 'color' => ($i['priority'] > 3) ? 'FF0000' : '960000' 469 ]; 470 471 if (!array_key_exists('maintenance_title', $i)) { 472 $info['iconid'] = $selement['iconid_on']; 473 $info['icon_type'] = SYSMAP_ELEMENT_ICON_ON; 474 475 return $info; 476 } 477 } 478 479 if (array_key_exists('maintenance_title', $i)) { 480 $info['iconid'] = $selement['iconid_maintenance']; 481 $info['icon_type'] = SYSMAP_ELEMENT_ICON_MAINTENANCE; 482 $info['info']['maintenance'] = [ 483 'msg' => _('MAINTENANCE').' ('.$i['maintenance_title'].')', 484 'color' => 'EE9600' 485 ]; 486 } 487 elseif ($i['trigger_disabled']) { 488 $info['iconid'] = $selement['iconid_disabled']; 489 $info['icon_type'] = SYSMAP_ELEMENT_ICON_DISABLED; 490 $info['info']['status'] = [ 491 'msg' => _('DISABLED'), 492 'color' => '960000' 493 ]; 494 } 495 else { 496 $info['iconid'] = $selement['iconid_off']; 497 $info['icon_type'] = SYSMAP_ELEMENT_ICON_OFF; 498 $info['info']['ok'] = [ 499 'msg' => _('OK'), 500 'color' => '009600' 501 ]; 502 } 503 504 return $info; 505} 506 507/** 508 * Returns host element icon rendering parameters. 509 * 510 * @param $selement 511 * @param $i 512 * @param $show_unack map "problem display" parameter 513 * 514 * @return array 515 */ 516function getHostsInfo($selement, $i, $show_unack) { 517 $info = [ 518 'latelyChanged' => $i['latelyChanged'], 519 'ack' => $i['ack'], 520 'priority' => $i['priority'], 521 'info' => [], 522 'iconid' => $selement['iconid_off'] 523 ]; 524 $hasProblem = false; 525 526 if ($i['problem']) { 527 if (in_array($show_unack, [EXTACK_OPTION_ALL, EXTACK_OPTION_BOTH])) { 528 if ($i['problem'] > 1) { 529 $msg = $i['problem'].' '._('Problems'); 530 } 531 elseif (isset($i['problem_title'])) { 532 $msg = $i['problem_title']; 533 } 534 else { 535 $msg = '1 '._('Problem'); 536 } 537 538 $info['info']['problem'] = [ 539 'msg' => $msg, 540 'color' => ($i['priority'] > 3) ? 'FF0000' : '960000' 541 ]; 542 } 543 544 if (in_array($show_unack, [EXTACK_OPTION_UNACK, EXTACK_OPTION_BOTH]) && $i['problem_unack']) { 545 $info['info']['unack'] = [ 546 'msg' => $i['problem_unack'].' '._('Unacknowledged'), 547 'color' => '960000' 548 ]; 549 } 550 551 // set element to problem state if it has problem events 552 if ($info['info']) { 553 $info['iconid'] = $selement['iconid_on']; 554 $info['icon_type'] = SYSMAP_ELEMENT_ICON_ON; 555 $hasProblem = true; 556 } 557 } 558 559 if (array_key_exists('maintenance_title', $i)) { 560 $info['iconid'] = $selement['iconid_maintenance']; 561 $info['icon_type'] = SYSMAP_ELEMENT_ICON_MAINTENANCE; 562 $info['info']['maintenance'] = [ 563 'msg' => _('MAINTENANCE').' ('.$i['maintenance_title'].')', 564 'color' => 'EE9600' 565 ]; 566 } 567 elseif ($i['disabled']) { 568 $info['iconid'] = $selement['iconid_disabled']; 569 $info['icon_type'] = SYSMAP_ELEMENT_ICON_DISABLED; 570 $info['info']['status'] = [ 571 'msg' => _('DISABLED'), 572 'color' => '960000' 573 ]; 574 } 575 elseif (!$hasProblem) { 576 $info['iconid'] = $selement['iconid_off']; 577 $info['icon_type'] = SYSMAP_ELEMENT_ICON_OFF; 578 $info['info']['ok'] = [ 579 'msg' => _('OK'), 580 'color' => '009600' 581 ]; 582 } 583 584 return $info; 585} 586 587/** 588 * Returns host groups element icon rendering parameters. 589 * 590 * @param $selement 591 * @param $i 592 * @param $show_unack map "problem display" parameter 593 * 594 * @return array 595 */ 596function getHostGroupsInfo($selement, $i, $show_unack) { 597 $info = [ 598 'latelyChanged' => $i['latelyChanged'], 599 'ack' => $i['ack'], 600 'priority' => $i['priority'], 601 'info' => [], 602 'iconid' => $selement['iconid_off'] 603 ]; 604 $hasProblem = false; 605 $hasStatus = false; 606 607 if ($i['problem']) { 608 if (in_array($show_unack, [EXTACK_OPTION_ALL, EXTACK_OPTION_BOTH])) { 609 if ($i['problem'] > 1) { 610 $msg = $i['problem'].' '._('Problems'); 611 } 612 elseif (isset($i['problem_title'])) { 613 $msg = $i['problem_title']; 614 } 615 else { 616 $msg = '1 '._('Problem'); 617 } 618 619 $info['info']['problem'] = [ 620 'msg' => $msg, 621 'color' => ($i['priority'] > 3) ? 'FF0000' : '960000' 622 ]; 623 } 624 625 if (in_array($show_unack, [EXTACK_OPTION_UNACK, EXTACK_OPTION_BOTH]) && $i['problem_unack']) { 626 $info['info']['unack'] = [ 627 'msg' => $i['problem_unack'].' '._('Unacknowledged'), 628 'color' => '960000' 629 ]; 630 } 631 632 // set element to problem state if it has problem events 633 if ($info['info']) { 634 $info['iconid'] = $selement['iconid_on']; 635 $info['icon_type'] = SYSMAP_ELEMENT_ICON_ON; 636 $hasProblem = true; 637 } 638 } 639 640 if ($i['maintenance']) { 641 if (!$hasProblem) { 642 $info['iconid'] = $selement['iconid_maintenance']; 643 $info['icon_type'] = SYSMAP_ELEMENT_ICON_MAINTENANCE; 644 } 645 $info['info']['maintenance'] = [ 646 'msg' => $i['maintenance'].' '._('Maintenance'), 647 'color' => 'EE9600' 648 ]; 649 $hasStatus = true; 650 } 651 652 if (!$hasStatus && !$hasProblem) { 653 $info['icon_type'] = SYSMAP_ELEMENT_ICON_OFF; 654 $info['iconid'] = $selement['iconid_off']; 655 $info['info']['ok'] = [ 656 'msg' => _('OK'), 657 'color' => '009600' 658 ]; 659 } 660 661 return $info; 662} 663 664/** 665 * Returns maps groups element icon rendering parameters. 666 * 667 * @param $selement 668 * @param $i 669 * @param $show_unack map "problem display" parameter 670 * 671 * @return array 672 */ 673function getMapsInfo($selement, $i, $show_unack) { 674 $info = [ 675 'latelyChanged' => $i['latelyChanged'], 676 'ack' => $i['ack'], 677 'priority' => $i['priority'], 678 'info' => [], 679 'iconid' => $selement['iconid_off'] 680 ]; 681 682 $hasProblem = false; 683 $hasStatus = false; 684 685 if ($i['problem']) { 686 if (in_array($show_unack, [EXTACK_OPTION_ALL, EXTACK_OPTION_BOTH])) { 687 if ($i['problem'] > 1) { 688 $msg = $i['problem'].' '._('Problems'); 689 } 690 elseif (isset($i['problem_title'])) { 691 $msg = $i['problem_title']; 692 } 693 else { 694 $msg = '1 '._('Problem'); 695 } 696 697 $info['info']['problem'] = [ 698 'msg' => $msg, 699 'color' => ($i['priority'] > 3) ? 'FF0000' : '960000' 700 ]; 701 } 702 703 if (in_array($show_unack, [EXTACK_OPTION_UNACK, EXTACK_OPTION_BOTH]) && $i['problem_unack']) { 704 $info['info']['unack'] = [ 705 'msg' => $i['problem_unack'].' '._('Unacknowledged'), 706 'color' => '960000' 707 ]; 708 } 709 710 if ($info['info']) { 711 $info['iconid'] = $selement['iconid_on']; 712 $info['icon_type'] = SYSMAP_ELEMENT_ICON_ON; 713 $hasProblem = true; 714 } 715 } 716 717 if ($i['maintenance']) { 718 if (!$hasProblem) { 719 $info['iconid'] = $selement['iconid_maintenance']; 720 $info['icon_type'] = SYSMAP_ELEMENT_ICON_MAINTENANCE; 721 } 722 $info['info']['maintenance'] = [ 723 'msg' => $i['maintenance'].' '._('Maintenance'), 724 'color' => 'EE9600' 725 ]; 726 $hasStatus = true; 727 } 728 729 if (!$hasStatus && !$hasProblem) { 730 $info['icon_type'] = SYSMAP_ELEMENT_ICON_OFF; 731 $info['iconid'] = $selement['iconid_off']; 732 $info['info']['ok'] = [ 733 'msg' => _('OK'), 734 'color' => '009600' 735 ]; 736 } 737 738 return $info; 739} 740 741function getImagesInfo($selement) { 742 return [ 743 'iconid' => $selement['iconid_off'], 744 'icon_type' => SYSMAP_ELEMENT_ICON_OFF, 745 'name' => _('Image'), 746 'latelyChanged' => false 747 ]; 748} 749 750/** 751 * Prepare map elements data. 752 * Calculate problem triggers and priorities. Populate map elements with automatic icon mapping, acknowledging and 753 * recent change markers. 754 * 755 * @param array $sysmap 756 * @param array $options 757 * @param int $options['severity_min'] Minimum trigger severity, default value is maximal (Disaster) 758 * 759 * @return array 760 */ 761function getSelementsInfo($sysmap, array $options = []) { 762 if (!isset($options['severity_min'])) { 763 $options['severity_min'] = TRIGGER_SEVERITY_NOT_CLASSIFIED; 764 } 765 766 $config = select_config(); 767 $showUnacknowledged = $config['event_ack_enable'] ? $sysmap['show_unack'] : EXTACK_OPTION_ALL; 768 769 $triggerIdToSelementIds = []; 770 $subSysmapTriggerIdToSelementIds = []; 771 $hostGroupIdToSelementIds = []; 772 $hostIdToSelementIds = []; 773 774 if ($sysmap['sysmapid']) { 775 $iconMap = API::IconMap()->get([ 776 'sysmapids' => $sysmap['sysmapid'], 777 'selectMappings' => API_OUTPUT_EXTEND, 778 'output' => API_OUTPUT_EXTEND 779 ]); 780 $iconMap = reset($iconMap); 781 782 } 783 $hostsToGetInventories = []; 784 785 $selements = $sysmap['selements']; 786 $selementIdToSubSysmaps = []; 787 foreach ($selements as $selementId => &$selement) { 788 $selement['hosts'] = []; 789 $selement['triggers'] = []; 790 791 switch ($selement['elementtype']) { 792 case SYSMAP_ELEMENT_TYPE_MAP: 793 $sysmapIds = [$selement['elementid']]; 794 795 while (!empty($sysmapIds)) { 796 $subSysmaps = API::Map()->get([ 797 'sysmapids' => $sysmapIds, 798 'output' => ['sysmapid'], 799 'selectSelements' => API_OUTPUT_EXTEND, 800 'nopermissions' => true, 801 'preservekeys' => true 802 ]); 803 804 if(!isset($selementIdToSubSysmaps[$selementId])) { 805 $selementIdToSubSysmaps[$selementId] = []; 806 } 807 $selementIdToSubSysmaps[$selementId] += $subSysmaps; 808 809 $sysmapIds = []; 810 foreach ($subSysmaps as $subSysmap) { 811 foreach ($subSysmap['selements'] as $subSysmapSelement) { 812 switch ($subSysmapSelement['elementtype']) { 813 case SYSMAP_ELEMENT_TYPE_MAP: 814 $sysmapIds[] = $subSysmapSelement['elementid']; 815 break; 816 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 817 $hostGroupIdToSelementIds[$subSysmapSelement['elementid']][$selementId] = $selementId; 818 break; 819 case SYSMAP_ELEMENT_TYPE_HOST: 820 $hostIdToSelementIds[$subSysmapSelement['elementid']][$selementId] = $selementId; 821 break; 822 case SYSMAP_ELEMENT_TYPE_TRIGGER: 823 $subSysmapTriggerIdToSelementIds[$subSysmapSelement['elementid']][$selementId] = $selementId; 824 break; 825 } 826 } 827 } 828 } 829 break; 830 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 831 $hostGroupId = $selement['elementid']; 832 $hostGroupIdToSelementIds[$hostGroupId][$selementId] = $selementId; 833 break; 834 case SYSMAP_ELEMENT_TYPE_HOST: 835 $hostId = $selement['elementid']; 836 $hostIdToSelementIds[$hostId][$selementId] = $selementId; 837 838 // if we have icon map applied, we need to get inventories for all hosts, 839 // where automatic icon selection is enabled. 840 if ($sysmap['iconmapid'] && $selement['use_iconmap']) { 841 $hostsToGetInventories[] = $hostId; 842 } 843 break; 844 case SYSMAP_ELEMENT_TYPE_TRIGGER: 845 $triggerId = $selement['elementid']; 846 $triggerIdToSelementIds[$triggerId][$selementId] = $selementId; 847 break; 848 } 849 } 850 unset($selement); 851 852 // get host inventories 853 if ($sysmap['iconmapid']) { 854 $hostInventories = API::Host()->get([ 855 'hostids' => $hostsToGetInventories, 856 'output' => ['hostid'], 857 'nopermissions' => true, 858 'preservekeys' => true, 859 'selectInventory' => API_OUTPUT_EXTEND 860 ]); 861 } 862 863 $allHosts = []; 864 if (!empty($hostIdToSelementIds)) { 865 $hosts = API::Host()->get([ 866 'hostids' => array_keys($hostIdToSelementIds), 867 'output' => ['name', 'status', 'maintenance_status', 'maintenanceid'], 868 'nopermissions' => true, 869 'preservekeys' => true 870 ]); 871 $allHosts = array_merge($allHosts, $hosts); 872 foreach ($hosts as $hostId => $host) { 873 foreach ($hostIdToSelementIds[$hostId] as $selementId) { 874 $selements[$selementId]['hosts'][$hostId] = $hostId; 875 } 876 } 877 } 878 879 $hostsFromHostGroups = []; 880 if (!empty($hostGroupIdToSelementIds)) { 881 $hostsFromHostGroups = API::Host()->get([ 882 'groupids' => array_keys($hostGroupIdToSelementIds), 883 'output' => ['name', 'status', 'maintenance_status', 'maintenanceid'], 884 'selectGroups' => ['groupid'], 885 'nopermissions' => true, 886 'preservekeys' => true 887 ]); 888 889 foreach ($hostsFromHostGroups as $hostId => $host) { 890 foreach ($host['groups'] as $group) { 891 $groupId = $group['groupid']; 892 893 if (isset($hostGroupIdToSelementIds[$groupId])) { 894 foreach ($hostGroupIdToSelementIds[$groupId] as $selementId) { 895 $selement =& $selements[$selementId]; 896 897 $selement['hosts'][$hostId] = $hostId; 898 899 // add hosts to hosts_map for trigger selection; 900 if (!isset($hostIdToSelementIds[$hostId])) { 901 $hostIdToSelementIds[$hostId] = []; 902 } 903 $hostIdToSelementIds[$hostId][$selementId] = $selementId; 904 905 unset($selement); 906 } 907 } 908 } 909 } 910 911 $allHosts = array_merge($allHosts, $hostsFromHostGroups); 912 } 913 914 $allHosts = zbx_toHash($allHosts, 'hostid'); 915 916 // get triggers data, triggers from current map, select all 917 if (!empty($triggerIdToSelementIds)) { 918 $triggers = API::Trigger()->get([ 919 'output' => ['triggerid', 'status', 'value', 'priority', 'lastchange', 'description', 'expression'], 920 'selectHosts' => ['maintenance_status', 'maintenanceid'], 921 'selectLastEvent' => ['acknowledged'], 922 'triggerids' => array_keys($triggerIdToSelementIds), 923 'filter' => ['state' => null], 924 'nopermissions' => true, 925 'preservekeys' => true 926 ]); 927 928 $monitored_triggers = API::Trigger()->get([ 929 'output' => [], 930 'triggerids' => array_keys($triggers), 931 'monitored' => true, 932 'nopermissions' => true, 933 'preservekeys' => true 934 ]); 935 936 foreach ($triggers as $trigger) { 937 if (!array_key_exists($trigger['triggerid'], $monitored_triggers)) { 938 $trigger['status'] = TRIGGER_STATUS_DISABLED; 939 } 940 941 foreach ($triggerIdToSelementIds[$trigger['triggerid']] as $belongs_to_sel) { 942 $selements[$belongs_to_sel]['triggers'][$trigger['triggerid']] = $trigger; 943 } 944 } 945 unset($triggers, $monitored_triggers); 946 } 947 948 // triggers from submaps, skip dependent 949 if (!empty($subSysmapTriggerIdToSelementIds)) { 950 $triggers = API::Trigger()->get([ 951 'output' => ['triggerid', 'status', 'value', 'priority', 'lastchange', 'description', 'expression'], 952 'selectLastEvent' => ['acknowledged'], 953 'triggerids' => array_keys($subSysmapTriggerIdToSelementIds), 954 'filter' => ['state' => null], 955 'skipDependent' => true, 956 'nopermissions' => true, 957 'preservekeys' => true, 958 'only_true' => true 959 ]); 960 961 $monitored_triggers = API::Trigger()->get([ 962 'output' => [], 963 'triggerids' => array_keys($triggers), 964 'monitored' => true, 965 'nopermissions' => true, 966 'preservekeys' => true 967 ]); 968 969 foreach ($triggers as $trigger) { 970 foreach ($subSysmapTriggerIdToSelementIds[$trigger['triggerid']] as $belongs_to_sel) { 971 if (!array_key_exists($trigger['triggerid'], $monitored_triggers)) { 972 $trigger['status'] = TRIGGER_STATUS_DISABLED; 973 } 974 975 $selements[$belongs_to_sel]['triggers'][$trigger['triggerid']] = $trigger; 976 } 977 } 978 unset($triggers, $monitored_triggers); 979 } 980 981 $monitored_hostids = []; 982 foreach ($allHosts as $hostid => $host) { 983 if ($host['status'] == HOST_STATUS_MONITORED) { 984 $monitored_hostids[$hostid] = true; 985 } 986 } 987 988 // triggers from all hosts/hostgroups, skip dependent 989 if ($monitored_hostids) { 990 $triggers = API::Trigger()->get([ 991 'output' => ['triggerid', 'status', 'value', 'priority', 'lastchange', 'description', 'expression'], 992 'selectHosts' => ['hostid'], 993 'selectItems' => ['itemid'], 994 'selectLastEvent' => ['acknowledged'], 995 'hostids' => array_keys($monitored_hostids), 996 'filter' => ['state' => null], 997 'monitored' => true, 998 'skipDependent' => true, 999 'nopermissions' => true, 1000 'preservekeys' => true, 1001 'only_true' => true 1002 ]); 1003 1004 foreach ($triggers as $trigger) { 1005 foreach ($trigger['hosts'] as $host) { 1006 if (isset($hostIdToSelementIds[$host['hostid']])) { 1007 foreach ($hostIdToSelementIds[$host['hostid']] as $belongs_to_sel) { 1008 $selements[$belongs_to_sel]['triggers'][$trigger['triggerid']] = $trigger; 1009 } 1010 } 1011 } 1012 } 1013 1014 $subSysmapHostApplicationFilters = getSelementHostApplicationFilters($selements, $selementIdToSubSysmaps, 1015 $hostsFromHostGroups 1016 ); 1017 $selements = filterSysmapTriggers($selements, $subSysmapHostApplicationFilters, $triggers, 1018 $subSysmapTriggerIdToSelementIds 1019 ); 1020 } 1021 1022 $info = []; 1023 foreach ($selements as $selementId => $selement) { 1024 $i = [ 1025 'disabled' => 0, 1026 'maintenance' => 0, 1027 'problem' => 0, 1028 'problem_unack' => 0, 1029 'priority' => 0, 1030 'trigger_disabled' => 0, 1031 'latelyChanged' => false, 1032 'ack' => true 1033 ]; 1034 1035 foreach ($selement['hosts'] as $hostId) { 1036 $host = $allHosts[$hostId]; 1037 $last_hostid = $hostId; 1038 1039 if ($host['status'] == HOST_STATUS_NOT_MONITORED) { 1040 $i['disabled']++; 1041 } 1042 elseif ($host['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) { 1043 $i['maintenance']++; 1044 } 1045 } 1046 1047 $last_event = false; 1048 1049 foreach ($selement['triggers'] as $trigger) { 1050 if ($options['severity_min'] <= $trigger['priority']) { 1051 if ($trigger['status'] == TRIGGER_STATUS_DISABLED) { 1052 $i['trigger_disabled']++; 1053 } 1054 else { 1055 if ($trigger['value'] == TRIGGER_VALUE_TRUE) { 1056 $i['problem']++; 1057 $lastProblemId = $trigger['triggerid']; 1058 1059 if ($i['priority'] < $trigger['priority']) { 1060 $i['priority'] = $trigger['priority']; 1061 } 1062 1063 if ($trigger['lastEvent']) { 1064 if (!$trigger['lastEvent']['acknowledged']) { 1065 $i['problem_unack']++; 1066 } 1067 1068 $last_event = $last_event || true; 1069 } 1070 } 1071 1072 $i['latelyChanged'] |= ((time() - $trigger['lastchange']) < $config['blink_period']); 1073 } 1074 } 1075 } 1076 1077 // If there are no events, problems cannot be unacknowledged. Hide the green line in this case. 1078 $i['ack'] = ($last_event) ? (bool) !($i['problem_unack']) : false; 1079 1080 if ($sysmap['expandproblem'] && $i['problem'] == 1) { 1081 $i['problem_title'] = CMacrosResolverHelper::resolveTriggerName($selement['triggers'][$lastProblemId]); 1082 } 1083 1084 // replace default icons 1085 if (!$selement['iconid_on']) { 1086 $selement['iconid_on'] = $selement['iconid_off']; 1087 } 1088 if (!$selement['iconid_maintenance']) { 1089 $selement['iconid_maintenance'] = $selement['iconid_off']; 1090 } 1091 if (!$selement['iconid_disabled']) { 1092 $selement['iconid_disabled'] = $selement['iconid_off']; 1093 } 1094 1095 switch ($selement['elementtype']) { 1096 case SYSMAP_ELEMENT_TYPE_MAP: 1097 $info[$selementId] = getMapsInfo($selement, $i, $showUnacknowledged); 1098 break; 1099 1100 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 1101 $info[$selementId] = getHostGroupsInfo($selement, $i, $showUnacknowledged); 1102 break; 1103 1104 case SYSMAP_ELEMENT_TYPE_HOST: 1105 if ($i['maintenance'] == 1) { 1106 $mnt = get_maintenance_by_maintenanceid($allHosts[$last_hostid]['maintenanceid']); 1107 $i['maintenance_title'] = $mnt['name']; 1108 } 1109 1110 $info[$selementId] = getHostsInfo($selement, $i, $showUnacknowledged); 1111 if ($sysmap['iconmapid'] && $selement['use_iconmap']) { 1112 $info[$selementId]['iconid'] = getIconByMapping($iconMap, $hostInventories[$selement['elementid']]); 1113 } 1114 break; 1115 1116 case SYSMAP_ELEMENT_TYPE_TRIGGER: 1117 foreach ($trigger['hosts'] as $host) { 1118 if (array_key_exists('maintenance_status', $host) 1119 && $host['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) { 1120 $maintenance = get_maintenance_by_maintenanceid($host['maintenanceid']); 1121 $i['maintenance_title'] = $maintenance['name']; 1122 1123 break; 1124 } 1125 } 1126 1127 $info[$selementId] = getTriggersInfo($selement, $i, $showUnacknowledged); 1128 break; 1129 1130 case SYSMAP_ELEMENT_TYPE_IMAGE: 1131 $info[$selementId] = getImagesInfo($selement); 1132 break; 1133 } 1134 } 1135 1136 if ($sysmap['label_format'] == SYSMAP_LABEL_ADVANCED_OFF) { 1137 $hlabel = $hglabel = $tlabel = $mlabel = ($sysmap['label_type'] == MAP_LABEL_TYPE_NAME); 1138 } 1139 else { 1140 $hlabel = ($sysmap['label_type_host'] == MAP_LABEL_TYPE_NAME); 1141 $hglabel = ($sysmap['label_type_hostgroup'] == MAP_LABEL_TYPE_NAME); 1142 $tlabel = ($sysmap['label_type_trigger'] == MAP_LABEL_TYPE_NAME); 1143 $mlabel = ($sysmap['label_type_map'] == MAP_LABEL_TYPE_NAME); 1144 } 1145 1146 // get names if needed 1147 $elems = separateMapElements($sysmap); 1148 if (!empty($elems['sysmaps']) && $mlabel) { 1149 $subSysmaps = API::Map()->get([ 1150 'sysmapids' => zbx_objectValues($elems['sysmaps'], 'elementid'), 1151 'nopermissions' => true, 1152 'output' => ['name'] 1153 ]); 1154 $subSysmaps = zbx_toHash($subSysmaps, 'sysmapid'); 1155 1156 foreach ($elems['sysmaps'] as $elem) { 1157 $info[$elem['selementid']]['name'] = $subSysmaps[$elem['elementid']]['name']; 1158 } 1159 } 1160 if (!empty($elems['hostgroups']) && $hglabel) { 1161 $hostgroups = API::HostGroup()->get([ 1162 'groupids' => zbx_objectValues($elems['hostgroups'], 'elementid'), 1163 'nopermissions' => true, 1164 'output' => ['name'] 1165 ]); 1166 $hostgroups = zbx_toHash($hostgroups, 'groupid'); 1167 1168 foreach ($elems['hostgroups'] as $elem) { 1169 $info[$elem['selementid']]['name'] = $hostgroups[$elem['elementid']]['name']; 1170 } 1171 } 1172 1173 if (!empty($elems['triggers']) && $tlabel) { 1174 foreach ($elems['triggers'] as $selementid => $elem) { 1175 $trigger = $selements[$selementid]['triggers'][$elem['elementid']]; 1176 $info[$elem['selementid']]['name'] = CMacrosResolverHelper::resolveTriggerName($trigger); 1177 } 1178 } 1179 if (!empty($elems['hosts']) && $hlabel) { 1180 foreach ($elems['hosts'] as $elem) { 1181 $info[$elem['selementid']]['name'] = $allHosts[$elem['elementid']]['name']; 1182 } 1183 } 1184 1185 return $info; 1186} 1187 1188/** 1189 * Takes sysmap selements array, applies filtering by application to triggers and returns sysmap selements array. 1190 * 1191 * @param array $selements selements of current sysmap 1192 * @param array $selementHostApplicationFilters a list of application filters applied to each host under each element 1193 * @see getSelementHostApplicationFilters() 1194 * @param array $triggersFromMonitoredHosts triggers that are relevant to filtering 1195 * @param array $subSysmapTriggerIdToSelementIds a map of triggers in sysmaps to selement IDs 1196 * 1197 * @return array 1198 */ 1199function filterSysmapTriggers(array $selements, array $selementHostApplicationFilters, array $triggersFromMonitoredHosts, array $subSysmapTriggerIdToSelementIds) { 1200 // pick only host, host group or map selements 1201 $filterableSelements = []; 1202 foreach ($selements as $selementId => $selement) { 1203 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST 1204 || $selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST_GROUP 1205 || $selement['elementtype'] == SYSMAP_ELEMENT_TYPE_MAP) { 1206 $filterableSelements[$selementId] = $selement; 1207 } 1208 } 1209 // calculate list of triggers that might get removed from $selement['triggers'] 1210 $triggersToFilter = []; 1211 foreach ($filterableSelements as $selementId => $selement) { 1212 foreach ($selement['triggers'] as $trigger) { 1213 if (!isset($triggersFromMonitoredHosts[$trigger['triggerid']])) { 1214 continue; 1215 } 1216 $trigger = $triggersFromMonitoredHosts[$trigger['triggerid']]; 1217 foreach ($trigger['hosts'] as $host) { 1218 $hostId = $host['hostid']; 1219 if (isset($selementHostApplicationFilters[$selementId][$hostId])) { 1220 $triggersToFilter[$trigger['triggerid']] = $trigger; 1221 } 1222 } 1223 } 1224 } 1225 1226 // if there are no triggers to filter 1227 if (!$triggersToFilter) { 1228 return $selements; 1229 } 1230 1231 // produce mapping of trigger to application names it is related to and produce mapping of host to triggers 1232 $itemIds = []; 1233 foreach ($triggersToFilter as $trigger) { 1234 foreach ($trigger['items'] as $item) { 1235 $itemIds[$item['itemid']] = $item['itemid']; 1236 } 1237 } 1238 $items = API::Item()->get([ 1239 'output' => ['itemid'], 1240 'selectApplications' => ['name'], 1241 'itemids' => $itemIds, 1242 'webitems' => true, 1243 'preservekeys' => true 1244 ]); 1245 1246 $triggerApplications = []; 1247 $hostIdToTriggers = []; 1248 foreach ($triggersToFilter as $trigger) { 1249 $triggerId = $trigger['triggerid']; 1250 1251 foreach ($trigger['items'] as $item) { 1252 foreach ($items[$item['itemid']]['applications'] as $application) { 1253 $triggerApplications[$triggerId][$application['name']] = true; 1254 } 1255 } 1256 1257 foreach ($trigger['hosts'] as $host) { 1258 $hostIdToTriggers[$host['hostid']][$triggerId] = $trigger; 1259 } 1260 } 1261 1262 foreach ($filterableSelements as $selementId => &$selement) { 1263 // walk through each host of a submap and apply its filters to all its triggers 1264 foreach ($selement['hosts'] as $hostId) { 1265 // skip hosts that don't have any filters or triggers to filter 1266 if (!isset($hostIdToTriggers[$hostId]) || !isset($selementHostApplicationFilters[$selementId][$hostId])) { 1267 continue; 1268 } 1269 1270 // remove the triggers that don't have applications or don't match the filter 1271 $filteredApplicationNames = $selementHostApplicationFilters[$selementId][$hostId]; 1272 foreach ($hostIdToTriggers[$hostId] as $trigger) { 1273 $triggerId = $trigger['triggerid']; 1274 1275 // skip if this trigger is standalone trigger and those are not filtered 1276 if (isset($subSysmapTriggerIdToSelementIds[$triggerId]) 1277 && isset($subSysmapTriggerIdToSelementIds[$triggerId][$selementId])) { 1278 continue; 1279 } 1280 1281 $applicationNamesForTrigger = isset($triggerApplications[$triggerId]) 1282 ? array_keys($triggerApplications[$triggerId]) 1283 : []; 1284 1285 if (!array_intersect($applicationNamesForTrigger, $filteredApplicationNames)) { 1286 unset($selement['triggers'][$triggerId]); 1287 } 1288 } 1289 } 1290 } 1291 unset($selement); 1292 1293 // put back updated selements 1294 foreach ($filterableSelements as $selementId => $selement) { 1295 $selements[$selementId] = $selement; 1296 } 1297 1298 return $selements; 1299} 1300 1301/** 1302 * Returns a list of application filters applied to each host under each element. 1303 * 1304 * @param array $selements selements of current sysmap 1305 * @param array $selementIdToSubSysmaps all sub-sysmaps used in current sysmap, indexed by selementId 1306 * @param array $hostsFromHostGroups collection of hosts that get included via host groups 1307 * 1308 * @return array a two-dimensional array with selement IDs as the primary key, host IDs as the secondary key 1309 * application names as values 1310 */ 1311function getSelementHostApplicationFilters(array $selements, array $selementIdToSubSysmaps, array $hostsFromHostGroups) { 1312 $hostIdsForHostGroupId = []; 1313 foreach ($hostsFromHostGroups as $host) { 1314 $hostId = $host['hostid']; 1315 foreach ($host['groups'] as $group) { 1316 $hostIdsForHostGroupId[$group['groupid']][$hostId] = $hostId; 1317 } 1318 } 1319 1320 $selementHostApplicationFilters = []; 1321 foreach ($selements as $selementId => $selement) { 1322 switch ($selement['elementtype']) { 1323 case SYSMAP_ELEMENT_TYPE_HOST: 1324 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 1325 // skip host and host group elements with an empty filter 1326 if ($selement['application'] === '') { 1327 continue 2; 1328 } 1329 1330 foreach ($selement['hosts'] as $hostId) { 1331 $selementHostApplicationFilters[$selementId][$hostId][] = $selement['application']; 1332 } 1333 1334 break; 1335 1336 case SYSMAP_ELEMENT_TYPE_MAP: 1337 foreach ($selementIdToSubSysmaps[$selementId] as $subSysmap) { 1338 // add all filters set for host elements 1339 foreach ($subSysmap['selements'] as $subSysmapSelement) { 1340 if ($subSysmapSelement['elementtype'] != SYSMAP_ELEMENT_TYPE_HOST 1341 || $subSysmapSelement['application'] === '') { 1342 1343 continue; 1344 } 1345 1346 $hostId = $subSysmapSelement['elementid']; 1347 $selementHostApplicationFilters[$selementId][$hostId][] = $subSysmapSelement['application']; 1348 } 1349 1350 // Find all selements with host groups and sort them into two arrays: 1351 // - with application filter 1352 // - without application filter 1353 $hostGroupSelementsWithApplication = []; 1354 $hostGroupSelementsWithoutApplication = []; 1355 foreach ($subSysmap['selements'] as $subSysmapSelement) { 1356 if ($subSysmapSelement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST_GROUP) { 1357 if ($subSysmapSelement['application'] !== '') { 1358 $hostGroupSelementsWithApplication[] = $subSysmapSelement; 1359 } 1360 else { 1361 $hostGroupSelementsWithoutApplication[] = $subSysmapSelement; 1362 } 1363 } 1364 } 1365 1366 // Combine application filters for hosts from host group selements with 1367 // application filters set. 1368 foreach ($hostGroupSelementsWithApplication as $hostGroupSelement) { 1369 $hostGroupId = $hostGroupSelement['elementid']; 1370 1371 if (isset($hostIdsForHostGroupId[$hostGroupId])) { 1372 foreach ($hostIdsForHostGroupId[$hostGroupId] as $hostId) { 1373 $selementHostApplicationFilters[$selementId][$hostId][] = $hostGroupSelement['application']; 1374 } 1375 } 1376 } 1377 1378 // Unset all application filters for hosts in host group selements without any filters. 1379 // This might reset application filters set by previous foreach. 1380 foreach ($hostGroupSelementsWithoutApplication AS $hostGroupSelement) { 1381 $hostGroupId = $hostGroupSelement['elementid']; 1382 1383 if (isset($hostIdsForHostGroupId[$hostGroupId])) { 1384 foreach ($hostIdsForHostGroupId[$hostGroupId] as $hostId) { 1385 unset($selementHostApplicationFilters[$selementId][$hostId]); 1386 } 1387 } 1388 } 1389 } 1390 1391 break; 1392 } 1393 } 1394 1395 return $selementHostApplicationFilters; 1396} 1397 1398function separateMapElements($sysmap) { 1399 $elements = [ 1400 'sysmaps' => [], 1401 'hostgroups' => [], 1402 'hosts' => [], 1403 'triggers' => [], 1404 'images' => [] 1405 ]; 1406 1407 foreach ($sysmap['selements'] as $selement) { 1408 switch ($selement['elementtype']) { 1409 case SYSMAP_ELEMENT_TYPE_MAP: 1410 $elements['sysmaps'][$selement['selementid']] = $selement; 1411 break; 1412 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 1413 $elements['hostgroups'][$selement['selementid']] = $selement; 1414 break; 1415 case SYSMAP_ELEMENT_TYPE_HOST: 1416 $elements['hosts'][$selement['selementid']] = $selement; 1417 break; 1418 case SYSMAP_ELEMENT_TYPE_TRIGGER: 1419 $elements['triggers'][$selement['selementid']] = $selement; 1420 break; 1421 case SYSMAP_ELEMENT_TYPE_IMAGE: 1422 default: 1423 $elements['images'][$selement['selementid']] = $selement; 1424 } 1425 } 1426 return $elements; 1427} 1428 1429function drawMapConnectors(&$im, $map, $mapInfo, $drawAll = false) { 1430 $selements = $map['selements']; 1431 1432 foreach ($map['links'] as $link) { 1433 $selement1 = $selements[$link['selementid1']]; 1434 $selement2 = $selements[$link['selementid2']]; 1435 1436 list($x1, $y1) = get_icon_center_by_selement($selement1, $mapInfo[$link['selementid1']], $map); 1437 list($x2, $y2) = get_icon_center_by_selement($selement2, $mapInfo[$link['selementid2']], $map); 1438 1439 if (isset($selement1['elementsubtype']) && $selement1['elementsubtype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 1440 if (!$drawAll && ($selement2['elementsubtype'] != SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS)) { 1441 continue; 1442 } 1443 1444 if ($selement1['areatype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 1445 $w = $selement1['width']; 1446 $h = $selement1['height']; 1447 } 1448 else { 1449 $w = $map['width']; 1450 $h = $map['height']; 1451 } 1452 list($x1, $y1) = calculateMapAreaLinkCoord($x1, $y1, $w, $h, $x2, $y2); 1453 } 1454 1455 if (isset($selement2['elementsubtype']) && $selement2['elementsubtype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 1456 if (!$drawAll && ($selement1['elementsubtype'] != SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS)) { 1457 continue; 1458 } 1459 1460 if ($selement2['areatype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 1461 $w = $selement2['width']; 1462 $h = $selement2['height']; 1463 } 1464 else { 1465 $w = $map['width']; 1466 $h = $map['height']; 1467 } 1468 list($x2, $y2) = calculateMapAreaLinkCoord($x2, $y2, $w,$h, $x1, $y1); 1469 } 1470 1471 $drawtype = $link['drawtype']; 1472 $color = get_color($im, $link['color']); 1473 1474 $linktriggers = $link['linktriggers']; 1475 order_result($linktriggers, 'triggerid'); 1476 1477 if (!empty($linktriggers)) { 1478 $max_severity = 0; 1479 1480 $triggers = []; 1481 foreach ($linktriggers as $link_trigger) { 1482 if (!$link_trigger['monitored']) { 1483 continue; 1484 } 1485 1486 $id = $link_trigger['linktriggerid']; 1487 1488 $triggers[$id] = zbx_array_merge($link_trigger, get_trigger_by_triggerid($link_trigger['triggerid'])); 1489 if ($triggers[$id]['status'] == TRIGGER_STATUS_ENABLED && $triggers[$id]['value'] == TRIGGER_VALUE_TRUE) { 1490 if ($triggers[$id]['priority'] >= $max_severity) { 1491 $drawtype = $triggers[$id]['drawtype']; 1492 $color = get_color($im, $triggers[$id]['color']); 1493 $max_severity = $triggers[$id]['priority']; 1494 } 1495 } 1496 } 1497 } 1498 1499 myDrawLine($im, $x1, $y1, $x2, $y2, $color, $drawtype); 1500 } 1501} 1502 1503function drawMapSelements(&$im, $map, $mapInfo) { 1504 $selements = $map['selements']; 1505 1506 foreach ($selements as $selementId => $selement) { 1507 if (isset($selement['elementsubtype']) && $selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS) { 1508 continue; 1509 } 1510 1511 $elementInfo = $mapInfo[$selementId]; 1512 $img = get_png_by_selement($elementInfo); 1513 1514 $iconX = imagesx($img); 1515 $iconY = imagesy($img); 1516 1517 imagecopy($im, $img, $selement['x'], $selement['y'], 0, 0, $iconX, $iconY); 1518 } 1519} 1520 1521function drawMapHighligts(&$im, $map, $mapInfo) { 1522 $config = select_config(); 1523 1524 $selements = $map['selements']; 1525 1526 foreach ($selements as $selementId => $selement) { 1527 if (isset($selement['elementsubtype']) && $selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS) { 1528 continue; 1529 } 1530 1531 $elementInfo = $mapInfo[$selementId]; 1532 $img = get_png_by_selement($elementInfo); 1533 1534 $iconX = imagesx($img); 1535 $iconY = imagesy($img); 1536 1537 if (($map['highlight'] % 2) == SYSMAP_HIGHLIGHT_ON) { 1538 $hl_color = null; 1539 $st_color = null; 1540 1541 if ($elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_ON) { 1542 $hl_color = getSeverityColor($elementInfo['priority']); 1543 } 1544 1545 if ($elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_MAINTENANCE) { 1546 $st_color = 'FF9933'; 1547 } 1548 if ($elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_DISABLED) { 1549 $st_color = '999999'; 1550 } 1551 1552 $mainProblems = [ 1553 SYSMAP_ELEMENT_TYPE_HOST_GROUP => 1, 1554 SYSMAP_ELEMENT_TYPE_MAP => 1 1555 ]; 1556 1557 if (isset($mainProblems[$selement['elementtype']])) { 1558 if ($hl_color !== null) { 1559 $st_color = null; 1560 } 1561 } 1562 elseif (!is_null($st_color)) { 1563 $hl_color = null; 1564 } 1565 1566 if ($st_color !== null) { 1567 imagefilledrectangle($im, 1568 $selement['x'] - 2, 1569 $selement['y'] - 2, 1570 $selement['x'] + $iconX + 2, 1571 $selement['y'] + $iconY + 2, 1572 get_color($im, $st_color, 50) 1573 ); 1574 } 1575 1576 if ($hl_color !== null) { 1577 imagefilledellipse($im, 1578 $selement['x'] + ($iconX / 2), 1579 $selement['y'] + ($iconY / 2), 1580 $iconX + 20, 1581 $iconX + 20, 1582 get_color($im, $hl_color) 1583 ); 1584 1585 if (isset($elementInfo['ack']) && $elementInfo['ack'] && $config['event_ack_enable']) { 1586 imagesetthickness($im, 5); 1587 imagearc($im, 1588 $selement['x'] + ($iconX / 2), 1589 $selement['y'] + ($iconY / 2), 1590 $iconX + 20 - 2, 1591 $iconX + 20 - 2, 1592 0, 1593 359, 1594 imagecolorallocate($im, 50, 150, 50) 1595 ); 1596 imagesetthickness($im, 1); 1597 } 1598 } 1599 } 1600 } 1601} 1602 1603function drawMapSelementsMarks(&$im, $map, $mapInfo) { 1604 $selements = $map['selements']; 1605 1606 foreach ($selements as $selementId => $selement) { 1607 if (empty($selement)) { 1608 continue; 1609 } 1610 1611 $elementInfo = $mapInfo[$selementId]; 1612 if (!$elementInfo['latelyChanged']) { 1613 continue; 1614 } 1615 1616 // skip host group element containers 1617 if ($selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS) { 1618 continue; 1619 } 1620 1621 $img = get_png_by_selement($elementInfo); 1622 1623 $iconX = imagesx($img); 1624 $iconY = imagesy($img); 1625 1626 $hl_color = null; 1627 $st_color = null; 1628 if (!isset($_REQUEST['noselements']) && (($map['highlight'] % 2) == SYSMAP_HIGHLIGHT_ON)) { 1629 if ($elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_ON) { 1630 $hl_color = true; 1631 } 1632 if ($elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_MAINTENANCE 1633 || $elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_DISABLED) { 1634 $st_color = true; 1635 } 1636 } 1637 1638 $mainProblems = [ 1639 SYSMAP_ELEMENT_TYPE_HOST_GROUP => 1, 1640 SYSMAP_ELEMENT_TYPE_MAP => 1 1641 ]; 1642 1643 if (isset($mainProblems[$selement['elementtype']])) { 1644 if (!is_null($hl_color)) { 1645 $st_color = null; 1646 } 1647 elseif (!is_null($st_color)) { 1648 $hl_color = null; 1649 } 1650 } 1651 1652 $markSize = $iconX / 2; 1653 if ($hl_color) { 1654 $markSize += 12; 1655 } 1656 elseif ($st_color) { 1657 $markSize += 8; 1658 } 1659 else { 1660 $markSize += 3; 1661 } 1662 1663 if ($map['label_type'] != MAP_LABEL_TYPE_NOTHING) { 1664 $labelLocation = $selement['label_location']; 1665 if (is_null($labelLocation) || ($labelLocation < 0)) { 1666 $labelLocation = $map['label_location']; 1667 } 1668 1669 switch ($labelLocation) { 1670 case MAP_LABEL_LOC_TOP: 1671 $marks = 'rbl'; 1672 break; 1673 case MAP_LABEL_LOC_LEFT: 1674 $marks = 'trb'; 1675 break; 1676 case MAP_LABEL_LOC_RIGHT: 1677 $marks = 'tbl'; 1678 break; 1679 case MAP_LABEL_LOC_BOTTOM: 1680 default: 1681 $marks = 'trl'; 1682 } 1683 } 1684 else { 1685 $marks = 'trbl'; 1686 } 1687 1688 imageVerticalMarks($im, $selement['x'] + ($iconX / 2), $selement['y'] + ($iconY / 2), $markSize, 'FF0000', $marks); 1689 } 1690} 1691 1692function drawMapLinkLabels(&$im, $map, $mapInfo, $resolveMacros, $graphtheme) { 1693 $links = $map['links']; 1694 $selements = $map['selements']; 1695 1696 foreach ($links as $link) { 1697 if (empty($link['label'])) { 1698 continue; 1699 } 1700 1701 $selement1 = $selements[$link['selementid1']]; 1702 list($x1, $y1) = get_icon_center_by_selement($selement1, $mapInfo[$link['selementid1']], $map); 1703 1704 $selement2 = $selements[$link['selementid2']]; 1705 list($x2, $y2) = get_icon_center_by_selement($selement2, $mapInfo[$link['selementid2']], $map); 1706 1707 if (isset($selement1['elementsubtype']) && $selement1['elementsubtype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 1708 if ($selement1['areatype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 1709 $w = $selement1['width']; 1710 $h = $selement1['height']; 1711 } 1712 else { 1713 $w = $map['width']; 1714 $h = $map['height']; 1715 } 1716 list($x1, $y1) = calculateMapAreaLinkCoord($x1, $y1, $w, $h, $x2, $y2); 1717 } 1718 1719 if (isset($selement2['elementsubtype']) && $selement2['elementsubtype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 1720 if ($selement2['areatype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 1721 $w = $selement2['width']; 1722 $h = $selement2['height']; 1723 } 1724 else { 1725 $w = $map['width']; 1726 $h = $map['height']; 1727 } 1728 list($x2, $y2) = calculateMapAreaLinkCoord($x2, $y2, $w, $h, $x1, $y1); 1729 } 1730 1731 $drawtype = $link['drawtype']; 1732 $color = get_color($im, $link['color']); 1733 1734 $linktriggers = $link['linktriggers']; 1735 order_result($linktriggers, 'triggerid'); 1736 1737 if (!empty($linktriggers)) { 1738 $max_severity = 0; 1739 1740 $triggers = []; 1741 foreach ($linktriggers as $link_trigger) { 1742 if (!$link_trigger['monitored']) { 1743 continue; 1744 } 1745 $id = $link_trigger['linktriggerid']; 1746 1747 $triggers[$id] = zbx_array_merge($link_trigger, get_trigger_by_triggerid($link_trigger['triggerid'])); 1748 if ($triggers[$id]['status'] == TRIGGER_STATUS_ENABLED && $triggers[$id]['value'] == TRIGGER_VALUE_TRUE) { 1749 if ($triggers[$id]['priority'] >= $max_severity) { 1750 $drawtype = $triggers[$id]['drawtype']; 1751 $color = get_color($im, $triggers[$id]['color']); 1752 $max_severity = $triggers[$id]['priority']; 1753 } 1754 } 1755 } 1756 } 1757 1758 $label = $link['label']; 1759 1760 $label = str_replace("\r", '', $label); 1761 $strings = explode("\n", $label); 1762 1763 $box_width = 0; 1764 $box_height = 0; 1765 1766 foreach ($strings as $snum => $str) { 1767 $strings[$snum] = $resolveMacros ? CMacrosResolverHelper::resolveMapLabelMacros($str) : $str; 1768 } 1769 1770 foreach ($strings as $str) { 1771 $dims = imageTextSize(8, 0, $str); 1772 1773 $box_width = ($box_width > $dims['width']) ? $box_width : $dims['width']; 1774 $box_height += $dims['height'] + 2; 1775 } 1776 1777 $boxX_left = round(($x1 + $x2) / 2 - ($box_width / 2) - 6); 1778 $boxX_right = round(($x1 + $x2) / 2 + ($box_width / 2) + 6); 1779 1780 $boxY_top = round(($y1 + $y2) / 2 - ($box_height / 2) - 4); 1781 $boxY_bottom = round(($y1 + $y2) / 2 + ($box_height / 2) + 2); 1782 1783 switch ($drawtype) { 1784 case MAP_LINK_DRAWTYPE_DASHED_LINE: 1785 case MAP_LINK_DRAWTYPE_DOT: 1786 dashedRectangle($im, $boxX_left, $boxY_top, $boxX_right, $boxY_bottom, $color); 1787 break; 1788 case MAP_LINK_DRAWTYPE_BOLD_LINE: 1789 imagerectangle($im, $boxX_left - 1, $boxY_top - 1, $boxX_right + 1, $boxY_bottom + 1, $color); 1790 // break; is not ne 1791 case MAP_LINK_DRAWTYPE_LINE: 1792 default: 1793 imagerectangle($im, $boxX_left, $boxY_top, $boxX_right, $boxY_bottom, $color); 1794 } 1795 1796 imagefilledrectangle($im, $boxX_left + 1, $boxY_top + 1, $boxX_right - 1, $boxY_bottom - 1, 1797 get_color($im, $graphtheme['backgroundcolor']) 1798 ); 1799 1800 $color = get_color($im, $graphtheme['textcolor']); 1801 1802 $increasey = 4; 1803 foreach ($strings as $str) { 1804 $dims = imageTextSize(8, 0, $str); 1805 1806 $labelx = ($x1 + $x2) / 2 - ($dims['width'] / 2); 1807 $labely = $boxY_top + $increasey; 1808 1809 imagetext($im, 8, 0, $labelx, $labely + $dims['height'], $color, $str); 1810 1811 $increasey += $dims['height'] + 2; 1812 } 1813 } 1814} 1815 1816function drawMapLabels(&$im, $map, $mapInfo, $resolveMacros, $graphtheme) { 1817 if ($map['label_type'] == MAP_LABEL_TYPE_NOTHING && $map['label_format'] == SYSMAP_LABEL_ADVANCED_OFF) { 1818 return; 1819 } 1820 1821 $selements = $map['selements']; 1822 $allStrings = ''; 1823 $labelLines = []; 1824 $statusLines = []; 1825 1826 foreach ($selements as $sid => $selement) { 1827 if (isset($selement['elementsubtype']) && $selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS) { 1828 unset($selements[$sid]); 1829 } 1830 } 1831 1832 // set label type and custom label text for all selements 1833 foreach ($selements as $selementId => $selement) { 1834 $selements[$selementId]['label_type'] = $map['label_type']; 1835 1836 if ($map['label_format'] == SYSMAP_LABEL_ADVANCED_OFF) { 1837 continue; 1838 } 1839 1840 switch ($selement['elementtype']) { 1841 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 1842 $selements[$selementId]['label_type'] = $map['label_type_hostgroup']; 1843 if ($map['label_type_hostgroup'] == MAP_LABEL_TYPE_CUSTOM) { 1844 $selements[$selementId]['label'] = $map['label_string_hostgroup']; 1845 } 1846 break; 1847 1848 case SYSMAP_ELEMENT_TYPE_HOST: 1849 $selements[$selementId]['label_type'] = $map['label_type_host']; 1850 if ($map['label_type_host'] == MAP_LABEL_TYPE_CUSTOM) { 1851 $selements[$selementId]['label'] = $map['label_string_host']; 1852 } 1853 break; 1854 1855 case SYSMAP_ELEMENT_TYPE_TRIGGER: 1856 $selements[$selementId]['label_type'] = $map['label_type_trigger']; 1857 if ($map['label_type_trigger'] == MAP_LABEL_TYPE_CUSTOM) { 1858 $selements[$selementId]['label'] = $map['label_string_trigger']; 1859 } 1860 break; 1861 1862 case SYSMAP_ELEMENT_TYPE_MAP: 1863 $selements[$selementId]['label_type'] = $map['label_type_map']; 1864 if ($map['label_type_map'] == MAP_LABEL_TYPE_CUSTOM) { 1865 $selements[$selementId]['label'] = $map['label_string_map']; 1866 } 1867 break; 1868 1869 case SYSMAP_ELEMENT_TYPE_IMAGE: 1870 $selements[$selementId]['label_type'] = $map['label_type_image']; 1871 if ($map['label_type_image'] == MAP_LABEL_TYPE_CUSTOM) { 1872 $selements[$selementId]['label'] = $map['label_string_image']; 1873 } 1874 break; 1875 } 1876 } 1877 1878 foreach ($selements as $selementId => $selement) { 1879 if (!isset($labelLines[$selementId])) { 1880 $labelLines[$selementId] = []; 1881 } 1882 if (!isset($statusLines[$selementId])) { 1883 $statusLines[$selementId] = []; 1884 } 1885 1886 $msg = $resolveMacros ? CMacrosResolverHelper::resolveMapLabelMacrosAll($selement) : $selement['label']; 1887 1888 $allStrings .= $msg; 1889 $msgs = explode("\n", $msg); 1890 foreach ($msgs as $msg) { 1891 $labelLines[$selementId][] = ['msg' => $msg]; 1892 } 1893 1894 $elementInfo = $mapInfo[$selementId]; 1895 1896 foreach (['problem', 'unack', 'maintenance', 'ok', 'status'] as $caption) { 1897 if (!isset($elementInfo['info'][$caption]) || zbx_empty($elementInfo['info'][$caption]['msg'])) { 1898 continue; 1899 } 1900 1901 $statusLines[$selementId][] = [ 1902 'msg' => $elementInfo['info'][$caption]['msg'], 1903 'color' => $elementInfo['info'][$caption]['color'] 1904 ]; 1905 1906 $allStrings .= $elementInfo['info'][$caption]['msg']; 1907 } 1908 } 1909 1910 $allLabelsSize = imageTextSize(8, 0, str_replace("\r", '', str_replace("\n", '', $allStrings))); 1911 $labelFontHeight = $allLabelsSize['height']; 1912 $labelFontBaseline = $allLabelsSize['baseline']; 1913 1914 $elementsHostIds = []; 1915 foreach ($selements as $selement) { 1916 if ($selement['label_type'] != MAP_LABEL_TYPE_IP) { 1917 continue; 1918 } 1919 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST) { 1920 $elementsHostIds[] = $selement['elementid']; 1921 } 1922 } 1923 1924 if (!empty($elementsHostIds)) { 1925 $mapHosts = API::Host()->get([ 1926 'hostids' => $elementsHostIds, 1927 'output' => ['hostid'], 1928 'selectInterfaces' => API_OUTPUT_EXTEND 1929 ]); 1930 $mapHosts = zbx_toHash($mapHosts, 'hostid'); 1931 } 1932 1933 // draw 1934 foreach ($selements as $selementId => $selement) { 1935 if (empty($selement) || $selement['label_type'] == MAP_LABEL_TYPE_NOTHING) { 1936 continue; 1937 } 1938 1939 $elementInfo = $mapInfo[$selementId]; 1940 1941 $hl_color = null; 1942 $st_color = null; 1943 1944 if (!isset($_REQUEST['noselements']) && ($map['highlight'] % 2) == SYSMAP_HIGHLIGHT_ON) { 1945 if ($elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_ON) { 1946 $hl_color = true; 1947 } 1948 if ($elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_MAINTENANCE) { 1949 $st_color = true; 1950 } 1951 if ($elementInfo['icon_type'] == SYSMAP_ELEMENT_ICON_DISABLED) { 1952 $st_color = true; 1953 } 1954 } 1955 1956 if (in_array($selement['elementtype'], [SYSMAP_ELEMENT_TYPE_HOST_GROUP, SYSMAP_ELEMENT_TYPE_MAP]) 1957 && !is_null($hl_color)) { 1958 $st_color = null; 1959 } 1960 elseif (!is_null($st_color)) { 1961 $hl_color = null; 1962 } 1963 1964 $labelLocation = (is_null($selement['label_location']) || $selement['label_location'] < 0) 1965 ? $map['label_location'] 1966 : $selement['label_location']; 1967 1968 $label = []; 1969 1970 if ($selement['label_type'] == MAP_LABEL_TYPE_IP && $selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST) { 1971 $interface = reset($mapHosts[$selement['elementid']]['interfaces']); 1972 1973 $label[] = ['msg' => $interface['ip']]; 1974 $label = array_merge($label, $statusLines[$selementId]); 1975 } 1976 elseif ($selement['label_type'] == MAP_LABEL_TYPE_STATUS) { 1977 $label = $statusLines[$selementId]; 1978 } 1979 elseif ($selement['label_type'] == MAP_LABEL_TYPE_NAME) { 1980 $label[] = ['msg' => $elementInfo['name']]; 1981 $label = array_merge($label, $statusLines[$selementId]); 1982 } 1983 else { 1984 $label = array_merge($labelLines[$selementId], $statusLines[$selementId]); 1985 } 1986 1987 if (empty($label)) { 1988 continue; 1989 } 1990 1991 $w = 0; 1992 foreach ($label as $str) { 1993 $dims = imageTextSize(8, 0, $str['msg']); 1994 $w = max($w, $dims['width']); 1995 } 1996 1997 $h = count($label) * $labelFontHeight; 1998 $x = $selement['x']; 1999 $y = $selement['y']; 2000 2001 $image = get_png_by_selement($elementInfo); 2002 $iconX = imagesx($image); 2003 $iconY = imagesy($image); 2004 2005 if (!is_null($hl_color)) { 2006 $icon_hl = 14; 2007 } 2008 elseif (!is_null($st_color)) { 2009 $icon_hl = 6; 2010 } 2011 else { 2012 $icon_hl = 2; 2013 } 2014 2015 switch ($labelLocation) { 2016 case MAP_LABEL_LOC_TOP: 2017 $y_rec = $y - $icon_hl - $h - 6; 2018 $x_rec = $x + $iconX / 2 - $w / 2; 2019 break; 2020 2021 case MAP_LABEL_LOC_LEFT: 2022 $y_rec = $y - $h / 2 + $iconY / 2; 2023 $x_rec = $x - $icon_hl - $w; 2024 break; 2025 2026 case MAP_LABEL_LOC_RIGHT: 2027 $y_rec = $y - $h / 2 + $iconY / 2; 2028 $x_rec = $x + $iconX + $icon_hl; 2029 break; 2030 2031 case MAP_LABEL_LOC_BOTTOM: 2032 default: 2033 $y_rec = $y + $iconY + $icon_hl; 2034 $x_rec = $x + $iconX / 2 - $w / 2; 2035 } 2036 2037 $increasey = 12; 2038 foreach ($label as $line) { 2039 if (zbx_empty($line['msg'])) { 2040 continue; 2041 } 2042 2043 $str = str_replace("\r", '', $line['msg']); 2044 $color = isset($line['color']) ? $line['color'] : $graphtheme['textcolor']; 2045 2046 $dims = imageTextSize(8, 0, $str); 2047 2048 if ($labelLocation == MAP_LABEL_LOC_TOP || $labelLocation == MAP_LABEL_LOC_BOTTOM) { 2049 $x_label = $x + ceil($iconX / 2) - ceil($dims['width'] / 2); 2050 } 2051 elseif ($labelLocation == MAP_LABEL_LOC_LEFT) { 2052 $x_label = $x_rec + $w - $dims['width']; 2053 } 2054 else { 2055 $x_label = $x_rec; 2056 } 2057 2058 imagefilledrectangle( 2059 $im, 2060 $x_label - 1, $y_rec + $increasey - $labelFontHeight + $labelFontBaseline, 2061 $x_label + $dims['width'] + 1, $y_rec + $increasey + $labelFontBaseline, 2062 get_color($im, $graphtheme['backgroundcolor']) 2063 ); 2064 imagetext($im, 8, 0, $x_label, $y_rec + $increasey, get_color($im, $color), $str); 2065 2066 $increasey += $labelFontHeight + 1; 2067 } 2068 } 2069} 2070 2071/** 2072 * For each host group which is area for hosts virtual elements as hosts from that host group are created 2073 * 2074 * @param array $map 2075 * @return array areas with area coordinates and selementids 2076 */ 2077function populateFromMapAreas(array &$map) { 2078 $areas = []; 2079 2080 foreach ($map['selements'] as $selement) { 2081 if ($selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS) { 2082 $area = ['selementids' => []]; 2083 2084 $origSelement = $selement; 2085 2086 $hosts = API::host()->get([ 2087 'groupids' => $selement['elementid'], 2088 'sortfield' => 'name', 2089 'output' => ['hostid'], 2090 'nopermissions' => true, 2091 'preservekeys' => true 2092 ]); 2093 $hostsCount = count($hosts); 2094 2095 if ($hostsCount == 0) { 2096 continue; 2097 } 2098 2099 if ($selement['areatype'] == SYSMAP_ELEMENT_AREA_TYPE_CUSTOM) { 2100 $area['width'] = $selement['width']; 2101 $area['height'] = $selement['height']; 2102 $area['x'] = $selement['x']; 2103 $area['y'] = $selement['y']; 2104 } 2105 else { 2106 $area['width'] = $map['width']; 2107 $area['height'] = $map['height']; 2108 $area['x'] = 0; 2109 $area['y'] = 0; 2110 } 2111 2112 foreach ($hosts as $host) { 2113 $selement['elementtype'] = SYSMAP_ELEMENT_TYPE_HOST; 2114 $selement['elementsubtype'] = SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP; 2115 $selement['elementid'] = $host['hostid']; 2116 2117 $newSelementid = rand(1, 9999999); 2118 while (isset($map['selements'][$newSelementid])) { 2119 $newSelementid += 1; 2120 }; 2121 $selement['selementid'] = $newSelementid; 2122 2123 $area['selementids'][$newSelementid] = $newSelementid; 2124 $map['selements'][$newSelementid] = $selement; 2125 } 2126 2127 $areas[] = $area; 2128 2129 foreach ($map['links'] as $link) { 2130 // do not multiply links between two areas 2131 if ($map['selements'][$link['selementid1']]['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS 2132 && $map['selements'][$link['selementid2']]['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS) { 2133 continue; 2134 } 2135 2136 $idNumber = null; 2137 if ($link['selementid1'] == $origSelement['selementid']) { 2138 $idNumber = 'selementid1'; 2139 } 2140 elseif ($link['selementid2'] == $origSelement['selementid']) { 2141 $idNumber = 'selementid2'; 2142 } 2143 2144 if ($idNumber) { 2145 foreach ($area['selementids'] as $newSelementid) { 2146 $newLinkid = rand(1, 9999999); 2147 while (isset($map['links'][$newLinkid])) { 2148 $newLinkid += 1; 2149 }; 2150 2151 $link['linkid'] = $newLinkid; 2152 $link[$idNumber] = $newSelementid; 2153 $map['links'][$newLinkid] = $link; 2154 } 2155 } 2156 } 2157 } 2158 } 2159 2160 return $areas; 2161} 2162 2163/** 2164 * Calculates coordinates from elements inside areas 2165 * 2166 * @param array $map 2167 * @param array $areas 2168 * @param array $mapInfo 2169 * 2170 * @return void 2171 */ 2172function processAreasCoordinates(array &$map, array $areas, array $mapInfo) { 2173 foreach ($areas as $area) { 2174 $rowPlaceCount = ceil(sqrt(count($area['selementids']))); 2175 2176 // offset from area borders 2177 $area['x'] += 5; 2178 $area['y'] += 5; 2179 $area['width'] -= 5; 2180 $area['height'] -= 5; 2181 2182 $xOffset = floor($area['width'] / $rowPlaceCount); 2183 $yOffset = floor($area['height'] / $rowPlaceCount); 2184 2185 $colNum = 0; 2186 $rowNum = 0; 2187 // some offset is required so that icon highlights are not drawn outside area 2188 $borderOffset = 20; 2189 foreach ($area['selementids'] as $selementId) { 2190 $selement = $map['selements'][$selementId]; 2191 2192 $image = get_png_by_selement($mapInfo[$selementId]); 2193 $iconX = imagesx($image); 2194 $iconY = imagesy($image); 2195 2196 $labelLocation = (is_null($selement['label_location']) || ($selement['label_location'] < 0)) 2197 ? $map['label_location'] : $selement['label_location']; 2198 switch ($labelLocation) { 2199 case MAP_LABEL_LOC_TOP: 2200 $newX = $area['x'] + ($xOffset / 2) - ($iconX / 2); 2201 $newY = $area['y'] + $yOffset - $iconY - ($iconY >= $iconX ? 0 : abs($iconX - $iconY) / 2) - $borderOffset; 2202 break; 2203 case MAP_LABEL_LOC_LEFT: 2204 $newX = $area['x'] + $xOffset - $iconX - $borderOffset; 2205 $newY = $area['y'] + ($yOffset / 2) - ($iconY / 2); 2206 break; 2207 case MAP_LABEL_LOC_RIGHT: 2208 $newX = $area['x'] + $borderOffset; 2209 $newY = $area['y'] + ($yOffset / 2) - ($iconY / 2); 2210 break; 2211 case MAP_LABEL_LOC_BOTTOM: 2212 $newX = $area['x'] + ($xOffset / 2) - ($iconX / 2); 2213 $newY = $area['y'] + abs($iconX - $iconY) / 2 + $borderOffset; 2214 break; 2215 } 2216 2217 $map['selements'][$selementId]['x'] = $newX + ($colNum * $xOffset); 2218 $map['selements'][$selementId]['y'] = $newY + ($rowNum * $yOffset); 2219 2220 $colNum++; 2221 if ($colNum == $rowPlaceCount) { 2222 $colNum = 0; 2223 $rowNum++; 2224 } 2225 } 2226 } 2227} 2228 2229/** 2230 * Calculates area connector point on area perimeter 2231 * 2232 * @param int $ax x area coordinate 2233 * @param int $ay y area coordinate 2234 * @param int $aWidth area width 2235 * @param int $aHeight area height 2236 * @param int $x2 x coordinate of connector second element 2237 * @param int $y2 y coordinate of connector second element 2238 * 2239 * @return array contains two values, x and y coordinates of new area connector point 2240 */ 2241function calculateMapAreaLinkCoord($ax, $ay, $aWidth, $aHeight, $x2, $y2) { 2242 $dY = abs($y2 - $ay); 2243 $dX = abs($x2 - $ax); 2244 2245 $halfHeight = $aHeight / 2; 2246 $halfWidth = $aWidth / 2; 2247 2248 if ($dY == 0) { 2249 $ay = $y2; 2250 $ax = ($x2 < $ax) ? $ax - $halfWidth : $ax + $halfWidth; 2251 } 2252 elseif ($dX == 0) { 2253 $ay = ($y2 > $ay) ? $ay + $halfHeight : $ay - $halfHeight; 2254 $ax = $x2; 2255 } 2256 else { 2257 $koef = $halfHeight / $dY; 2258 2259 $c = $dX * $koef; 2260 2261 // if point is further than area diagonal, we should use calculations with width instead of height 2262 if (($halfHeight / $c) > ($halfHeight / $halfWidth)) { 2263 $ay = ($y2 > $ay) ? $ay + $halfHeight : $ay - $halfHeight; 2264 $ax = ($x2 < $ax) ? $ax - $c : $ax + $c; 2265 } 2266 else { 2267 $koef = $halfWidth / $dX; 2268 2269 $c = $dY * $koef; 2270 2271 $ay = ($y2 > $ay) ? $ay + $c : $ay - $c; 2272 $ax = ($x2 < $ax) ? $ax - $halfWidth : $ax + $halfWidth; 2273 } 2274 } 2275 2276 return [$ax, $ay]; 2277} 2278 2279/** 2280 * Get icon id by mapping. 2281 * 2282 * @param array $iconMap 2283 * @param array $inventory 2284 * 2285 * @return int 2286 */ 2287function getIconByMapping($iconMap, $inventory) { 2288 if (!empty($inventory['inventory'])) { 2289 $inventories = getHostInventories(); 2290 2291 foreach ($iconMap['mappings'] as $mapping) { 2292 try { 2293 $expr = new CGlobalRegexp($mapping['expression']); 2294 if ($expr->match($inventory['inventory'][$inventories[$mapping['inventory_link']]['db_field']])) { 2295 return $mapping['iconid']; 2296 } 2297 } 2298 catch(Exception $e) { 2299 continue; 2300 } 2301 } 2302 } 2303 2304 return $iconMap['default_iconid']; 2305} 2306 2307/** 2308 * Get parent maps for current map. 2309 * 2310 * @param int $sysmapid 2311 * 2312 * @return array 2313 */ 2314function get_parent_sysmaps($sysmapid) { 2315 $db_sysmaps_elements = DBselect( 2316 'SELECT DISTINCT se.sysmapid'. 2317 ' FROM sysmaps_elements se'. 2318 ' WHERE '.dbConditionInt('se.elementtype', [SYSMAP_ELEMENT_TYPE_MAP]). 2319 ' AND '.dbConditionInt('se.elementid', [$sysmapid]) 2320 ); 2321 2322 $sysmapids = []; 2323 2324 while ($db_sysmaps_element = DBfetch($db_sysmaps_elements)) { 2325 $sysmapids[] = $db_sysmaps_element['sysmapid']; 2326 } 2327 2328 if ($sysmapids) { 2329 $sysmaps = API::Map()->get([ 2330 'output' => ['sysmapid', 'name'], 2331 'sysmapids' => $sysmapids 2332 ]); 2333 2334 CArrayHelper::sort($sysmaps, ['name']); 2335 2336 return $sysmaps; 2337 } 2338 2339 return []; 2340} 2341 2342/** 2343 * Function extends link triggers adding boolean property 'monitored'. 2344 * 2345 * @param array $map 2346 */ 2347function resolveMapLinksTriggersState(&$map) { 2348 $triggerids = []; 2349 foreach ($map['links'] as $link) { 2350 $triggerids = array_merge($triggerids, zbx_objectValues($link['linktriggers'], 'triggerid')); 2351 } 2352 $monitored_triggers = API::Trigger()->get([ 2353 'output' => [], 2354 'triggerids' => $triggerids, 2355 'monitored' => true, 2356 'nopermissions' => true, 2357 'preservekeys' => true 2358 ]); 2359 2360 foreach ($map['links'] as $linkid => $link) { 2361 foreach ($link['linktriggers'] as $link_triggerid => $link_trigger) { 2362 $map['links'][$linkid]['linktriggers'][$link_triggerid]['monitored'] 2363 = array_key_exists($link_trigger['triggerid'], $monitored_triggers); 2364 } 2365 } 2366} 2367