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 containing methods for operations with items. 24 */ 25class CItem extends CItemGeneral { 26 27 protected $tableName = 'items'; 28 protected $tableAlias = 'i'; 29 protected $sortColumns = ['itemid', 'name', 'key_', 'delay', 'history', 'trends', 'type', 'status']; 30 31 /** 32 * Define a set of supported pre-processing rules. 33 * 34 * @var array 35 */ 36 const SUPPORTED_PREPROCESSING_TYPES = [ZBX_PREPROC_REGSUB, ZBX_PREPROC_TRIM, ZBX_PREPROC_RTRIM, 37 ZBX_PREPROC_LTRIM, ZBX_PREPROC_XPATH, ZBX_PREPROC_JSONPATH, ZBX_PREPROC_MULTIPLIER, ZBX_PREPROC_DELTA_VALUE, 38 ZBX_PREPROC_DELTA_SPEED, ZBX_PREPROC_BOOL2DEC, ZBX_PREPROC_OCT2DEC, ZBX_PREPROC_HEX2DEC, 39 ZBX_PREPROC_VALIDATE_RANGE, ZBX_PREPROC_VALIDATE_REGEX, ZBX_PREPROC_VALIDATE_NOT_REGEX, 40 ZBX_PREPROC_ERROR_FIELD_JSON, ZBX_PREPROC_ERROR_FIELD_XML, ZBX_PREPROC_ERROR_FIELD_REGEX, 41 ZBX_PREPROC_THROTTLE_VALUE, ZBX_PREPROC_THROTTLE_TIMED_VALUE, ZBX_PREPROC_SCRIPT, 42 ZBX_PREPROC_PROMETHEUS_PATTERN, ZBX_PREPROC_PROMETHEUS_TO_JSON, ZBX_PREPROC_CSV_TO_JSON, 43 ZBX_PREPROC_STR_REPLACE, ZBX_PREPROC_VALIDATE_NOT_SUPPORTED, ZBX_PREPROC_XML_TO_JSON 44 ]; 45 46 /** 47 * Define a set of supported item types. 48 * 49 * @var array 50 */ 51 const SUPPORTED_ITEM_TYPES = [ITEM_TYPE_ZABBIX, ITEM_TYPE_TRAPPER, ITEM_TYPE_SIMPLE, ITEM_TYPE_INTERNAL, 52 ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_EXTERNAL, ITEM_TYPE_DB_MONITOR, ITEM_TYPE_IPMI, ITEM_TYPE_SSH, 53 ITEM_TYPE_TELNET, ITEM_TYPE_CALCULATED, ITEM_TYPE_JMX, ITEM_TYPE_SNMPTRAP, ITEM_TYPE_DEPENDENT, 54 ITEM_TYPE_HTTPAGENT, ITEM_TYPE_SNMP, ITEM_TYPE_SCRIPT 55 ]; 56 57 public function __construct() { 58 parent::__construct(); 59 60 $this->errorMessages = array_merge($this->errorMessages, [ 61 self::ERROR_EXISTS_TEMPLATE => _('Item "%1$s" already exists on "%2$s", inherited from another template.'), 62 self::ERROR_EXISTS => _('Item "%1$s" already exists on "%2$s".'), 63 self::ERROR_INVALID_KEY => _('Invalid key "%1$s" for item "%2$s" on "%3$s": %4$s.') 64 ]); 65 } 66 67 /** 68 * Get items data. 69 * 70 * @param array $options 71 * @param array $options['itemids'] 72 * @param array $options['hostids'] 73 * @param array $options['groupids'] 74 * @param array $options['triggerids'] 75 * @param bool $options['status'] 76 * @param bool $options['templated_items'] 77 * @param bool $options['editable'] 78 * @param bool $options['count'] 79 * @param string $options['pattern'] 80 * @param int $options['limit'] 81 * @param string $options['order'] 82 * 83 * @return array|int item data as array or false if error 84 */ 85 public function get($options = []) { 86 $result = []; 87 88 $sqlParts = [ 89 'select' => ['items' => 'i.itemid'], 90 'from' => ['items' => 'items i'], 91 'where' => ['webtype' => 'i.type<>'.ITEM_TYPE_HTTPTEST, 'flags' => 'i.flags IN ('.ZBX_FLAG_DISCOVERY_NORMAL.','.ZBX_FLAG_DISCOVERY_CREATED.')'], 92 'group' => [], 93 'order' => [], 94 'limit' => null 95 ]; 96 97 $defOptions = [ 98 'groupids' => null, 99 'templateids' => null, 100 'hostids' => null, 101 'proxyids' => null, 102 'itemids' => null, 103 'interfaceids' => null, 104 'graphids' => null, 105 'triggerids' => null, 106 'webitems' => null, 107 'inherited' => null, 108 'templated' => null, 109 'monitored' => null, 110 'editable' => false, 111 'nopermissions' => null, 112 'group' => null, 113 'host' => null, 114 'with_triggers' => null, 115 'evaltype' => TAG_EVAL_TYPE_AND_OR, 116 'tags' => null, 117 // filter 118 'filter' => null, 119 'search' => null, 120 'searchByAny' => null, 121 'startSearch' => false, 122 'excludeSearch' => false, 123 'searchWildcardsEnabled' => null, 124 // output 125 'output' => API_OUTPUT_EXTEND, 126 'selectHosts' => null, 127 'selectInterfaces' => null, 128 'selectTags' => null, 129 'selectTriggers' => null, 130 'selectGraphs' => null, 131 'selectDiscoveryRule' => null, 132 'selectItemDiscovery' => null, 133 'selectPreprocessing' => null, 134 'selectValueMap' => null, 135 'countOutput' => false, 136 'groupCount' => false, 137 'preservekeys' => false, 138 'sortfield' => '', 139 'sortorder' => '', 140 'limit' => null, 141 'limitSelects' => null 142 ]; 143 $options = zbx_array_merge($defOptions, $options); 144 $this->validateGet($options); 145 146 // editable + permission check 147 if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN && !$options['nopermissions']) { 148 $permission = $options['editable'] ? PERM_READ_WRITE : PERM_READ; 149 $userGroups = getUserGroupsByUserId(self::$userData['userid']); 150 151 $sqlParts['where'][] = 'EXISTS ('. 152 'SELECT NULL'. 153 ' FROM hosts_groups hgg'. 154 ' JOIN rights r'. 155 ' ON r.id=hgg.groupid'. 156 ' AND '.dbConditionInt('r.groupid', $userGroups). 157 ' WHERE i.hostid=hgg.hostid'. 158 ' GROUP BY hgg.hostid'. 159 ' HAVING MIN(r.permission)>'.PERM_DENY. 160 ' AND MAX(r.permission)>='.zbx_dbstr($permission). 161 ')'; 162 } 163 164 // itemids 165 if (!is_null($options['itemids'])) { 166 zbx_value2array($options['itemids']); 167 168 $sqlParts['where']['itemid'] = dbConditionInt('i.itemid', $options['itemids']); 169 } 170 171 // templateids 172 if (!is_null($options['templateids'])) { 173 zbx_value2array($options['templateids']); 174 175 if (!is_null($options['hostids'])) { 176 zbx_value2array($options['hostids']); 177 $options['hostids'] = array_merge($options['hostids'], $options['templateids']); 178 } 179 else { 180 $options['hostids'] = $options['templateids']; 181 } 182 } 183 184 // hostids 185 if (!is_null($options['hostids'])) { 186 zbx_value2array($options['hostids']); 187 188 $sqlParts['where']['hostid'] = dbConditionInt('i.hostid', $options['hostids']); 189 190 if ($options['groupCount']) { 191 $sqlParts['group']['i'] = 'i.hostid'; 192 } 193 } 194 195 // interfaceids 196 if (!is_null($options['interfaceids'])) { 197 zbx_value2array($options['interfaceids']); 198 199 $sqlParts['where']['interfaceid'] = dbConditionId('i.interfaceid', $options['interfaceids']); 200 201 if ($options['groupCount']) { 202 $sqlParts['group']['i'] = 'i.interfaceid'; 203 } 204 } 205 206 // groupids 207 if (!is_null($options['groupids'])) { 208 zbx_value2array($options['groupids']); 209 210 $sqlParts['from']['hosts_groups'] = 'hosts_groups hg'; 211 $sqlParts['where'][] = dbConditionInt('hg.groupid', $options['groupids']); 212 $sqlParts['where'][] = 'hg.hostid=i.hostid'; 213 214 if ($options['groupCount']) { 215 $sqlParts['group']['hg'] = 'hg.groupid'; 216 } 217 } 218 219 // proxyids 220 if (!is_null($options['proxyids'])) { 221 zbx_value2array($options['proxyids']); 222 223 $sqlParts['from']['hosts'] = 'hosts h'; 224 $sqlParts['where'][] = dbConditionId('h.proxy_hostid', $options['proxyids']); 225 $sqlParts['where'][] = 'h.hostid=i.hostid'; 226 227 if ($options['groupCount']) { 228 $sqlParts['group']['h'] = 'h.proxy_hostid'; 229 } 230 } 231 232 // triggerids 233 if (!is_null($options['triggerids'])) { 234 zbx_value2array($options['triggerids']); 235 236 $sqlParts['from']['functions'] = 'functions f'; 237 $sqlParts['where'][] = dbConditionInt('f.triggerid', $options['triggerids']); 238 $sqlParts['where']['if'] = 'i.itemid=f.itemid'; 239 } 240 241 // tags 242 if ($options['tags'] !== null && $options['tags']) { 243 $sqlParts['where'][] = CApiTagHelper::addWhereCondition($options['tags'], $options['evaltype'], 'i', 244 'item_tag', 'itemid' 245 ); 246 } 247 248 // graphids 249 if (!is_null($options['graphids'])) { 250 zbx_value2array($options['graphids']); 251 252 $sqlParts['from']['graphs_items'] = 'graphs_items gi'; 253 $sqlParts['where'][] = dbConditionInt('gi.graphid', $options['graphids']); 254 $sqlParts['where']['igi'] = 'i.itemid=gi.itemid'; 255 } 256 257 // webitems 258 if (!is_null($options['webitems'])) { 259 unset($sqlParts['where']['webtype']); 260 } 261 262 // inherited 263 if (!is_null($options['inherited'])) { 264 if ($options['inherited']) { 265 $sqlParts['where'][] = 'i.templateid IS NOT NULL'; 266 } 267 else { 268 $sqlParts['where'][] = 'i.templateid IS NULL'; 269 } 270 } 271 272 // templated 273 if (!is_null($options['templated'])) { 274 $sqlParts['from']['hosts'] = 'hosts h'; 275 $sqlParts['where']['hi'] = 'h.hostid=i.hostid'; 276 277 if ($options['templated']) { 278 $sqlParts['where'][] = 'h.status='.HOST_STATUS_TEMPLATE; 279 } 280 else { 281 $sqlParts['where'][] = 'h.status<>'.HOST_STATUS_TEMPLATE; 282 } 283 } 284 285 // monitored 286 if (!is_null($options['monitored'])) { 287 $sqlParts['from']['hosts'] = 'hosts h'; 288 $sqlParts['where']['hi'] = 'h.hostid=i.hostid'; 289 290 if ($options['monitored']) { 291 $sqlParts['where'][] = 'h.status='.HOST_STATUS_MONITORED; 292 $sqlParts['where'][] = 'i.status='.ITEM_STATUS_ACTIVE; 293 } 294 else { 295 $sqlParts['where'][] = '(h.status<>'.HOST_STATUS_MONITORED.' OR i.status<>'.ITEM_STATUS_ACTIVE.')'; 296 } 297 } 298 299 // search 300 if (is_array($options['search'])) { 301 if (array_key_exists('error', $options['search']) && $options['search']['error'] !== null) { 302 zbx_db_search('item_rtdata ir', ['search' => ['error' => $options['search']['error']]] + $options, 303 $sqlParts 304 ); 305 } 306 307 zbx_db_search('items i', $options, $sqlParts); 308 } 309 310 // filter 311 if (is_array($options['filter'])) { 312 if (array_key_exists('delay', $options['filter']) && $options['filter']['delay'] !== null) { 313 $sqlParts['where'][] = makeUpdateIntervalFilter('i.delay', $options['filter']['delay']); 314 unset($options['filter']['delay']); 315 } 316 317 if (array_key_exists('history', $options['filter']) && $options['filter']['history'] !== null) { 318 $options['filter']['history'] = getTimeUnitFilters($options['filter']['history']); 319 } 320 321 if (array_key_exists('trends', $options['filter']) && $options['filter']['trends'] !== null) { 322 $options['filter']['trends'] = getTimeUnitFilters($options['filter']['trends']); 323 } 324 325 if (array_key_exists('state', $options['filter']) && $options['filter']['state'] !== null) { 326 $this->dbFilter('item_rtdata ir', ['filter' => ['state' => $options['filter']['state']]] + $options, 327 $sqlParts 328 ); 329 } 330 331 $this->dbFilter('items i', $options, $sqlParts); 332 333 if (isset($options['filter']['host'])) { 334 zbx_value2array($options['filter']['host']); 335 336 $sqlParts['from']['hosts'] = 'hosts h'; 337 $sqlParts['where']['hi'] = 'h.hostid=i.hostid'; 338 $sqlParts['where']['h'] = dbConditionString('h.host', $options['filter']['host'], false, true); 339 } 340 341 if (array_key_exists('flags', $options['filter']) 342 && (is_null($options['filter']['flags']) || !zbx_empty($options['filter']['flags']))) { 343 unset($sqlParts['where']['flags']); 344 } 345 } 346 347 // group 348 if (!is_null($options['group'])) { 349 $sqlParts['from']['hstgrp'] = 'hstgrp g'; 350 $sqlParts['from']['hosts_groups'] = 'hosts_groups hg'; 351 $sqlParts['where']['ghg'] = 'g.groupid=hg.groupid'; 352 $sqlParts['where']['hgi'] = 'hg.hostid=i.hostid'; 353 $sqlParts['where'][] = ' g.name='.zbx_dbstr($options['group']); 354 } 355 356 // host 357 if (!is_null($options['host'])) { 358 $sqlParts['from']['hosts'] = 'hosts h'; 359 $sqlParts['where']['hi'] = 'h.hostid=i.hostid'; 360 $sqlParts['where'][] = ' h.host='.zbx_dbstr($options['host']); 361 } 362 363 // with_triggers 364 if (!is_null($options['with_triggers'])) { 365 if ($options['with_triggers'] == 1) { 366 $sqlParts['where'][] = 'EXISTS ('. 367 'SELECT NULL'. 368 ' FROM functions ff,triggers t'. 369 ' WHERE i.itemid=ff.itemid'. 370 ' AND ff.triggerid=t.triggerid'. 371 ' AND t.flags IN ('.ZBX_FLAG_DISCOVERY_NORMAL.','.ZBX_FLAG_DISCOVERY_CREATED.')'. 372 ')'; 373 } 374 else { 375 $sqlParts['where'][] = 'NOT EXISTS ('. 376 'SELECT NULL'. 377 ' FROM functions ff,triggers t'. 378 ' WHERE i.itemid=ff.itemid'. 379 ' AND ff.triggerid=t.triggerid'. 380 ' AND t.flags IN ('.ZBX_FLAG_DISCOVERY_NORMAL.','.ZBX_FLAG_DISCOVERY_CREATED.')'. 381 ')'; 382 } 383 } 384 385 // limit 386 if (zbx_ctype_digit($options['limit']) && $options['limit']) { 387 $sqlParts['limit'] = $options['limit']; 388 } 389 390 $sqlParts = $this->applyQueryOutputOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts); 391 $sqlParts = $this->applyQuerySortOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts); 392 $res = DBselect(self::createSelectQueryFromParts($sqlParts), $sqlParts['limit']); 393 while ($item = DBfetch($res)) { 394 // Items share table with item prototypes. Therefore remove item unrelated fields. 395 unset($item['discover']); 396 397 if (!$options['countOutput']) { 398 $result[$item['itemid']] = $item; 399 continue; 400 } 401 402 if ($options['groupCount']) { 403 $result[] = $item; 404 } 405 else { 406 $result = $item['rowscount']; 407 } 408 } 409 410 if ($options['countOutput']) { 411 return $result; 412 } 413 414 if ($result) { 415 if (self::dbDistinct($sqlParts)) { 416 $result = $this->addNclobFieldValues($options, $result); 417 } 418 419 $result = $this->addRelatedObjects($options, $result); 420 $result = $this->unsetExtraFields($result, ['hostid', 'interfaceid', 'value_type', 'valuemapid'], 421 $options['output'] 422 ); 423 } 424 425 // removing keys (hash -> array) 426 if (!$options['preservekeys']) { 427 $result = zbx_cleanHashes($result); 428 } 429 430 // Decode ITEM_TYPE_HTTPAGENT encoded fields. 431 foreach ($result as &$item) { 432 if (array_key_exists('query_fields', $item)) { 433 $query_fields = ($item['query_fields'] !== '') ? json_decode($item['query_fields'], true) : []; 434 $item['query_fields'] = json_last_error() ? [] : $query_fields; 435 } 436 437 if (array_key_exists('headers', $item)) { 438 $item['headers'] = $this->headersStringToArray($item['headers']); 439 } 440 } 441 unset($item); 442 443 return $result; 444 } 445 446 /** 447 * Validates the input parameters for the get() method. 448 * 449 * @param array $options 450 * 451 * @throws APIException if the input is invalid 452 */ 453 private function validateGet(array $options) { 454 // Validate input parameters. 455 $api_input_rules = ['type' => API_OBJECT, 'fields' => [ 456 'selectValueMap' => ['type' => API_OUTPUT, 'flags' => API_ALLOW_NULL, 'in' => 'valuemapid,name,mappings'], 457 'evaltype' => ['type' => API_INT32, 'in' => implode(',', [TAG_EVAL_TYPE_AND_OR, TAG_EVAL_TYPE_OR])] 458 ]]; 459 $options_filter = array_intersect_key($options, $api_input_rules['fields']); 460 if (!CApiInputValidator::validate($api_input_rules, $options_filter, '/', $error)) { 461 self::exception(ZBX_API_ERROR_PARAMETERS, $error); 462 } 463 } 464 465 /** 466 * Create item. 467 * 468 * @param $items 469 * 470 * @return array 471 */ 472 public function create($items) { 473 $items = zbx_toArray($items); 474 475 parent::checkInput($items); 476 self::validateInventoryLinks($items); 477 478 foreach ($items as &$item) { 479 $item['flags'] = ZBX_FLAG_DISCOVERY_NORMAL; 480 unset($item['itemid']); 481 } 482 unset($item); 483 484 $this->validateDependentItems($items); 485 486 foreach ($items as &$item) { 487 if ($item['type'] == ITEM_TYPE_HTTPAGENT) { 488 if (array_key_exists('query_fields', $item)) { 489 $item['query_fields'] = $item['query_fields'] ? json_encode($item['query_fields']) : ''; 490 } 491 492 if (array_key_exists('headers', $item)) { 493 $item['headers'] = $this->headersArrayToString($item['headers']); 494 } 495 496 if (array_key_exists('request_method', $item) && $item['request_method'] == HTTPCHECK_REQUEST_HEAD 497 && !array_key_exists('retrieve_mode', $item)) { 498 $item['retrieve_mode'] = HTTPTEST_STEP_RETRIEVE_MODE_HEADERS; 499 } 500 } 501 else { 502 $item['query_fields'] = ''; 503 $item['headers'] = ''; 504 } 505 } 506 unset($item); 507 508 // Get only hosts not templates from items 509 $hosts = API::Host()->get([ 510 'output' => [], 511 'hostids' => zbx_objectValues($items, 'hostid'), 512 'preservekeys' => true 513 ]); 514 foreach ($items as &$item) { 515 if (array_key_exists($item['hostid'], $hosts)) { 516 $item['rtdata'] = true; 517 } 518 } 519 unset($item); 520 521 $this->createReal($items); 522 $this->inherit($items); 523 524 return ['itemids' => zbx_objectValues($items, 'itemid')]; 525 } 526 527 /** 528 * Create host item. 529 * 530 * @param array $items 531 */ 532 protected function createReal(array &$items) { 533 $items_rtdata = []; 534 535 foreach ($items as $key => &$item) { 536 if ($item['type'] != ITEM_TYPE_DEPENDENT) { 537 $item['master_itemid'] = null; 538 } 539 540 if (array_key_exists('rtdata', $item)) { 541 $items_rtdata[$key] = []; 542 unset($item['rtdata']); 543 } 544 } 545 unset($item); 546 547 $itemids = DB::insert('items', $items); 548 549 foreach ($items_rtdata as $key => &$value) { 550 $value['itemid'] = $itemids[$key]; 551 } 552 unset($value); 553 554 DB::insert('item_rtdata', $items_rtdata, false); 555 556 foreach ($items as $key => $item) { 557 $items[$key]['itemid'] = $itemids[$key]; 558 } 559 560 $this->createItemParameters($items, $itemids); 561 $this->createItemPreprocessing($items); 562 $this->createItemTags($items, $itemids); 563 } 564 565 /** 566 * Update host items. 567 * 568 * @param array $items 569 */ 570 protected function updateReal(array $items) { 571 CArrayHelper::sort($items, ['itemid']); 572 573 $data = []; 574 foreach ($items as $item) { 575 unset($item['flags']); // flags cannot be changed 576 $data[] = ['values' => $item, 'where' => ['itemid' => $item['itemid']]]; 577 } 578 DB::update('items', $data); 579 580 $this->updateItemParameters($items); 581 $this->updateItemPreprocessing($items); 582 $this->updateItemTags($items); 583 } 584 585 /** 586 * Update item. 587 * 588 * @param array $items 589 * 590 * @return array 591 */ 592 public function update($items) { 593 $items = zbx_toArray($items); 594 595 parent::checkInput($items, true); 596 self::validateInventoryLinks($items, true); 597 598 $db_items = $this->get([ 599 'output' => ['flags', 'type', 'master_itemid', 'authtype', 'allow_traps', 'retrieve_mode', 'value_type'], 600 'itemids' => zbx_objectValues($items, 'itemid'), 601 'editable' => true, 602 'preservekeys' => true 603 ]); 604 605 $items = $this->extendFromObjects(zbx_toHash($items, 'itemid'), $db_items, ['flags', 'type', 'authtype', 606 'master_itemid', 'value_type' 607 ]); 608 609 $this->validateDependentItems($items); 610 611 $defaults = DB::getDefaults('items'); 612 $clean = [ 613 ITEM_TYPE_HTTPAGENT => [ 614 'url' => '', 615 'query_fields' => '', 616 'timeout' => $defaults['timeout'], 617 'status_codes' => $defaults['status_codes'], 618 'follow_redirects' => $defaults['follow_redirects'], 619 'request_method' => $defaults['request_method'], 620 'allow_traps' => $defaults['allow_traps'], 621 'post_type' => $defaults['post_type'], 622 'http_proxy' => '', 623 'headers' => '', 624 'retrieve_mode' => $defaults['retrieve_mode'], 625 'output_format' => $defaults['output_format'], 626 'ssl_key_password' => '', 627 'verify_peer' => $defaults['verify_peer'], 628 'verify_host' => $defaults['verify_host'], 629 'ssl_cert_file' => '', 630 'ssl_key_file' => '', 631 'posts' => '' 632 ] 633 ]; 634 635 foreach ($items as &$item) { 636 $type_change = ($item['type'] != $db_items[$item['itemid']]['type']); 637 638 if ($item['type'] != ITEM_TYPE_DEPENDENT && $db_items[$item['itemid']]['master_itemid'] != 0) { 639 $item['master_itemid'] = 0; 640 } 641 642 if ($type_change && $db_items[$item['itemid']]['type'] == ITEM_TYPE_HTTPAGENT) { 643 $item = array_merge($item, $clean[ITEM_TYPE_HTTPAGENT]); 644 645 if ($item['type'] != ITEM_TYPE_SSH) { 646 $item['authtype'] = $defaults['authtype']; 647 $item['username'] = ''; 648 $item['password'] = ''; 649 } 650 651 if ($item['type'] != ITEM_TYPE_TRAPPER) { 652 $item['trapper_hosts'] = ''; 653 } 654 } 655 656 if ($item['type'] == ITEM_TYPE_HTTPAGENT) { 657 // Clean username and password when authtype is set to HTTPTEST_AUTH_NONE. 658 if ($item['authtype'] == HTTPTEST_AUTH_NONE) { 659 $item['username'] = ''; 660 $item['password'] = ''; 661 } 662 663 if (array_key_exists('allow_traps', $item) && $item['allow_traps'] == HTTPCHECK_ALLOW_TRAPS_OFF 664 && $item['allow_traps'] != $db_items[$item['itemid']]['allow_traps']) { 665 $item['trapper_hosts'] = ''; 666 } 667 668 if (array_key_exists('query_fields', $item) && is_array($item['query_fields'])) { 669 $item['query_fields'] = $item['query_fields'] ? json_encode($item['query_fields']) : ''; 670 } 671 672 if (array_key_exists('headers', $item) && is_array($item['headers'])) { 673 $item['headers'] = $this->headersArrayToString($item['headers']); 674 } 675 676 if (array_key_exists('request_method', $item) && $item['request_method'] == HTTPCHECK_REQUEST_HEAD 677 && !array_key_exists('retrieve_mode', $item) 678 && $db_items[$item['itemid']]['retrieve_mode'] != HTTPTEST_STEP_RETRIEVE_MODE_HEADERS) { 679 $item['retrieve_mode'] = HTTPTEST_STEP_RETRIEVE_MODE_HEADERS; 680 } 681 } 682 else { 683 $item['query_fields'] = ''; 684 $item['headers'] = ''; 685 } 686 687 if ($type_change && $db_items[$item['itemid']]['type'] == ITEM_TYPE_SCRIPT) { 688 if ($item['type'] != ITEM_TYPE_SSH && $item['type'] != ITEM_TYPE_DB_MONITOR 689 && $item['type'] != ITEM_TYPE_TELNET && $item['type'] != ITEM_TYPE_CALCULATED) { 690 $item['params'] = ''; 691 } 692 693 if ($item['type'] != ITEM_TYPE_HTTPAGENT) { 694 $item['timeout'] = $defaults['timeout']; 695 } 696 } 697 698 if ($item['value_type'] == ITEM_VALUE_TYPE_LOG || $item['value_type'] == ITEM_VALUE_TYPE_TEXT) { 699 if ($item['value_type'] != $db_items[$item['itemid']]['value_type']) { 700 // Reset valuemapid when value_type is LOG or TEXT. 701 $item['valuemapid'] = 0; 702 } 703 else { 704 unset($item['valuemapid']); 705 } 706 } 707 708 if (array_key_exists('tags', $item)) { 709 $item['tags'] = array_map(function ($tag) { 710 return $tag + ['value' => '']; 711 }, $item['tags']); 712 } 713 } 714 unset($item); 715 716 $this->updateReal($items); 717 $this->inherit($items); 718 719 return ['itemids' => zbx_objectValues($items, 'itemid')]; 720 } 721 722 /** 723 * Delete items. 724 * 725 * @param array $itemids 726 * 727 * @return array 728 */ 729 public function delete(array $itemids) { 730 $this->validateDelete($itemids, $db_items); 731 732 CItemManager::delete($itemids); 733 734 $this->addAuditBulk(AUDIT_ACTION_DELETE, AUDIT_RESOURCE_ITEM, $db_items); 735 736 return ['itemids' => $itemids]; 737 } 738 739 /** 740 * Validates the input parameters for the delete() method. 741 * 742 * @param array $itemids [IN/OUT] 743 * @param array $db_items [OUT] 744 * 745 * @throws APIException if the input is invalid. 746 */ 747 private function validateDelete(array &$itemids, array &$db_items = null) { 748 $api_input_rules = ['type' => API_IDS, 'flags' => API_NOT_EMPTY, 'uniq' => true]; 749 if (!CApiInputValidator::validate($api_input_rules, $itemids, '/', $error)) { 750 self::exception(ZBX_API_ERROR_PARAMETERS, $error); 751 } 752 753 $db_items = $this->get([ 754 'output' => ['itemid', 'name', 'templateid', 'flags'], 755 'itemids' => $itemids, 756 'editable' => true, 757 'preservekeys' => true 758 ]); 759 760 foreach ($itemids as $itemid) { 761 if (!array_key_exists($itemid, $db_items)) { 762 self::exception(ZBX_API_ERROR_PERMISSIONS, 763 _('No permissions to referred object or it does not exist!') 764 ); 765 } 766 767 $db_item = $db_items[$itemid]; 768 769 if ($db_item['templateid'] != 0) { 770 self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot delete templated item.')); 771 } 772 } 773 } 774 775 public function syncTemplates($data) { 776 $data['templateids'] = zbx_toArray($data['templateids']); 777 $data['hostids'] = zbx_toArray($data['hostids']); 778 779 $output = []; 780 foreach ($this->fieldRules as $field_name => $rules) { 781 if (!array_key_exists('system', $rules) && !array_key_exists('host', $rules)) { 782 $output[] = $field_name; 783 } 784 } 785 786 $tpl_items = $this->get([ 787 'output' => $output, 788 'selectPreprocessing' => ['type', 'params', 'error_handler', 'error_handler_params'], 789 'selectTags' => ['tag', 'value'], 790 'hostids' => $data['templateids'], 791 'filter' => ['flags' => ZBX_FLAG_DISCOVERY_NORMAL], 792 'preservekeys' => true 793 ]); 794 795 foreach ($tpl_items as &$tpl_item) { 796 if ($tpl_item['type'] == ITEM_TYPE_HTTPAGENT) { 797 if (array_key_exists('query_fields', $tpl_item) && is_array($tpl_item['query_fields'])) { 798 $tpl_item['query_fields'] = $tpl_item['query_fields'] 799 ? json_encode($tpl_item['query_fields']) 800 : ''; 801 } 802 803 if (array_key_exists('headers', $tpl_item) && is_array($tpl_item['headers'])) { 804 $tpl_item['headers'] = $this->headersArrayToString($tpl_item['headers']); 805 } 806 } 807 else { 808 $tpl_item['query_fields'] = ''; 809 $tpl_item['headers'] = ''; 810 } 811 } 812 unset($tpl_item); 813 814 $this->inherit($tpl_items, $data['hostids']); 815 816 return true; 817 } 818 819 /** 820 * Check item specific fields: 821 * - validate history and trends using simple interval parser and user macro parser; 822 * - validate item preprocessing. 823 * 824 * @param array $item An array of single item data. 825 * @param string $method A string of "create" or "update" method. 826 * 827 * @throws APIException if the input is invalid. 828 */ 829 protected function checkSpecificFields(array $item, $method) { 830 if (array_key_exists('history', $item) 831 && !validateTimeUnit($item['history'], SEC_PER_HOUR, 25 * SEC_PER_YEAR, true, $error, 832 ['usermacros' => true])) { 833 self::exception(ZBX_API_ERROR_PARAMETERS, 834 _s('Incorrect value for field "%1$s": %2$s.', 'history', $error) 835 ); 836 } 837 838 if (array_key_exists('trends', $item) 839 && !validateTimeUnit($item['trends'], SEC_PER_DAY, 25 * SEC_PER_YEAR, true, $error, 840 ['usermacros' => true])) { 841 self::exception(ZBX_API_ERROR_PARAMETERS, 842 _s('Incorrect value for field "%1$s": %2$s.', 'trends', $error) 843 ); 844 } 845 } 846 847 /** 848 * Check, if items that are about to be inserted or updated violate the rule: 849 * only one item can be linked to a inventory filed. 850 * If everything is ok, function return true or throws Exception otherwise 851 * 852 * @static 853 * 854 * @param array $items 855 * @param bool $update whether this is update operation 856 * 857 * @return bool 858 */ 859 public static function validateInventoryLinks(array $items, $update = false) { 860 // inventory link field is not being updated, or being updated to 0, no need to validate anything then 861 foreach ($items as $i => $item) { 862 if (!isset($item['inventory_link']) || $item['inventory_link'] == 0) { 863 unset($items[$i]); 864 } 865 } 866 867 if (zbx_empty($items)) { 868 return true; 869 } 870 871 $possibleHostInventories = getHostInventories(); 872 if ($update) { 873 // for successful validation we need three fields for each item: inventory_link, hostid and key_ 874 // problem is, that when we are updating an item, we might not have them, because they are not changed 875 // so, we need to find out what is missing and use API to get the lacking info 876 $itemsWithNoHostId = []; 877 $itemsWithNoInventoryLink = []; 878 $itemsWithNoKeys = []; 879 foreach ($items as $item) { 880 if (!isset($item['inventory_link'])) { 881 $itemsWithNoInventoryLink[$item['itemid']] = $item['itemid']; 882 } 883 if (!isset($item['hostid'])) { 884 $itemsWithNoHostId[$item['itemid']] = $item['itemid']; 885 } 886 if (!isset($item['key_'])) { 887 $itemsWithNoKeys[$item['itemid']] = $item['itemid']; 888 } 889 } 890 $itemsToFind = array_merge($itemsWithNoHostId, $itemsWithNoInventoryLink, $itemsWithNoKeys); 891 892 // are there any items with lacking info? 893 if (!zbx_empty($itemsToFind)) { 894 $missingInfo = API::Item()->get([ 895 'output' => ['hostid', 'inventory_link', 'key_'], 896 'filter' => ['itemid' => $itemsToFind], 897 'nopermissions' => true 898 ]); 899 $missingInfo = zbx_toHash($missingInfo, 'itemid'); 900 901 // appending host ids, inventory_links and keys where they are needed 902 foreach ($items as $i => $item) { 903 if (isset($missingInfo[$item['itemid']])) { 904 if (!isset($items[$i]['hostid'])) { 905 $items[$i]['hostid'] = $missingInfo[$item['itemid']]['hostid']; 906 } 907 if (!isset($items[$i]['inventory_link'])) { 908 $items[$i]['inventory_link'] = $missingInfo[$item['itemid']]['inventory_link']; 909 } 910 if (!isset($items[$i]['key_'])) { 911 $items[$i]['key_'] = $missingInfo[$item['itemid']]['key_']; 912 } 913 } 914 } 915 } 916 } 917 918 $hostids = zbx_objectValues($items, 'hostid'); 919 920 // getting all inventory links on every affected host 921 $itemsOnHostsInfo = API::Item()->get([ 922 'output' => ['key_', 'inventory_link', 'hostid'], 923 'filter' => ['hostid' => $hostids], 924 'nopermissions' => true 925 ]); 926 927 // now, changing array to: 'hostid' => array('key_'=>'inventory_link') 928 $linksOnHostsCurr = []; 929 foreach ($itemsOnHostsInfo as $info) { 930 // 0 means no link - we are not interested in those ones 931 if ($info['inventory_link'] != 0) { 932 if (!isset($linksOnHostsCurr[$info['hostid']])) { 933 $linksOnHostsCurr[$info['hostid']] = [$info['key_'] => $info['inventory_link']]; 934 } 935 else{ 936 $linksOnHostsCurr[$info['hostid']][$info['key_']] = $info['inventory_link']; 937 } 938 } 939 } 940 941 $linksOnHostsFuture = []; 942 943 foreach ($items as $item) { 944 // checking if inventory_link value is a valid number 945 if ($update || $item['value_type'] != ITEM_VALUE_TYPE_LOG) { 946 // does inventory field with provided number exists? 947 if (!isset($possibleHostInventories[$item['inventory_link']])) { 948 $maxVar = max(array_keys($possibleHostInventories)); 949 self::exception( 950 ZBX_API_ERROR_PARAMETERS, 951 _s('Item "%1$s" cannot populate a missing host inventory field number "%2$d". Choices are: from 0 (do not populate) to %3$d.', $item['name'], $item['inventory_link'], $maxVar) 952 ); 953 } 954 } 955 956 if (!isset($linksOnHostsFuture[$item['hostid']])) { 957 $linksOnHostsFuture[$item['hostid']] = [$item['key_'] => $item['inventory_link']]; 958 } 959 else { 960 $linksOnHostsFuture[$item['hostid']][$item['key_']] = $item['inventory_link']; 961 } 962 } 963 964 foreach ($linksOnHostsFuture as $hostId => $linkFuture) { 965 if (isset($linksOnHostsCurr[$hostId])) { 966 $futureSituation = array_merge($linksOnHostsCurr[$hostId], $linksOnHostsFuture[$hostId]); 967 } 968 else { 969 $futureSituation = $linksOnHostsFuture[$hostId]; 970 } 971 $valuesCount = array_count_values($futureSituation); 972 973 // if we have a duplicate inventory links after merging - we are in trouble 974 if (max($valuesCount) > 1) { 975 // what inventory field caused this conflict? 976 $conflictedLink = array_keys($valuesCount, 2); 977 $conflictedLink = reset($conflictedLink); 978 979 // which of updated items populates this link? 980 $beingSavedItemName = ''; 981 foreach ($items as $item) { 982 if ($item['inventory_link'] == $conflictedLink) { 983 if (isset($item['name'])) { 984 $beingSavedItemName = $item['name']; 985 } 986 else { 987 $thisItem = API::Item()->get([ 988 'output' => ['name'], 989 'filter' => ['itemid' => $item['itemid']], 990 'nopermissions' => true 991 ]); 992 $beingSavedItemName = $thisItem[0]['name']; 993 } 994 break; 995 } 996 } 997 998 // name of the original item that already populates the field 999 $originalItem = API::Item()->get([ 1000 'output' => ['name'], 1001 'filter' => [ 1002 'hostid' => $hostId, 1003 'inventory_link' => $conflictedLink 1004 ], 1005 'nopermissions' => true 1006 ]); 1007 $originalItemName = $originalItem[0]['name']; 1008 1009 self::exception( 1010 ZBX_API_ERROR_PARAMETERS, 1011 _s( 1012 'Two items ("%1$s" and "%2$s") cannot populate one host inventory field "%3$s", this would lead to a conflict.', 1013 $beingSavedItemName, 1014 $originalItemName, 1015 $possibleHostInventories[$conflictedLink]['title'] 1016 ) 1017 ); 1018 } 1019 } 1020 1021 return true; 1022 } 1023 1024 public function addRelatedObjects(array $options, array $result) { 1025 $result = parent::addRelatedObjects($options, $result); 1026 1027 $itemids = array_keys($result); 1028 1029 // adding interfaces 1030 if ($options['selectInterfaces'] !== null && $options['selectInterfaces'] != API_OUTPUT_COUNT) { 1031 $relationMap = $this->createRelationMap($result, 'itemid', 'interfaceid'); 1032 $interfaces = API::HostInterface()->get([ 1033 'output' => $options['selectInterfaces'], 1034 'interfaceids' => $relationMap->getRelatedIds(), 1035 'nopermissions' => true, 1036 'preservekeys' => true 1037 ]); 1038 $result = $relationMap->mapMany($result, $interfaces, 'interfaces'); 1039 } 1040 1041 // adding triggers 1042 if (!is_null($options['selectTriggers'])) { 1043 if ($options['selectTriggers'] != API_OUTPUT_COUNT) { 1044 $triggers = []; 1045 $relationMap = $this->createRelationMap($result, 'itemid', 'triggerid', 'functions'); 1046 $related_ids = $relationMap->getRelatedIds(); 1047 1048 if ($related_ids) { 1049 $triggers = API::Trigger()->get([ 1050 'output' => $options['selectTriggers'], 1051 'triggerids' => $related_ids, 1052 'preservekeys' => true 1053 ]); 1054 1055 if (!is_null($options['limitSelects'])) { 1056 order_result($triggers, 'description'); 1057 } 1058 } 1059 1060 $result = $relationMap->mapMany($result, $triggers, 'triggers', $options['limitSelects']); 1061 } 1062 else { 1063 $triggers = API::Trigger()->get([ 1064 'countOutput' => true, 1065 'groupCount' => true, 1066 'itemids' => $itemids 1067 ]); 1068 $triggers = zbx_toHash($triggers, 'itemid'); 1069 1070 foreach ($result as $itemid => $item) { 1071 $result[$itemid]['triggers'] = array_key_exists($itemid, $triggers) 1072 ? $triggers[$itemid]['rowscount'] 1073 : '0'; 1074 } 1075 } 1076 } 1077 1078 // adding graphs 1079 if (!is_null($options['selectGraphs'])) { 1080 if ($options['selectGraphs'] != API_OUTPUT_COUNT) { 1081 $graphs = []; 1082 $relationMap = $this->createRelationMap($result, 'itemid', 'graphid', 'graphs_items'); 1083 $related_ids = $relationMap->getRelatedIds(); 1084 1085 if ($related_ids) { 1086 $graphs = API::Graph()->get([ 1087 'output' => $options['selectGraphs'], 1088 'graphids' => $related_ids, 1089 'preservekeys' => true 1090 ]); 1091 1092 if (!is_null($options['limitSelects'])) { 1093 order_result($graphs, 'name'); 1094 } 1095 } 1096 1097 $result = $relationMap->mapMany($result, $graphs, 'graphs', $options['limitSelects']); 1098 } 1099 else { 1100 $graphs = API::Graph()->get([ 1101 'countOutput' => true, 1102 'groupCount' => true, 1103 'itemids' => $itemids 1104 ]); 1105 $graphs = zbx_toHash($graphs, 'itemid'); 1106 1107 foreach ($result as $itemid => $item) { 1108 $result[$itemid]['graphs'] = array_key_exists($itemid, $graphs) 1109 ? $graphs[$itemid]['rowscount'] 1110 : '0'; 1111 } 1112 } 1113 } 1114 1115 // adding discoveryrule 1116 if ($options['selectDiscoveryRule'] !== null && $options['selectDiscoveryRule'] != API_OUTPUT_COUNT) { 1117 $discoveryRules = []; 1118 $relationMap = new CRelationMap(); 1119 // discovered items 1120 $dbRules = DBselect( 1121 'SELECT id1.itemid,id2.parent_itemid'. 1122 ' FROM item_discovery id1,item_discovery id2,items i'. 1123 ' WHERE '.dbConditionInt('id1.itemid', $itemids). 1124 ' AND id1.parent_itemid=id2.itemid'. 1125 ' AND i.itemid=id1.itemid'. 1126 ' AND i.flags='.ZBX_FLAG_DISCOVERY_CREATED 1127 ); 1128 while ($rule = DBfetch($dbRules)) { 1129 $relationMap->addRelation($rule['itemid'], $rule['parent_itemid']); 1130 } 1131 1132 // item prototypes 1133 // TODO: this should not be in the item API 1134 $dbRules = DBselect( 1135 'SELECT id.parent_itemid,id.itemid'. 1136 ' FROM item_discovery id,items i'. 1137 ' WHERE '.dbConditionInt('id.itemid', $itemids). 1138 ' AND i.itemid=id.itemid'. 1139 ' AND i.flags='.ZBX_FLAG_DISCOVERY_PROTOTYPE 1140 ); 1141 while ($rule = DBfetch($dbRules)) { 1142 $relationMap->addRelation($rule['itemid'], $rule['parent_itemid']); 1143 } 1144 1145 $related_ids = $relationMap->getRelatedIds(); 1146 1147 if ($related_ids) { 1148 $discoveryRules = API::DiscoveryRule()->get([ 1149 'output' => $options['selectDiscoveryRule'], 1150 'itemids' => $related_ids, 1151 'nopermissions' => true, 1152 'preservekeys' => true 1153 ]); 1154 } 1155 1156 $result = $relationMap->mapOne($result, $discoveryRules, 'discoveryRule'); 1157 } 1158 1159 // adding item discovery 1160 if ($options['selectItemDiscovery'] !== null) { 1161 $itemDiscoveries = API::getApiService()->select('item_discovery', [ 1162 'output' => $this->outputExtend($options['selectItemDiscovery'], ['itemdiscoveryid', 'itemid']), 1163 'filter' => ['itemid' => array_keys($result)], 1164 'preservekeys' => true 1165 ]); 1166 $relationMap = $this->createRelationMap($itemDiscoveries, 'itemid', 'itemdiscoveryid'); 1167 1168 $itemDiscoveries = $this->unsetExtraFields($itemDiscoveries, ['itemid', 'itemdiscoveryid'], 1169 $options['selectItemDiscovery'] 1170 ); 1171 $result = $relationMap->mapOne($result, $itemDiscoveries, 'itemDiscovery'); 1172 } 1173 1174 // adding history data 1175 $requestedOutput = []; 1176 if ($this->outputIsRequested('lastclock', $options['output'])) { 1177 $requestedOutput['lastclock'] = true; 1178 } 1179 if ($this->outputIsRequested('lastns', $options['output'])) { 1180 $requestedOutput['lastns'] = true; 1181 } 1182 if ($this->outputIsRequested('lastvalue', $options['output'])) { 1183 $requestedOutput['lastvalue'] = true; 1184 } 1185 if ($this->outputIsRequested('prevvalue', $options['output'])) { 1186 $requestedOutput['prevvalue'] = true; 1187 } 1188 if ($requestedOutput) { 1189 $history = Manager::History()->getLastValues($result, 2, timeUnitToSeconds(CSettingsHelper::get( 1190 CSettingsHelper::HISTORY_PERIOD 1191 ))); 1192 foreach ($result as &$item) { 1193 $lastHistory = isset($history[$item['itemid']][0]) ? $history[$item['itemid']][0] : null; 1194 $prevHistory = isset($history[$item['itemid']][1]) ? $history[$item['itemid']][1] : null; 1195 $no_value = in_array($item['value_type'], 1196 [ITEM_VALUE_TYPE_STR, ITEM_VALUE_TYPE_LOG, ITEM_VALUE_TYPE_TEXT]) ? '' : '0'; 1197 1198 if (isset($requestedOutput['lastclock'])) { 1199 $item['lastclock'] = $lastHistory ? $lastHistory['clock'] : '0'; 1200 } 1201 if (isset($requestedOutput['lastns'])) { 1202 $item['lastns'] = $lastHistory ? $lastHistory['ns'] : '0'; 1203 } 1204 if (isset($requestedOutput['lastvalue'])) { 1205 $item['lastvalue'] = $lastHistory ? $lastHistory['value'] : $no_value; 1206 } 1207 if (isset($requestedOutput['prevvalue'])) { 1208 $item['prevvalue'] = $prevHistory ? $prevHistory['value'] : $no_value; 1209 } 1210 } 1211 unset($item); 1212 } 1213 1214 // Adding item tags. 1215 if ($options['selectTags'] !== null) { 1216 $options['selectTags'] = ($options['selectTags'] !== API_OUTPUT_EXTEND) 1217 ? (array) $options['selectTags'] 1218 : ['tag', 'value']; 1219 1220 $options['selectTags'] = array_intersect(['tag', 'value'], $options['selectTags']); 1221 $requested_output = array_flip($options['selectTags']); 1222 1223 $db_tags = DBselect( 1224 'SELECT '.implode(',', array_merge($options['selectTags'], ['itemid'])). 1225 ' FROM item_tag'. 1226 ' WHERE '.dbConditionInt('itemid', $itemids) 1227 ); 1228 1229 array_walk($result, function (&$item) { 1230 $item['tags'] = []; 1231 }); 1232 1233 while ($db_tag = DBfetch($db_tags)) { 1234 $result[$db_tag['itemid']]['tags'][] = array_intersect_key($db_tag, $requested_output); 1235 } 1236 } 1237 1238 return $result; 1239 } 1240 1241 protected function applyQueryOutputOptions($tableName, $tableAlias, array $options, array $sqlParts) { 1242 $sqlParts = parent::applyQueryOutputOptions($tableName, $tableAlias, $options, $sqlParts); 1243 1244 if ((!$options['countOutput'] && ($this->outputIsRequested('state', $options['output']) 1245 || $this->outputIsRequested('error', $options['output']))) 1246 || (is_array($options['search']) && array_key_exists('error', $options['search'])) 1247 || (is_array($options['filter']) && array_key_exists('state', $options['filter']))) { 1248 $sqlParts['left_join'][] = ['alias' => 'ir', 'table' => 'item_rtdata', 'using' => 'itemid']; 1249 $sqlParts['left_table'] = ['alias' => $this->tableAlias, 'table' => $this->tableName]; 1250 } 1251 1252 if (!$options['countOutput']) { 1253 if ($this->outputIsRequested('state', $options['output'])) { 1254 $sqlParts = $this->addQuerySelect('ir.state', $sqlParts); 1255 } 1256 if ($this->outputIsRequested('error', $options['output'])) { 1257 /* 1258 * SQL func COALESCE use for template items because they don't have record 1259 * in item_rtdata table and DBFetch convert null to '0' 1260 */ 1261 $sqlParts = $this->addQuerySelect(dbConditionCoalesce('ir.error', '', 'error'), $sqlParts); 1262 } 1263 1264 if ($options['selectHosts'] !== null) { 1265 $sqlParts = $this->addQuerySelect('i.hostid', $sqlParts); 1266 } 1267 1268 if ($options['selectInterfaces'] !== null) { 1269 $sqlParts = $this->addQuerySelect('i.interfaceid', $sqlParts); 1270 } 1271 1272 if ($options['selectValueMap'] !== null) { 1273 $sqlParts = $this->addQuerySelect('i.valuemapid', $sqlParts); 1274 } 1275 1276 if ($this->outputIsRequested('lastclock', $options['output']) 1277 || $this->outputIsRequested('lastns', $options['output']) 1278 || $this->outputIsRequested('lastvalue', $options['output']) 1279 || $this->outputIsRequested('prevvalue', $options['output'])) { 1280 1281 $sqlParts = $this->addQuerySelect('i.value_type', $sqlParts); 1282 } 1283 } 1284 1285 return $sqlParts; 1286 } 1287} 1288