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 22/** 23 * Class shares common properties, constants and methods for different controllers used for item tests. 24 */ 25abstract class CControllerPopupItemTest extends CController { 26 /** 27 * Types of preprocessing tests, depending on type of item. 28 */ 29 const ZBX_TEST_TYPE_ITEM = 0; 30 const ZBX_TEST_TYPE_ITEM_PROTOTYPE = 1; 31 const ZBX_TEST_TYPE_LLD = 2; 32 33 /** 34 * Max-length of input fields that can contain resolved macro values. Used in views for input fields. 35 * 36 * @var int 37 */ 38 public const INPUT_MAX_LENGTH = 2048; 39 40 /** 41 * Define a set of item types allowed to test and item properties needed to collect for each item type. 42 * 43 * @var array 44 */ 45 private static $testable_item_types = [ITEM_TYPE_ZABBIX, ITEM_TYPE_SIMPLE, ITEM_TYPE_INTERNAL, ITEM_TYPE_EXTERNAL, 46 ITEM_TYPE_DB_MONITOR, ITEM_TYPE_HTTPAGENT, ITEM_TYPE_SSH, ITEM_TYPE_TELNET, ITEM_TYPE_JMX, 47 ITEM_TYPE_CALCULATED, ITEM_TYPE_SNMP, ITEM_TYPE_SCRIPT 48 ]; 49 50 /** 51 * Item value type used if user has not specified one. 52 */ 53 const ZBX_DEFAULT_VALUE_TYPE = ITEM_VALUE_TYPE_TEXT; 54 55 /** 56 * Item types requiring interface. 57 * 58 * @var array 59 */ 60 protected $items_require_interface = [ 61 ITEM_TYPE_ZABBIX => [ 62 'address' => true, 63 'port' => true 64 ], 65 ITEM_TYPE_IPMI => [ 66 'address' => true, 67 'port' => true 68 ], 69 ITEM_TYPE_SIMPLE => [ 70 'address' => true, 71 'port' => false 72 ], 73 ITEM_TYPE_SNMP => [ 74 'address' => true, 75 'port' => true 76 ], 77 ITEM_TYPE_SSH => [ 78 'address' => true, 79 'port' => false 80 ], 81 ITEM_TYPE_TELNET => [ 82 'address' => true, 83 'port' => false 84 ] 85 ]; 86 87 /** 88 * Item types with proxy support. 89 * 90 * @var array 91 */ 92 protected $items_support_proxy = [ITEM_TYPE_ZABBIX, ITEM_TYPE_SIMPLE, ITEM_TYPE_INTERNAL, ITEM_TYPE_EXTERNAL, 93 ITEM_TYPE_DB_MONITOR, ITEM_TYPE_HTTPAGENT, ITEM_TYPE_IPMI, ITEM_TYPE_SSH, ITEM_TYPE_TELNET, ITEM_TYPE_JMX, 94 ITEM_TYPE_SNMP, ITEM_TYPE_SCRIPT 95 ]; 96 97 /** 98 * Item types with mandatory item key. 99 * 100 * @var array 101 */ 102 protected $item_types_has_key_mandatory = [ITEM_TYPE_ZABBIX, ITEM_TYPE_SIMPLE, ITEM_TYPE_INTERNAL, 103 ITEM_TYPE_EXTERNAL, ITEM_TYPE_DB_MONITOR, ITEM_TYPE_HTTPAGENT, ITEM_TYPE_IPMI, 104 ITEM_TYPE_SSH, ITEM_TYPE_TELNET, ITEM_TYPE_JMX, ITEM_TYPE_CALCULATED 105 ]; 106 107 /** 108 * Item properties where macros are supported. 109 * 110 * @var array 111 */ 112 protected $macros_by_item_props = [ 113 'key' => [ 114 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 115 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 116 'support_user_macros' => true, 117 'support_lld_macros' => true 118 ], 119 'params_es' => [ 120 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 121 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 122 'support_user_macros' => true, 123 'support_lld_macros' => true 124 ], 125 'params_ap' => [ 126 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 127 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 128 'support_user_macros' => true, 129 'support_lld_macros' => true 130 ], 131 'jmx_endpoint' => [ 132 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 133 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 134 'support_user_macros' => true, 135 'support_lld_macros' => true 136 ], 137 'url' => [ 138 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 139 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 140 'item' => ['{ITEM.ID}', '{ITEM.KEY.ORIG}', '{ITEM.KEY}'], 141 'support_user_macros' => true, 142 'support_lld_macros' => true 143 ], 144 'posts' => [ 145 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 146 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 147 'item' => ['{ITEM.ID}', '{ITEM.KEY.ORIG}', '{ITEM.KEY}'], 148 'support_user_macros' => true, 149 'support_lld_macros' => true 150 ], 151 'http_proxy' => [ 152 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 153 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 154 'item' => ['{ITEM.ID}', '{ITEM.KEY.ORIG}', '{ITEM.KEY}'], 155 'support_user_macros' => true, 156 'support_lld_macros' => true 157 ], 158 'ssl_cert_file' => [ 159 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 160 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 161 'item' => ['{ITEM.ID}', '{ITEM.KEY.ORIG}', '{ITEM.KEY}'], 162 'support_user_macros' => true, 163 'support_lld_macros' => true 164 ], 165 'ssl_key_file' => [ 166 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 167 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 168 'item' => ['{ITEM.ID}', '{ITEM.KEY.ORIG}', '{ITEM.KEY}'], 169 'support_user_macros' => true, 170 'support_lld_macros' => true 171 ], 172 'query_fields' => [ 173 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 174 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 175 'item' => ['{ITEM.ID}', '{ITEM.KEY.ORIG}', '{ITEM.KEY}'], 176 'support_user_macros' => true, 177 'support_lld_macros' => true 178 ], 179 'headers' => [ 180 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 181 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}', '{HOST.PORT}'], 182 'item' => ['{ITEM.ID}', '{ITEM.KEY.ORIG}', '{ITEM.KEY}'], 183 'support_user_macros' => true, 184 'support_lld_macros' => true 185 ], 186 'parameters' => [ 187 'host' => ['{HOSTNAME}', '{HOST.HOST}', '{HOST.NAME}'], 188 'interface' => ['{HOST.IP}', '{IPADDRESS}', '{HOST.DNS}', '{HOST.CONN}'], 189 'item' => ['{ITEM.ID}', '{ITEM.KEY.ORIG}', '{ITEM.KEY}'], 190 'support_user_macros' => true, 191 'support_lld_macros' => true 192 ], 193 'params_f' => [], 194 'script' => [ 195 'support_user_macros' => true, 196 'support_lld_macros' => true 197 ], 198 'timeout' => [ 199 'support_user_macros' => true, 200 'support_lld_macros' => true 201 ], 202 'ipmi_sensor' => [ 203 'support_user_macros' => false, 204 'support_lld_macros' => true 205 ], 206 'snmp_oid' => [ 207 'support_user_macros' => true, 208 'support_lld_macros' => true 209 ], 210 'username' => [ 211 'support_user_macros' => true, 212 'support_lld_macros' => true 213 ], 214 'password' => [ 215 'support_user_macros' => true, 216 'support_lld_macros' => true 217 ], 218 'http_username' => [ 219 'support_user_macros' => true, 220 'support_lld_macros' => true 221 ], 222 'http_password' => [ 223 'support_user_macros' => true, 224 'support_lld_macros' => true 225 ] 226 ]; 227 228 /** 229 * Tested item type. 230 * 231 * @var int 232 */ 233 protected $item_type; 234 235 /** 236 * Tested item's host. 237 * 238 * @var array 239 */ 240 protected $host; 241 242 /** 243 * Is item testable. 244 * 245 * @var bool 246 */ 247 protected $is_item_testable; 248 249 /** 250 * @var object 251 */ 252 protected $preproc_item; 253 254 /** 255 * @var array 256 */ 257 protected static $preproc_steps_using_prev_value = [ZBX_PREPROC_DELTA_VALUE, ZBX_PREPROC_DELTA_SPEED, 258 ZBX_PREPROC_THROTTLE_VALUE, ZBX_PREPROC_THROTTLE_TIMED_VALUE 259 ]; 260 261 /** 262 * @var int 263 */ 264 protected $eol; 265 266 /** 267 * Get testable item types based on host type. 268 * 269 * @param string $hostid 270 * 271 * @return array 272 */ 273 public static function getTestableItemTypes(string $hostid = '0'): array { 274 if ($hostid != 0 && self::isItemTypeTestable($hostid)) { 275 self::$testable_item_types[] = ITEM_TYPE_IPMI; 276 } 277 278 return self::$testable_item_types; 279 } 280 281 /** 282 * Function checks if item type can be tested depending on what type of host it belongs to. 283 * 284 * @param string $hostid 285 * 286 * @return bool 287 */ 288 protected static function isItemTypeTestable(string $hostid): bool { 289 $ret = (bool) API::Template()->get([ 290 'countOutput' => true, 291 'templateids' => [$hostid] 292 ]); 293 294 return !$ret; 295 } 296 297 protected function checkPermissions() { 298 $ret = ($this->getUserType() >= USER_TYPE_ZABBIX_ADMIN); 299 300 /* 301 * Preprocessing test can be done from mass-update section so host is non mandatory but if it is used, it must 302 * be editable. 303 */ 304 $hostid = $this->getInput('hostid', 0); 305 306 if ($ret && $hostid != 0) { 307 $hosts = API::Host()->get([ 308 'output' => ['hostid', 'host', 'name', 'status', 'proxy_hostid', 'tls_subject', 'maintenance_status', 309 'maintenance_type', 'ipmi_authtype', 'ipmi_privilege', 'ipmi_username', 'ipmi_password', 310 'tls_issuer', 'tls_connect' 311 ], 312 'hostids' => [$hostid], 313 'editable' => true 314 ]); 315 316 if (!$hosts) { 317 $hosts = API::Template()->get([ 318 'output' => ['templateid', 'host', 'name', 'status'], 319 'templateids' => [$hostid], 320 'editable' => true 321 ]); 322 323 $hosts[0] = CArrayHelper::renameKeys($hosts[0], ['templateid' => 'hostid']); 324 } 325 326 $this->host = reset($hosts); 327 328 return (bool) $this->host; 329 } 330 331 return $ret; 332 } 333 334 /** 335 * Function returns instance of item, item prototype or discovery rule class. 336 * 337 * @param int $test_type 338 * 339 * @return CItem|CItemPrototype|CDiscoveryRule 340 */ 341 protected static function getPreprocessingItemClassInstance($test_type) { 342 switch ($test_type) { 343 case self::ZBX_TEST_TYPE_ITEM: 344 return new CItem; 345 346 case self::ZBX_TEST_TYPE_ITEM_PROTOTYPE: 347 return new CItemPrototype; 348 349 case self::ZBX_TEST_TYPE_LLD: 350 return new CDiscoveryRule; 351 } 352 } 353 354 /** 355 * Function returns list of proxies. 356 * 357 * @return array 358 */ 359 protected function getHostProxies() { 360 $proxies = API::Proxy()->get([ 361 'output' => ['host'], 362 'preservekeys' => true 363 ]); 364 365 CArrayHelper::sort($proxies, [['field' => 'host', 'order' => ZBX_SORT_UP]]); 366 367 foreach ($proxies as &$proxy) { 368 $proxy = $proxy['host']; 369 } 370 unset($proxy); 371 372 return $proxies; 373 } 374 375 /** 376 * Function returns array of item specific properties used for item testing. 377 * 378 * @param array $input Stored user input used to overwrite values retrieved from database. 379 * @param bool $for_server Whether need to add to result an additional properties used only for connection with 380 * Zabbix server. 381 * 382 * @return array 383 */ 384 protected function getItemTestProperties(array $input, bool $for_server = false) { 385 $data = [ 386 'value_type' => $input['value_type'] 387 ]; 388 389 if (!$this->is_item_testable) { 390 return $data; 391 } 392 393 $data['type'] = $this->item_type; 394 395 if (array_key_exists('itemid', $input)) { 396 $data['itemid'] = $input['itemid']; 397 } 398 399 if (array_key_exists('interface', $input) && array_key_exists('interfaceid', $input['interface'])) { 400 $interface_input['interfaceid'] = $input['interface']['interfaceid']; 401 } 402 elseif (array_key_exists('interfaceid', $input)) { 403 $interface_input['interfaceid'] = $input['interfaceid']; 404 } 405 else { 406 $interface_input['interfaceid'] = 0; 407 } 408 409 if (array_key_exists('interface', $input) && array_key_exists('useip', $input['interface'])) { 410 $interface_input['useip'] = $input['interface']['useip']; 411 } 412 413 if (array_key_exists('data', $input) && array_key_exists('port', $input['data'])) { 414 $interface_input['port'] = $input['data']['port']; 415 } 416 elseif (array_key_exists('interface', $input) && array_key_exists('port', $input['interface'])) { 417 $interface_input['port'] = $input['interface']['port']; 418 } 419 420 if (array_key_exists('data', $input) && array_key_exists('address', $input['data'])) { 421 $interface_input['address'] = $input['data']['address']; 422 } 423 elseif (array_key_exists('interface', $input) && array_key_exists('address', $input['interface'])) { 424 $interface_input['address'] = $input['interface']['address']; 425 } 426 elseif (array_key_exists('address', $input)) { 427 $interface_input['address'] = $input['address']; 428 } 429 430 if (array_key_exists('data', $input) && array_key_exists('interface_details', $input['data']) 431 && is_array($input['data']['interface_details'])) { 432 $interface_input['details'] = $input['data']['interface_details']; 433 } 434 elseif (array_key_exists('interface', $input) && array_key_exists('details', $input['interface'])) { 435 $interface_input['details'] = $input['interface']['details']; 436 } 437 438 // Set proxy. 439 if (in_array($this->item_type, $this->items_support_proxy)) { 440 if (array_key_exists('data', $input) && array_key_exists('proxy_hostid', $input['data'])) { 441 $data['proxy_hostid'] = $input['data']['proxy_hostid']; 442 } 443 elseif (array_key_exists('proxy_hostid', $input)) { 444 $data['proxy_hostid'] = $input['proxy_hostid']; 445 } 446 elseif (array_key_exists('proxy_hostid', $this->host)) { 447 $data['proxy_hostid'] = $this->host['proxy_hostid']; 448 } 449 else { 450 $data['proxy_hostid'] = 0; 451 } 452 } 453 454 switch ($this->item_type) { 455 case ITEM_TYPE_ZABBIX: 456 $data += [ 457 'key' => array_key_exists('key', $input) ? $input['key'] : null, 458 'interface' => $this->getHostInterface($interface_input) 459 ]; 460 461 if ($this->host['status'] != HOST_STATUS_TEMPLATE) { 462 $data['host'] = [ 463 'tls_issuer' => $this->host['tls_issuer'], 464 'tls_connect' => $this->host['tls_connect'], 465 'tls_subject' => $this->host['tls_subject'] 466 ]; 467 468 if ($for_server && $this->host['tls_connect'] == HOST_ENCRYPTION_PSK) { 469 $hosts = API::Host()->get([ 470 'output' => ['tls_psk_identity', 'tls_psk'], 471 'hostids' => $this->host['hostid'], 472 'editable' => true 473 ]); 474 $host = reset($hosts); 475 476 $data['host']['tls_psk_identity'] = $host['tls_psk_identity']; 477 $data['host']['tls_psk'] = $host['tls_psk']; 478 } 479 } 480 481 unset($data['interface']['useip'], $data['interface']['interfaceid'], $data['interface']['ip'], 482 $data['interface']['dns'] 483 ); 484 break; 485 486 case ITEM_TYPE_SNMP: 487 if (!array_key_exists('flags', $input)) { 488 $items = (array_key_exists('itemid', $input)) 489 ? API::Item()->get([ 490 'output' => ['flags'], 491 'itemids' => $input['itemid'] 492 ]) 493 : []; 494 495 if ($items) { 496 $item_flag = $items[0]['flags']; 497 } 498 else { 499 switch ($this->getInput('test_type')) { 500 case self::ZBX_TEST_TYPE_LLD: 501 $item_flag = ZBX_FLAG_DISCOVERY_RULE; 502 break; 503 504 case self::ZBX_TEST_TYPE_ITEM_PROTOTYPE; 505 $item_flag = ZBX_FLAG_DISCOVERY_PROTOTYPE; 506 break; 507 508 default: 509 $item_flag = ZBX_FLAG_DISCOVERY_NORMAL; 510 break; 511 } 512 } 513 } 514 else { 515 $item_flag = $input['flags']; 516 } 517 518 $data += [ 519 'snmp_oid' => array_key_exists('snmp_oid', $input) ? $input['snmp_oid'] : null, 520 'flags' => $item_flag, 521 'host' => [ 522 'host' => $this->host['host'] 523 ], 524 'interface' => $this->getHostInterface($interface_input) 525 ]; 526 527 unset($data['interface']['ip'], $data['interface']['dns']); 528 break; 529 530 case ITEM_TYPE_INTERNAL: 531 $data += [ 532 'key' => $input['key'], 533 'host' => [ 534 'hostid' => $this->host['hostid'] 535 ] 536 ]; 537 538 if ($this->host['status'] != HOST_STATUS_TEMPLATE) { 539 $data['host'] += [ 540 'maintenance_status' => $this->host['maintenance_status'], 541 'maintenance_type' => $this->host['maintenance_type'] 542 ]; 543 } 544 break; 545 546 case ITEM_TYPE_EXTERNAL: 547 $data += [ 548 'key' => $input['key'] 549 ]; 550 break; 551 552 case ITEM_TYPE_DB_MONITOR: 553 $data += [ 554 'key' => $input['key'], 555 'params_ap' => array_key_exists('params_ap', $input) ? $input['params_ap'] : null, 556 'username' => array_key_exists('username', $input) ? $input['username'] : null, 557 'password' => array_key_exists('password', $input) ? $input['password'] : null 558 ]; 559 break; 560 561 case ITEM_TYPE_HTTPAGENT: 562 $data += [ 563 'key' => $input['key'], 564 'http_authtype' => array_key_exists('http_authtype', $input) 565 ? $input['http_authtype'] 566 : HTTPTEST_AUTH_NONE, 567 'follow_redirects' => array_key_exists('follow_redirects', $input) ? $input['follow_redirects'] : 0, 568 'headers' => array_key_exists('headers', $input) ? $input['headers'] : [], 569 'http_proxy' => array_key_exists('http_proxy', $input) ? $input['http_proxy'] : null, 570 'output_format' => array_key_exists('output_format', $input) ? $input['output_format'] : 0, 571 'posts' => array_key_exists('posts', $input) ? $input['posts'] : null, 572 'post_type' => array_key_exists('post_type', $input) ? $input['post_type'] : ZBX_POSTTYPE_RAW, 573 'query_fields' => array_key_exists('query_fields', $input) ? $input['query_fields'] : [], 574 'request_method' => array_key_exists('request_method', $input) 575 ? $input['request_method'] 576 : HTTPCHECK_REQUEST_GET, 577 'retrieve_mode' => array_key_exists('retrieve_mode', $input) 578 ? $input['retrieve_mode'] 579 : HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, 580 'ssl_cert_file' => array_key_exists('ssl_cert_file', $input) ? $input['ssl_cert_file'] : null, 581 'ssl_key_file' => array_key_exists('ssl_key_file', $input) ? $input['ssl_key_file'] : null, 582 'ssl_key_password' => array_key_exists('ssl_key_password', $input) 583 ? $input['ssl_key_password'] 584 : null, 585 'status_codes' => array_key_exists('status_codes', $input) ? $input['status_codes'] : null, 586 'timeout' => array_key_exists('timeout', $input) ? $input['timeout'] : null, 587 'url' => array_key_exists('url', $input) ? $input['url'] : null, 588 'verify_host' => array_key_exists('verify_host', $input) ? $input['verify_host'] : 0, 589 'verify_peer' => array_key_exists('verify_peer', $input) ? $input['verify_peer'] : 0 590 ]; 591 592 if ($data['http_authtype'] != HTTPTEST_AUTH_NONE) { 593 $data += [ 594 'http_username' => array_key_exists('http_username', $input) ? $input['http_username'] : null, 595 'http_password' => array_key_exists('http_password', $input) ? $input['http_password'] : null 596 ]; 597 } 598 break; 599 600 case ITEM_TYPE_IPMI: 601 $data += [ 602 'key' => $input['key'], 603 'ipmi_sensor' => array_key_exists('ipmi_sensor', $input) ? $input['ipmi_sensor'] : null, 604 'interface' => $this->getHostInterface($interface_input), 605 'host' => [ 606 'hostid' => $this->host['hostid'] 607 ] 608 ]; 609 610 if ($this->host['status'] != HOST_STATUS_TEMPLATE) { 611 $data['host'] += [ 612 'ipmi_authtype' => $this->host['ipmi_authtype'], 613 'ipmi_privilege' => $this->host['ipmi_privilege'], 614 'ipmi_username' => $this->host['ipmi_username'], 615 'ipmi_password' => $this->host['ipmi_password'] 616 ]; 617 } 618 619 unset($data['interface']['useip'], $data['interface']['interfaceid'], $data['interface']['ip'], 620 $data['interface']['dns'] 621 ); 622 break; 623 624 case ITEM_TYPE_SSH: 625 $data += [ 626 'key' => $input['key'], 627 'authtype' => array_key_exists('authtype', $input) ? $input['authtype'] : ITEM_AUTHTYPE_PASSWORD, 628 'params_es' => array_key_exists('params_es', $input) ? $input['params_es'] : ITEM_AUTHTYPE_PASSWORD, 629 'username' => array_key_exists('username', $input) ? $input['username'] : null, 630 'password' => array_key_exists('password', $input) ? $input['password'] : null, 631 'interface' => $this->getHostInterface($interface_input) 632 ]; 633 634 if ($data['authtype'] == ITEM_AUTHTYPE_PUBLICKEY) { 635 $data += [ 636 'publickey' => array_key_exists('publickey', $input) ? $input['publickey'] : null, 637 'privatekey' => array_key_exists('privatekey', $input) ? $input['privatekey'] : null 638 ]; 639 } 640 break; 641 642 case ITEM_TYPE_TELNET: 643 $data += [ 644 'key' => $input['key'], 645 'params_es' => array_key_exists('params_es', $input) ? $input['params_es'] : null, 646 'username' => array_key_exists('username', $input) ? $input['username'] : null, 647 'password' => array_key_exists('password', $input) ? $input['password'] : null, 648 'interface' => $this->getHostInterface($interface_input) 649 ]; 650 break; 651 652 case ITEM_TYPE_JMX: 653 $data += [ 654 'key' => $input['key'], 655 'jmx_endpoint' => array_key_exists('jmx_endpoint', $input) ? $input['jmx_endpoint'] : null, 656 'username' => array_key_exists('username', $input) ? $input['username'] : null, 657 'password' => array_key_exists('password', $input) ? $input['password'] : null 658 ]; 659 break; 660 661 case ITEM_TYPE_CALCULATED: 662 $data += [ 663 'key' => $input['key'], 664 'params_f' => array_key_exists('params_f', $input) ? $input['params_f'] : null, 665 'host' => [ 666 'host' => $this->host['host'] 667 ] 668 ]; 669 break; 670 671 case ITEM_TYPE_SIMPLE: 672 $data += [ 673 'key' => $input['key'], 674 'interface' => $this->getHostInterface($interface_input), 675 'username' => array_key_exists('username', $input) ? $input['username'] : null, 676 'password' => array_key_exists('password', $input) ? $input['password'] : null 677 ]; 678 679 unset($data['interface']['useip'], $data['interface']['interfaceid'], $data['interface']['ip'], 680 $data['interface']['dns'], $data['interface']['port'] 681 ); 682 break; 683 684 case ITEM_TYPE_SCRIPT: 685 $data += [ 686 'key' => $input['key'], 687 'parameters' => array_key_exists('parameters', $input) ? $input['parameters'] : [], 688 'script' => array_key_exists('script', $input) ? $input['script'] : null, 689 'timeout' => array_key_exists('timeout', $input) ? $input['timeout'] : null 690 ]; 691 break; 692 } 693 694 return $data; 695 } 696 697 /** 698 * Check if item belongs to host and select and resolve interface properties. Leave fields empty otherwise. 699 * 700 * @param array $inputs Stored user input used to overwrite values retrieved from database. 701 * 702 * @return array $interface_data 703 */ 704 protected function getHostInterface(array $inputs) { 705 $interface_data = [ 706 'address' => '', 707 'port' => '', 708 'interfaceid' => 0, 709 'type' => INTERFACE_TYPE_UNKNOWN, 710 'ip' => '', 711 'dns' => '', 712 'useip' => INTERFACE_USE_DNS, 713 'details' => [ 714 'community' => '', 715 'version' => SNMP_V2C, 716 'securityname' => '', 717 'securitylevel' => ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV, 718 'authpassphrase' => '', 719 'privpassphrase' => '', 720 'authprotocol' => ITEM_SNMPV3_AUTHPROTOCOL_MD5, 721 'privprotocol' => ITEM_SNMPV3_PRIVPROTOCOL_DES, 722 'contextname' => '' 723 ] 724 ]; 725 726 if ($this->item_type != ITEM_TYPE_SNMP) { 727 unset($interface_data['details'], $inputs['details']); 728 } 729 730 // Get values from database; resolve macros. 731 if (($this->host['status'] == HOST_STATUS_MONITORED || $this->host['status'] == HOST_STATUS_NOT_MONITORED) 732 && array_key_exists('interfaceid', $inputs)) { 733 $output = ['hostid', 'type', 'dns', 'ip', 'port', 'main', 'useip']; 734 $interfaces = []; 735 736 if ($this->item_type == ITEM_TYPE_SNMP) { 737 $output[] = 'details'; 738 } 739 740 if (itemTypeInterface($this->item_type) === false) { 741 $host_interfaces = API::HostInterface()->get([ 742 'output' => $output, 743 'hostids' => $this->host['hostid'], 744 'filter' => ['main' => INTERFACE_PRIMARY] 745 ]); 746 $host_interfaces = zbx_toHash($host_interfaces, 'type'); 747 748 $ordered_interface_types = [INTERFACE_TYPE_AGENT, INTERFACE_TYPE_SNMP, INTERFACE_TYPE_JMX, 749 INTERFACE_TYPE_IPMI 750 ]; 751 752 foreach ($ordered_interface_types as $interface_type) { 753 if (array_key_exists($interface_type, $host_interfaces)) { 754 $interfaces[] = $host_interfaces[$interface_type]; 755 break; 756 } 757 } 758 } 759 else { 760 $interfaces = API::HostInterface()->get([ 761 'output' => $output, 762 'interfaceids' => $inputs['interfaceid'], 763 'hostids' => $this->host['hostid'] 764 ]); 765 } 766 767 if (count($interfaces) != 0) { 768 $interfaces = CMacrosResolverHelper::resolveHostInterfaces($interfaces); 769 $interface_data = ($this->item_type == ITEM_TYPE_SNMP) 770 ? ['details' => $interfaces[0]['details'] + $interface_data['details']] 771 : []; 772 773 $interface_data += [ 774 'address' => ($interfaces[0]['useip'] == INTERFACE_USE_IP) 775 ? $interfaces[0]['ip'] 776 : $interfaces[0]['dns'], 777 'port' => $interfaces[0]['port'], 778 'useip' => $interfaces[0]['useip'], 779 'type' => $interfaces[0]['type'], 780 'ip' => $interfaces[0]['ip'], 781 'dns' => $interfaces[0]['dns'], 782 'interfaceid' => $interfaces[0]['interfaceid'] 783 ]; 784 } 785 } 786 787 if ($this->item_type == ITEM_TYPE_SCRIPT) { 788 return $interface_data; 789 } 790 791 // Apply client side cache. 792 foreach ($inputs as $key => $value) { 793 if (is_array($value)) { 794 $interface_data[$key] = $value + $interface_data[$key]; 795 } 796 else { 797 $interface_data[$key] = $value; 798 } 799 } 800 801 return $interface_data; 802 } 803 804 /** 805 * Function returns human readable time used for previous time field in item test. 806 * 807 * @return string 808 */ 809 protected function getPrevTime() { 810 $time_change = max($this->getInput('time_change', 1), 1); 811 812 if ($time_change >= SEC_PER_DAY) { 813 $n = floor($time_change / SEC_PER_DAY); 814 return 'now-'.$n.'d'; 815 } 816 elseif ($time_change >= SEC_PER_HOUR * 5) { 817 $n = floor($time_change / SEC_PER_HOUR); 818 return 'now-'.$n.'h'; 819 } 820 elseif ($time_change >= SEC_PER_MIN * 5) { 821 $n = floor($time_change / SEC_PER_MIN); 822 return 'now-'.$n.'m'; 823 } 824 else { 825 return 'now-'.$time_change.'s'; 826 } 827 } 828 829 /** 830 * Function to unset unspecified values before sending 'get value' request to server. 831 * 832 * @param array $data Data array containing all parameters prepared to be sent to server. 833 * 834 * @return array 835 */ 836 protected function unsetEmptyValues(array $data) { 837 foreach ($data as $key => $value) { 838 if ($key === 'host' && is_array($value)) { 839 $data[$key] = $this->unsetEmptyValues($value); 840 841 if (!$data[$key]) { 842 unset($data[$key]); 843 } 844 } 845 elseif ($key === 'interface' && $this->item_type == ITEM_TYPE_SNMP) { 846 if ($data['interface']['details']['version'] == SNMP_V3) { 847 unset($data['interface']['details']['community']); 848 849 if ($data['interface']['details']['securitylevel'] == ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV) { 850 unset($data['interface']['details']['authprotocol'], 851 $data['interface']['details']['authpassphrase'], 852 $data['interface']['details']['privprotocol'], 853 $data['interface']['details']['privpassphrase'] 854 ); 855 } 856 elseif ($data['interface']['details']['securitylevel'] == ITEM_SNMPV3_SECURITYLEVEL_AUTHNOPRIV) { 857 unset($data['interface']['details']['privprotocol'], 858 $data['interface']['details']['privpassphrase'] 859 ); 860 } 861 } 862 else { 863 unset($data['interface']['details']['contextname'], 864 $data['interface']['details']['securityname'], 865 $data['interface']['details']['securitylevel'], 866 $data['interface']['details']['authprotocol'], 867 $data['interface']['details']['authpassphrase'], 868 $data['interface']['details']['privprotocol'], 869 $data['interface']['details']['privpassphrase'] 870 ); 871 } 872 873 unset($data['interface']['type']); 874 } 875 elseif ($key === 'query_fields') { 876 if ($value === '[]') { 877 unset($data[$key]); 878 } 879 } 880 elseif ($key === 'parameters') { 881 if (!$value) { 882 unset($data[$key]); 883 } 884 } 885 elseif ($value === '' || $value === null) { 886 unset($data[$key]); 887 } 888 } 889 890 return $data; 891 } 892 893 /** 894 * Function returns array containing values for each of supported macros. 895 * 896 * @return array 897 */ 898 protected function getSupportedMacros(array $inputs) { 899 $interface = $this->getHostInterface(['interfaceid' => $inputs['interfaceid']]); 900 901 $macros = [ 902 'host' => [ 903 '{HOSTNAME}' => $this->host['host'], 904 '{HOST.HOST}' => $this->host['host'], 905 '{HOST.NAME}' => $this->host['name'] 906 ], 907 'interface' => [ 908 '{HOST.IP}' => $interface['ip'], 909 '{IPADDRESS}' => $interface['ip'], 910 '{HOST.DNS}' => $interface['dns'], 911 '{HOST.CONN}' => $interface['address'], 912 '{HOST.PORT}' => $interface['port'] 913 ], 914 'item' => [ 915 '{ITEM.ID}' => (array_key_exists('itemid', $inputs) && $inputs['itemid']) 916 ? $inputs['itemid'] 917 : UNRESOLVED_MACRO_STRING, 918 '{ITEM.KEY}' => array_key_exists('key', $inputs) ? $inputs['key'] : UNRESOLVED_MACRO_STRING, 919 '{ITEM.KEY.ORIG}' => array_key_exists('key', $inputs) ? $inputs['key'] : UNRESOLVED_MACRO_STRING 920 ] 921 ]; 922 923 if (array_key_exists('key', $inputs) && strstr($inputs['key'], '{') !== false) { 924 $usermacros = CMacrosResolverHelper::extractItemTestMacros([ 925 'steps' => [], 926 'delay' => '', 927 'supported_macros' => array_diff_key($this->macros_by_item_props['key'], 928 ['support_user_macros' => true, 'support_lld_macros' => true] 929 ), 930 'support_lldmacros' => ($this->preproc_item instanceof CItemPrototype), 931 'texts_support_macros' => [$inputs['key']], 932 'texts_support_lld_macros' => [$inputs['key']], 933 'texts_support_user_macros' => [$inputs['key']], 934 'hostid' => $this->host ? $this->host['hostid'] : 0, 935 'macros_values' => array_intersect_key($macros, $this->macros_by_item_props['key']) 936 ]); 937 938 foreach ($usermacros['macros'] as $macro => $value) { 939 $macros['item']['{ITEM.KEY}'] = str_replace($macro, $value, $macros['item']['{ITEM.KEY}']); 940 } 941 } 942 943 return $macros; 944 } 945 946 /** 947 * Transform front-end familiar array of http query fields to the form server is capable to handle. 948 * 949 * @param array $data 950 * @param array $data[name] Indexed array of names. 951 * @param array $data[value] Indexed array of values. 952 * 953 * @return string 954 */ 955 protected function transformQueryFields(array $data) { 956 $result = []; 957 958 if (array_key_exists('name', $data) && array_key_exists('value', $data)) { 959 foreach (array_keys($data['name']) as $num) { 960 if (array_key_exists($num, $data['value']) && $data['name'][$num] !== '') { 961 $result[] = [$data['name'][$num] => $data['value'][$num]]; 962 } 963 } 964 } 965 966 return json_encode($result); 967 } 968 969 /** 970 * Transform front-end familiar array of parameters fields to the form server is capable to handle. Server expects 971 * one object where parameter names are keys and parameter values are values. Note that parameter names are unique. 972 * 973 * @param array $data 974 * @param array $data[name] Indexed array of names. 975 * @param array $data[value] Indexed array of values. 976 * 977 * @return array 978 */ 979 protected function transformParametersFields(array $data): array { 980 $result = []; 981 982 if (array_key_exists('name', $data) && array_key_exists('value', $data)) { 983 foreach (array_keys($data['name']) as $num) { 984 if (array_key_exists($num, $data['value']) && $data['name'][$num] !== '') { 985 $result += [$data['name'][$num] => $data['value'][$num]]; 986 } 987 } 988 } 989 990 return $result; 991 } 992 993 /** 994 * Transform front-end familiar array of http header fields to the form server is capable to handle. 995 * 996 * @param array $data 997 * @param array $data[name] Indexed array of names. 998 * @param array $data[value] Indexed array of values. 999 * 1000 * @return string 1001 */ 1002 protected function transformHeaderFields(array $data) { 1003 $result = []; 1004 1005 if (array_key_exists('name', $data) && array_key_exists('value', $data)) { 1006 foreach (array_keys($data['name']) as $num) { 1007 if (array_key_exists($num, $data['value']) && $data['name'][$num] !== '') { 1008 $result[] = $data['name'][$num].': '.$data['value'][$num]; 1009 } 1010 } 1011 } 1012 1013 return implode("\r\n", $result); 1014 } 1015 1016 /** 1017 * Resolve macros used in preprocessing step parameter fields. 1018 * 1019 * @param array $steps Steps from item test input form. 1020 * 1021 * @return array 1022 */ 1023 protected function resolvePreprocessingStepMacros(array $steps) { 1024 // Resolve macros used in parameter fields. 1025 $macros_posted = $this->getInput('macros', []); 1026 $macros_types = ($this->preproc_item instanceof CItemPrototype) 1027 ? ['usermacros' => true, 'lldmacros' => true] 1028 : ['usermacros' => true]; 1029 1030 foreach ($steps as &$step) { 1031 /* 1032 * Values received from user input form may be transformed so we must remove redundant "\r" before 1033 * sending data to Zabbix server. 1034 */ 1035 $step['params'] = str_replace("\r\n", "\n", $step['params']); 1036 1037 // Resolve macros in parameter fields before send data to Zabbix server. 1038 foreach (['params', 'error_handler_params'] as $field) { 1039 $matched_macros = (new CMacrosResolverGeneral)->getMacroPositions($step[$field], $macros_types); 1040 1041 foreach (array_reverse($matched_macros, true) as $pos => $macro) { 1042 $macro_value = array_key_exists($macro, $macros_posted) 1043 ? $macros_posted[$macro] 1044 : ''; 1045 1046 $step[$field] = substr_replace($step[$field], $macro_value, $pos, strlen($macro)); 1047 } 1048 } 1049 } 1050 unset($step); 1051 1052 return $steps; 1053 } 1054 1055 /** 1056 * Resolve macros used in the calculates item formula. 1057 * 1058 * @param string $formula Calculated item formula. 1059 * 1060 * @return array 1061 */ 1062 private function resolveCalcFormulaMacros(string $formula) { 1063 $macros_posted = $this->getInput('macros', []); 1064 1065 if (!$macros_posted) { 1066 return $formula; 1067 } 1068 1069 $expression_parser = new CExpressionParser([ 1070 'usermacros' => true, 1071 'lldmacros' => ($this->preproc_item instanceof CItemPrototype), 1072 'calculated' => true, 1073 'host_macro' => true, 1074 'empty_host' => true 1075 ]); 1076 1077 if ($expression_parser->parse($formula) != CParser::PARSE_SUCCESS) { 1078 // Cannot parse a calculated item formula. Return as is. 1079 return $formula; 1080 } 1081 1082 $expression = []; 1083 $pos_left = 0; 1084 1085 $tokens = $expression_parser->getResult()->getTokensOfTypes([ 1086 CExpressionParserResult::TOKEN_TYPE_USER_MACRO, 1087 CExpressionParserResult::TOKEN_TYPE_LLD_MACRO, 1088 CExpressionParserResult::TOKEN_TYPE_STRING, 1089 CExpressionParserResult::TOKEN_TYPE_HIST_FUNCTION 1090 ]); 1091 foreach ($tokens as $token) { 1092 switch ($token['type']) { 1093 case CExpressionParserResult::TOKEN_TYPE_USER_MACRO: 1094 case CExpressionParserResult::TOKEN_TYPE_LLD_MACRO: 1095 if ($pos_left != $token['pos']) { 1096 $expression[] = substr($formula, $pos_left, $token['pos'] - $pos_left); 1097 } 1098 $pos_left = $token['pos'] + $token['length']; 1099 1100 $expression[] = array_key_exists($token['match'], $macros_posted) 1101 ? CExpressionParser::quoteString($macros_posted[$token['match']], false) 1102 : $token['match']; 1103 break; 1104 1105 case CExpressionParserResult::TOKEN_TYPE_STRING: 1106 if ($pos_left != $token['pos']) { 1107 $expression[] = substr($formula, $pos_left, $token['pos'] - $pos_left); 1108 } 1109 $pos_left = $token['pos'] + $token['length']; 1110 1111 $string = strtr(CExpressionParser::unquoteString($token['match']), $macros_posted); 1112 $expression[] = CExpressionParser::quoteString($string, false, true); 1113 break; 1114 1115 case CExpressionParserResult::TOKEN_TYPE_HIST_FUNCTION: 1116 foreach ($token['data']['parameters'][0]['data']['filter']['tokens'] as $filter_token) { 1117 switch ($filter_token['type']) { 1118 case CFilterParser::TOKEN_TYPE_USER_MACRO: 1119 case CFilterParser::TOKEN_TYPE_LLD_MACRO: 1120 if ($pos_left != $filter_token['pos']) { 1121 $expression[] = substr($formula, $pos_left, $filter_token['pos'] - $pos_left); 1122 } 1123 $pos_left = $filter_token['pos'] + $filter_token['length']; 1124 1125 $string = strtr($filter_token['match'], $macros_posted); 1126 $expression[] = CFilterParser::quoteString($string); 1127 break; 1128 1129 case CFilterParser::TOKEN_TYPE_STRING: 1130 if ($pos_left != $filter_token['pos']) { 1131 $expression[] = substr($formula, $pos_left, $filter_token['pos'] - $pos_left); 1132 } 1133 $pos_left = $filter_token['pos'] + $filter_token['length']; 1134 1135 $string = strtr(CFilterParser::unquoteString($filter_token['match']), $macros_posted); 1136 $expression[] = CFilterParser::quoteString($string); 1137 break; 1138 } 1139 } 1140 break; 1141 } 1142 } 1143 1144 if ($pos_left != strlen($formula)) { 1145 $expression[] = substr($formula, $pos_left); 1146 } 1147 1148 return implode('', $expression); 1149 } 1150 1151 /** 1152 * Resolve macros used in item property fields. 1153 * 1154 * @param array $inputs Item fields potentially having supported macros. 1155 * 1156 * @return array 1157 */ 1158 protected function resolveItemPropertyMacros(array $inputs) { 1159 // Resolve macros used in parameter fields. 1160 $macros_posted = $this->getInput('macros', []); 1161 1162 foreach (array_keys($this->macros_by_item_props) as $field) { 1163 if (!array_key_exists($field, $inputs)) { 1164 continue; 1165 } 1166 1167 // Special processing for calculated item formula. 1168 if ($field === 'params_f') { 1169 $inputs[$field] = $this->resolveCalcFormulaMacros($inputs[$field], $macros_posted); 1170 continue; 1171 } 1172 1173 // Construct array of supported macros. 1174 $types = [ 1175 'usermacros' => true, 1176 'macros_n' => [] 1177 ]; 1178 1179 if ($this->preproc_item instanceof CItemPrototype) { 1180 $types += ['lldmacros' => true]; 1181 } 1182 1183 foreach (['host', 'interface', 'item'] as $type) { 1184 if (array_key_exists($type, $this->macros_by_item_props[$field])) { 1185 $types['macros_n'] = array_merge($types['macros_n'], $this->macros_by_item_props[$field][$type]); 1186 } 1187 } 1188 1189 // Get strings to resolve and types of supported macros. 1190 if ($field === 'query_fields' || $field === 'headers' || $field === 'parameters') { 1191 if (!array_key_exists($field, $inputs) || !$inputs[$field]) { 1192 continue; 1193 } 1194 1195 foreach (['name', 'value'] as $key) { 1196 foreach (array_keys($inputs[$field][$key]) as $nr) { 1197 $str = &$inputs[$field][$key][$nr]; 1198 if (strstr($str, '{') !== false) { 1199 $matched_macros = (new CMacrosResolverGeneral)->getMacroPositions($str, $types); 1200 1201 foreach (array_reverse($matched_macros, true) as $pos => $macro) { 1202 $macro_value = array_key_exists($macro, $macros_posted) 1203 ? $macros_posted[$macro] 1204 : ''; 1205 1206 $str = substr_replace($str, $macro_value, $pos, strlen($macro)); 1207 } 1208 } 1209 1210 unset($str); 1211 } 1212 } 1213 } 1214 elseif (strstr($inputs[$field], '{') !== false) { 1215 $matched_macros = (new CMacrosResolverGeneral)->getMacroPositions($inputs[$field], $types); 1216 1217 foreach (array_reverse($matched_macros, true) as $pos => $macro) { 1218 $macro_value = array_key_exists($macro, $macros_posted) 1219 ? $macros_posted[$macro] 1220 : ''; 1221 1222 if ($inputs['type'] == ITEM_TYPE_HTTPAGENT && $field === 'posts') { 1223 if ($inputs['post_type'] == ZBX_POSTTYPE_JSON && !is_numeric($macro_value)) { 1224 $macro_value = json_encode($macro_value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); 1225 // Remove " wrapping. 1226 $macro_value = substr($macro_value, 1, -1); 1227 } 1228 elseif ($inputs['post_type'] == ZBX_POSTTYPE_XML) { 1229 $macro_value = htmlentities($macro_value); 1230 } 1231 } 1232 1233 $inputs[$field] = substr_replace($inputs[$field], $macro_value, $pos, strlen($macro)); 1234 } 1235 } 1236 } 1237 1238 // Resolve interface details (SNMP) macros separately. 1239 if (array_key_exists('interface', $inputs) && array_key_exists('details', $inputs['interface'])) { 1240 foreach ($inputs['interface']['details'] as &$field) { 1241 if (strstr($field, '{') !== false) { 1242 $matched_macros = (new CMacrosResolverGeneral)->getMacroPositions($field, ['usermacros' => true]); 1243 1244 foreach (array_reverse($matched_macros, true) as $pos => $macro) { 1245 $macro_value = array_key_exists($macro, $macros_posted) 1246 ? $macros_posted[$macro] 1247 : ''; 1248 1249 $field = substr_replace($field, $macro_value, $pos, strlen($macro)); 1250 } 1251 } 1252 } 1253 unset($field); 1254 } 1255 1256 return $inputs; 1257 } 1258 1259 /** 1260 * Get single input parameter. Converts value fields to specified newline. 1261 * 1262 * @return var 1263 */ 1264 public function getInput($var, $default = null) { 1265 $value = parent::getInput($var, $default); 1266 if ($var === 'value' || $var === 'prev_value') { 1267 $value = str_replace("\r\n", "\n", $value); 1268 1269 if ($this->eol == ZBX_EOL_CRLF) { 1270 $value = str_replace("\n", "\r\n", $value); 1271 } 1272 } 1273 1274 return $value; 1275 } 1276 1277 1278 /** 1279 * Validates interface object in context of current item type. 1280 * 1281 * @param array $interface 1282 * @param string $interface['address'] (optional) 1283 * @param string $interface['port'] (optional) 1284 * @param array $interface['details'] (optional) 1285 * @param int $interface['details']['version'] 1286 * @param string $interface['details']['community'] (optional) 1287 * 1288 * @return bool 1289 */ 1290 final protected function validateInterface(array $interface): bool { 1291 if ($this->item_type == ITEM_TYPE_SNMP) { 1292 if (($interface['details']['version'] == SNMP_V1 || $interface['details']['version'] == SNMP_V2C) 1293 && (!array_key_exists('community', $interface['details']) 1294 || $interface['details']['community'] === '')) { 1295 error(_s('Incorrect value for field "%1$s": %2$s.', _('SNMP community'), _('cannot be empty'))); 1296 1297 return false; 1298 } 1299 } 1300 1301 if ($this->items_require_interface[$this->item_type]['address'] 1302 && (!array_key_exists('address', $interface) || $interface['address'] === '')) { 1303 error(_s('Incorrect value for field "%1$s": %2$s.', _('Host address'), _('cannot be empty'))); 1304 1305 return false; 1306 } 1307 1308 if ($this->items_require_interface[$this->item_type]['port'] 1309 && (!array_key_exists('port', $interface) || $interface['port'] === '')) { 1310 error(_s('Incorrect value for field "%1$s": %2$s.', _('Port'), _('cannot be empty'))); 1311 1312 return false; 1313 } 1314 1315 return true; 1316 } 1317} 1318