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 22require_once dirname(__FILE__).'/include/config.inc.php'; 23require_once dirname(__FILE__).'/include/hosts.inc.php'; 24require_once dirname(__FILE__).'/include/items.inc.php'; 25require_once dirname(__FILE__).'/include/forms.inc.php'; 26 27$page['title'] = _('Configuration of item prototypes'); 28$page['file'] = 'disc_prototypes.php'; 29$page['scripts'] = ['effects.js', 'class.cviewswitcher.js', 'multilineinput.js', 'multiselect.js', 'items.js', 30 'textareaflexible.js', 'class.tab-indicators.js' 31]; 32 33require_once dirname(__FILE__).'/include/page_header.php'; 34 35$paramsFieldName = getParamFieldNameByType(getRequest('type', 0)); 36 37// VAR TYPE OPTIONAL FLAGS VALIDATION EXCEPTION 38$fields = [ 39 'parent_discoveryid' => [T_ZBX_INT, O_MAND, P_SYS, DB_ID, null], 40 'hostid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null], 41 'itemid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, 'isset({form}) && {form} == "update"'], 42 'interfaceid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null, _('Interface')], 43 'name' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 'isset({add}) || isset({update})', 44 _('Name') 45 ], 46 'description' => [T_ZBX_STR, O_OPT, null, null, 'isset({add}) || isset({update})'], 47 'key' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 'isset({add}) || isset({update})', 48 _('Key') 49 ], 50 'master_itemid' => [T_ZBX_STR, O_OPT, null, null, 51 '(isset({add}) || isset({update})) && isset({type})'. 52 ' && {type} == '.ITEM_TYPE_DEPENDENT, 53 _('Master item') 54 ], 55 'delay' => [T_ZBX_TU, O_OPT, P_ALLOW_USER_MACRO | P_ALLOW_LLD_MACRO, null, 56 '(isset({add}) || isset({update}))'. 57 ' && isset({type}) && {type} != '.ITEM_TYPE_TRAPPER. 58 ' && {type} != '.ITEM_TYPE_SNMPTRAP. 59 ' && {type} != '.ITEM_TYPE_DEPENDENT. 60 ' && !({type} == '.ITEM_TYPE_ZABBIX_ACTIVE. 61 ' && isset({key}) && strncmp({key}, "mqtt.get", 8) === 0)', 62 _('Update interval') 63 ], 64 'delay_flex' => [T_ZBX_STR, O_OPT, null, null, null], 65 'status' => [T_ZBX_INT, O_OPT, null, IN([ITEM_STATUS_ACTIVE, ITEM_STATUS_DISABLED]), null], 66 'discover' => [T_ZBX_INT, O_OPT, null, IN([ZBX_PROTOTYPE_DISCOVER, ZBX_PROTOTYPE_NO_DISCOVER]), null], 67 'type' => [T_ZBX_INT, O_OPT, null, 68 IN([-1, ITEM_TYPE_ZABBIX, ITEM_TYPE_TRAPPER, ITEM_TYPE_SIMPLE, 69 ITEM_TYPE_INTERNAL, ITEM_TYPE_ZABBIX_ACTIVE, 70 ITEM_TYPE_EXTERNAL, ITEM_TYPE_DB_MONITOR, ITEM_TYPE_IPMI, ITEM_TYPE_SSH, 71 ITEM_TYPE_TELNET, ITEM_TYPE_JMX, ITEM_TYPE_CALCULATED, ITEM_TYPE_SNMPTRAP, 72 ITEM_TYPE_DEPENDENT, ITEM_TYPE_HTTPAGENT, ITEM_TYPE_SNMP, ITEM_TYPE_SCRIPT 73 ]), 74 'isset({add}) || isset({update})' 75 ], 76 'value_type' => [T_ZBX_INT, O_OPT, null, IN('0,1,2,3,4'), 'isset({add}) || isset({update})'], 77 'valuemapid' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 78 'authtype' => [T_ZBX_INT, O_OPT, null, IN(ITEM_AUTHTYPE_PASSWORD.','.ITEM_AUTHTYPE_PUBLICKEY), 79 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_SSH 80 ], 81 'username' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 82 '(isset({add}) || isset({update})) && isset({type})'. 83 ' && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_TELNET, 'type'), 84 _('User name') 85 ], 86 'password' => [T_ZBX_STR, O_OPT, null, null, 87 '(isset({add}) || isset({update})) && isset({type})'. 88 ' && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_TELNET, 'type') 89 ], 90 'publickey' => [T_ZBX_STR, O_OPT, null, null, 91 '(isset({add}) || isset({update})) && isset({type})'. 92 ' && {type} == '.ITEM_TYPE_SSH.' && {authtype} == '.ITEM_AUTHTYPE_PUBLICKEY 93 ], 94 'privatekey' => [T_ZBX_STR, O_OPT, null, null, 95 '(isset({add}) || isset({update})) && isset({type})'. 96 ' && {type} == '.ITEM_TYPE_SSH.' && {authtype} == '.ITEM_AUTHTYPE_PUBLICKEY 97 ], 98 $paramsFieldName => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 99 '(isset({add}) || isset({update})) && isset({type})'. 100 ' && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_DB_MONITOR.','.ITEM_TYPE_TELNET.','. 101 ITEM_TYPE_CALCULATED.','.ITEM_TYPE_SCRIPT, 'type' 102 ), 103 getParamFieldLabelByType(getRequest('type', 0)) 104 ], 105 'snmp_oid' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 106 '(isset({add}) || isset({update})) && isset({type})'. 107 ' && {type} == '.ITEM_TYPE_SNMP, 108 _('SNMP OID') 109 ], 110 'ipmi_sensor' => [T_ZBX_STR, O_OPT, P_NO_TRIM, null, 111 '(isset({add}) || isset({update})) && isset({type})'. 112 ' && {type} == '.ITEM_TYPE_IPMI, 113 _('IPMI sensor') 114 ], 115 'trapper_hosts' => [T_ZBX_STR, O_OPT, null, null, 116 '(isset({add}) || isset({update})) && isset({type})'. 117 ' && {type} == '.ITEM_TYPE_TRAPPER 118 ], 119 'units' => [T_ZBX_STR, O_OPT, null, null, 120 '(isset({add}) || isset({update})) && isset({value_type})'. 121 ' && '.IN(ITEM_VALUE_TYPE_FLOAT.','.ITEM_VALUE_TYPE_UINT64, 'value_type') 122 ], 123 'logtimefmt' => [T_ZBX_STR, O_OPT, null, null, 124 '(isset({add}) || isset({update})) && isset({value_type})'. 125 ' && {value_type} == '.ITEM_VALUE_TYPE_LOG 126 ], 127 'preprocessing' => [T_ZBX_STR, O_OPT, P_NO_TRIM, null, null], 128 'group_itemid' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 129 'history_mode' => [T_ZBX_INT, O_OPT, null, IN([ITEM_STORAGE_OFF, ITEM_STORAGE_CUSTOM]), null], 130 'history' => [T_ZBX_STR, O_OPT, null, null, 131 '(isset({add}) || isset({update}))'. 132 ' && isset({history_mode}) && {history_mode}=='.ITEM_STORAGE_CUSTOM, 133 _('History storage period') 134 ], 135 'trends_mode' => [T_ZBX_INT, O_OPT, null, IN([ITEM_STORAGE_OFF, ITEM_STORAGE_CUSTOM]), null], 136 'trends' => [T_ZBX_STR, O_OPT, null, null, 137 '(isset({add}) || isset({update}))'. 138 ' && isset({trends_mode}) && {trends_mode}=='.ITEM_STORAGE_CUSTOM. 139 ' && isset({value_type})'. 140 ' && '.IN(ITEM_VALUE_TYPE_FLOAT.','.ITEM_VALUE_TYPE_UINT64, 'value_type'), 141 _('Trend storage period') 142 ], 143 'jmx_endpoint' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 144 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_JMX 145 ], 146 'timeout' => [T_ZBX_TU, O_OPT, P_ALLOW_USER_MACRO|P_ALLOW_LLD_MACRO, null, 147 '(isset({add}) || isset({update})) && isset({type})'. 148 ' && '.IN(ITEM_TYPE_HTTPAGENT.','.ITEM_TYPE_SCRIPT, 'type'), 149 _('Timeout') 150 ], 151 'url' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 152 '(isset({add}) || isset({update})) && isset({type})'. 153 ' && {type} == '.ITEM_TYPE_HTTPAGENT, 154 _('URL') 155 ], 156 'query_fields' => [T_ZBX_STR, O_OPT, null, null, null], 157 'parameters' => [T_ZBX_STR, O_OPT, null, null, null], 158 'posts' => [T_ZBX_STR, O_OPT, null, null, null], 159 'status_codes' => [T_ZBX_STR, O_OPT, null, null, null], 160 'follow_redirects' => [T_ZBX_INT, O_OPT, null, 161 IN([HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF, HTTPTEST_STEP_FOLLOW_REDIRECTS_ON]), 162 null 163 ], 164 'post_type' => [T_ZBX_INT, O_OPT, null, 165 IN([ZBX_POSTTYPE_RAW, ZBX_POSTTYPE_JSON, ZBX_POSTTYPE_XML]), 166 null 167 ], 168 'http_proxy' => [T_ZBX_STR, O_OPT, null, null, null], 169 'headers' => [T_ZBX_STR, O_OPT, null, null, null], 170 'retrieve_mode' => [T_ZBX_INT, O_OPT, null, 171 IN([HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, HTTPTEST_STEP_RETRIEVE_MODE_HEADERS, 172 HTTPTEST_STEP_RETRIEVE_MODE_BOTH 173 ]), 174 null 175 ], 176 'request_method' => [T_ZBX_INT, O_OPT, null, 177 IN([HTTPCHECK_REQUEST_GET, HTTPCHECK_REQUEST_POST, HTTPCHECK_REQUEST_PUT, 178 HTTPCHECK_REQUEST_HEAD 179 ]), 180 null 181 ], 182 'output_format' => [T_ZBX_INT, O_OPT, null, IN([HTTPCHECK_STORE_RAW, HTTPCHECK_STORE_JSON]), null], 183 'allow_traps' => [T_ZBX_INT, O_OPT, null, 184 IN([HTTPCHECK_ALLOW_TRAPS_OFF, HTTPCHECK_ALLOW_TRAPS_ON]), 185 null 186 ], 187 'ssl_cert_file' => [T_ZBX_STR, O_OPT, null, null, null], 188 'ssl_key_file' => [T_ZBX_STR, O_OPT, null, null, null], 189 'ssl_key_password' => [T_ZBX_STR, O_OPT, null, null, null], 190 'verify_peer' => [T_ZBX_INT, O_OPT, null, 191 IN([HTTPTEST_VERIFY_PEER_OFF, HTTPTEST_VERIFY_PEER_ON]), 192 null 193 ], 194 'verify_host' => [T_ZBX_INT, O_OPT, null, 195 IN([HTTPTEST_VERIFY_HOST_OFF, HTTPTEST_VERIFY_HOST_ON]), 196 null 197 ], 198 'http_authtype' => [T_ZBX_INT, O_OPT, null, 199 IN([HTTPTEST_AUTH_NONE, HTTPTEST_AUTH_BASIC, HTTPTEST_AUTH_NTLM, 200 HTTPTEST_AUTH_KERBEROS, HTTPTEST_AUTH_DIGEST 201 ]), 202 null 203 ], 204 'http_username' => [T_ZBX_STR, O_OPT, null, null, 205 '(isset({add}) || isset({update})) && isset({http_authtype})'. 206 ' && ({http_authtype} == '.HTTPTEST_AUTH_BASIC. 207 ' || {http_authtype} == '.HTTPTEST_AUTH_NTLM. 208 ' || {http_authtype} == '.HTTPTEST_AUTH_KERBEROS. 209 ' || {http_authtype} == '.HTTPTEST_AUTH_DIGEST. 210 ')', 211 _('Username') 212 ], 213 'http_password' => [T_ZBX_STR, O_OPT, null, null, 214 '(isset({add}) || isset({update})) && isset({http_authtype})'. 215 ' && ({http_authtype} == '.HTTPTEST_AUTH_BASIC. 216 ' || {http_authtype} == '.HTTPTEST_AUTH_NTLM. 217 ' || {http_authtype} == '.HTTPTEST_AUTH_KERBEROS. 218 ' || {http_authtype} == '.HTTPTEST_AUTH_DIGEST. 219 ')', 220 _('Password') 221 ], 222 'visible' => [T_ZBX_STR, O_OPT, null, null, null], 223 'context' => [T_ZBX_STR, O_MAND, P_SYS, IN('"host", "template"'), null], 224 'tags' => [T_ZBX_STR, O_OPT, null, null, null], 225 'show_inherited_tags' => [T_ZBX_INT, O_OPT, null, IN([0,1]), null], 226 // actions 227 'action' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, 228 IN('"itemprototype.massdelete","itemprototype.massdisable",'. 229 '"itemprototype.massenable","itemprototype.massdiscover.enable",'. 230 '"itemprototype.massdiscover.disable"' 231 ), 232 null 233 ], 234 'add' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 235 'update' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 236 'clone' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 237 'delete' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 238 'cancel' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 239 'form' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 240 'form_refresh' => [T_ZBX_INT, O_OPT, null, null, null], 241 // filter 242 'filter_set' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 243 // sort and sortorder 244 'sort' => [T_ZBX_STR, O_OPT, P_SYS, 245 IN('"delay","history","key_","name","status","trends","type","discover"'), null 246 ], 247 'sortorder' => [T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'), null] 248]; 249$valid_input = check_fields($fields); 250 251$_REQUEST['params'] = getRequest($paramsFieldName, ''); 252unset($_REQUEST[$paramsFieldName]); 253 254// permissions 255$discoveryRule = API::DiscoveryRule()->get([ 256 'output' => ['hostid'], 257 'itemids' => getRequest('parent_discoveryid'), 258 'editable' => true 259]); 260$discoveryRule = reset($discoveryRule); 261if (!$discoveryRule) { 262 access_deny(); 263} 264 265$itemPrototypeId = getRequest('itemid'); 266if ($itemPrototypeId) { 267 $item_prorotypes = API::ItemPrototype()->get([ 268 'output' => [], 269 'itemids' => $itemPrototypeId, 270 'editable' => true 271 ]); 272 273 if (!$item_prorotypes) { 274 access_deny(); 275 } 276} 277 278// Convert CR+LF to LF in preprocessing script. 279if (hasRequest('preprocessing')) { 280 foreach ($_REQUEST['preprocessing'] as &$step) { 281 if ($step['type'] == ZBX_PREPROC_SCRIPT) { 282 $step['params'][0] = CRLFtoLF($step['params'][0]); 283 } 284 } 285 unset($step); 286} 287 288$tags = getRequest('tags', []); 289foreach ($tags as $key => $tag) { 290 if ($tag['tag'] === '' && $tag['value'] === '') { 291 unset($tags[$key]); 292 } 293 elseif (array_key_exists('type', $tag) && !($tag['type'] & ZBX_PROPERTY_OWN)) { 294 unset($tags[$key]); 295 } 296 else { 297 unset($tags[$key]['type']); 298 } 299} 300 301/* 302 * Actions 303 */ 304if (hasRequest('delete') && hasRequest('itemid')) { 305 DBstart(); 306 $result = API::ItemPrototype()->delete([getRequest('itemid')]); 307 $result = DBend($result); 308 309 if ($result) { 310 uncheckTableRows(getRequest('parent_discoveryid')); 311 } 312 show_messages($result, _('Item prototype deleted'), _('Cannot delete item prototype')); 313 314 unset($_REQUEST['itemid'], $_REQUEST['form']); 315} 316elseif (hasRequest('add') || hasRequest('update')) { 317 $result = true; 318 DBstart(); 319 320 $delay = getRequest('delay', DB::getDefault('items', 'delay')); 321 $type = getRequest('type', ITEM_TYPE_ZABBIX); 322 323 /* 324 * "delay_flex" is a temporary field that collects flexible and scheduling intervals separated by a semicolon. 325 * In the end, custom intervals together with "delay" are stored in the "delay" variable. 326 */ 327 if ($type != ITEM_TYPE_TRAPPER && $type != ITEM_TYPE_SNMPTRAP 328 && ($type != ITEM_TYPE_ZABBIX_ACTIVE || strncmp(getRequest('key'), 'mqtt.get', 8) !== 0) 329 && hasRequest('delay_flex')) { 330 $intervals = []; 331 $simple_interval_parser = new CSimpleIntervalParser([ 332 'usermacros' => true, 333 'lldmacros' => true 334 ]); 335 $time_period_parser = new CTimePeriodParser([ 336 'usermacros' => true, 337 'lldmacros' => true 338 ]); 339 $scheduling_interval_parser = new CSchedulingIntervalParser([ 340 'usermacros' => true, 341 'lldmacros' => true 342 ]); 343 344 foreach (getRequest('delay_flex') as $interval) { 345 if ($interval['type'] == ITEM_DELAY_FLEXIBLE) { 346 if ($interval['delay'] === '' && $interval['period'] === '') { 347 continue; 348 } 349 350 if ($simple_interval_parser->parse($interval['delay']) != CParser::PARSE_SUCCESS) { 351 $result = false; 352 info(_s('Invalid interval "%1$s".', $interval['delay'])); 353 break; 354 } 355 elseif ($time_period_parser->parse($interval['period']) != CParser::PARSE_SUCCESS) { 356 $result = false; 357 info(_s('Invalid interval "%1$s".', $interval['period'])); 358 break; 359 } 360 361 $intervals[] = $interval['delay'].'/'.$interval['period']; 362 } 363 else { 364 if ($interval['schedule'] === '') { 365 continue; 366 } 367 368 if ($scheduling_interval_parser->parse($interval['schedule']) != CParser::PARSE_SUCCESS) { 369 $result = false; 370 info(_s('Invalid interval "%1$s".', $interval['schedule'])); 371 break; 372 } 373 374 $intervals[] = $interval['schedule']; 375 } 376 } 377 378 if ($intervals) { 379 $delay .= ';'.implode(';', $intervals); 380 } 381 } 382 383 if ($result) { 384 $preprocessing = getRequest('preprocessing', []); 385 386 foreach ($preprocessing as &$step) { 387 switch ($step['type']) { 388 case ZBX_PREPROC_MULTIPLIER: 389 case ZBX_PREPROC_PROMETHEUS_TO_JSON: 390 $step['params'] = trim($step['params'][0]); 391 break; 392 393 case ZBX_PREPROC_RTRIM: 394 case ZBX_PREPROC_LTRIM: 395 case ZBX_PREPROC_TRIM: 396 case ZBX_PREPROC_XPATH: 397 case ZBX_PREPROC_JSONPATH: 398 case ZBX_PREPROC_VALIDATE_REGEX: 399 case ZBX_PREPROC_VALIDATE_NOT_REGEX: 400 case ZBX_PREPROC_ERROR_FIELD_JSON: 401 case ZBX_PREPROC_ERROR_FIELD_XML: 402 case ZBX_PREPROC_THROTTLE_TIMED_VALUE: 403 case ZBX_PREPROC_SCRIPT: 404 $step['params'] = $step['params'][0]; 405 break; 406 407 case ZBX_PREPROC_VALIDATE_RANGE: 408 case ZBX_PREPROC_PROMETHEUS_PATTERN: 409 foreach ($step['params'] as &$param) { 410 $param = trim($param); 411 } 412 unset($param); 413 414 $step['params'] = implode("\n", $step['params']); 415 break; 416 417 case ZBX_PREPROC_REGSUB: 418 case ZBX_PREPROC_ERROR_FIELD_REGEX: 419 case ZBX_PREPROC_STR_REPLACE: 420 $step['params'] = implode("\n", $step['params']); 421 break; 422 423 // ZBX-16642 424 case ZBX_PREPROC_CSV_TO_JSON: 425 if (!array_key_exists(2, $step['params'])) { 426 $step['params'][2] = ZBX_PREPROC_CSV_NO_HEADER; 427 } 428 $step['params'] = implode("\n", $step['params']); 429 break; 430 431 default: 432 $step['params'] = ''; 433 } 434 435 $step += [ 436 'error_handler' => ZBX_PREPROC_FAIL_DEFAULT, 437 'error_handler_params' => '' 438 ]; 439 } 440 unset($step); 441 442 $item = [ 443 'name' => getRequest('name'), 444 'description' => getRequest('description'), 445 'key_' => getRequest('key'), 446 'hostid' => $discoveryRule['hostid'], 447 'interfaceid' => getRequest('interfaceid'), 448 'delay' => $delay, 449 'status' => getRequest('status', ITEM_STATUS_DISABLED), 450 'discover' => getRequest('discover', ZBX_PROTOTYPE_DISCOVER), 451 'type' => getRequest('type'), 452 'snmp_oid' => getRequest('snmp_oid'), 453 'value_type' => getRequest('value_type'), 454 'trapper_hosts' => getRequest('trapper_hosts'), 455 'history' => (getRequest('history_mode', ITEM_STORAGE_CUSTOM) == ITEM_STORAGE_OFF) 456 ? ITEM_NO_STORAGE_VALUE 457 : getRequest('history'), 458 'units' => getRequest('units'), 459 'logtimefmt' => getRequest('logtimefmt'), 460 'valuemapid' => getRequest('valuemapid', 0), 461 'authtype' => getRequest('authtype'), 462 'username' => getRequest('username'), 463 'password' => getRequest('password'), 464 'publickey' => getRequest('publickey'), 465 'privatekey' => getRequest('privatekey'), 466 'params' => getRequest('params'), 467 'ipmi_sensor' => getRequest('ipmi_sensor'), 468 'ruleid' => getRequest('parent_discoveryid') 469 ]; 470 471 if ($item['type'] == ITEM_TYPE_SCRIPT) { 472 $script_item = [ 473 'parameters' => getRequest('parameters', []), 474 'timeout' => getRequest('timeout', DB::getDefault('items', 'timeout')) 475 ]; 476 477 $item = prepareScriptItemFormData($script_item) + $item; 478 } 479 480 if ($item['type'] == ITEM_TYPE_JMX) { 481 $item['jmx_endpoint'] = getRequest('jmx_endpoint', ''); 482 } 483 484 if ($item['value_type'] == ITEM_VALUE_TYPE_FLOAT || $item['value_type'] == ITEM_VALUE_TYPE_UINT64) { 485 $item['trends'] = (getRequest('trends_mode', ITEM_STORAGE_CUSTOM) == ITEM_STORAGE_OFF) 486 ? ITEM_NO_STORAGE_VALUE 487 : getRequest('trends'); 488 } 489 490 if ($item['type'] == ITEM_TYPE_DEPENDENT) { 491 $item['master_itemid'] = getRequest('master_itemid'); 492 } 493 494 if (hasRequest('update')) { 495 $itemId = getRequest('itemid'); 496 497 $db_item = API::ItemPrototype()->get([ 498 'output' => ['type', 'snmp_oid', 'hostid', 'name', 'key_', 'delay', 'history', 499 'trends', 'status', 'value_type', 'trapper_hosts', 'units', 500 'logtimefmt', 'templateid', 'valuemapid', 'params', 'ipmi_sensor', 'authtype', 'username', 501 'password', 'publickey', 'privatekey', 'interfaceid', 'description', 'jmx_endpoint', 502 'master_itemid', 'timeout', 'url', 'query_fields', 'posts', 'status_codes', 'follow_redirects', 503 'post_type', 'http_proxy', 'headers', 'retrieve_mode', 'request_method', 'output_format', 504 'ssl_cert_file', 'ssl_key_file', 'ssl_key_password', 'verify_peer', 'verify_host', 'allow_traps', 505 'discover', 'parameters' 506 ], 507 'selectPreprocessing' => ['type', 'params', 'error_handler', 'error_handler_params'], 508 'selectTags' => ['tag', 'value'], 509 'itemids' => [$itemId] 510 ]); 511 512 $db_item = $db_item[0]; 513 514 if ($item['type'] == ITEM_TYPE_HTTPAGENT) { 515 $http_item = [ 516 'timeout' => getRequest('timeout', DB::getDefault('items', 'timeout')), 517 'url' => getRequest('url'), 518 'query_fields' => getRequest('query_fields', []), 519 'posts' => getRequest('posts'), 520 'status_codes' => getRequest('status_codes', DB::getDefault('items', 'status_codes')), 521 'follow_redirects' => (int) getRequest('follow_redirects'), 522 'post_type' => (int) getRequest('post_type'), 523 'http_proxy' => getRequest('http_proxy'), 524 'headers' => getRequest('headers', []), 525 'retrieve_mode' => (int) getRequest('retrieve_mode'), 526 'request_method' => (int) getRequest('request_method'), 527 'output_format' => (int) getRequest('output_format'), 528 'allow_traps' => (int) getRequest('allow_traps', HTTPCHECK_ALLOW_TRAPS_OFF), 529 'ssl_cert_file' => getRequest('ssl_cert_file'), 530 'ssl_key_file' => getRequest('ssl_key_file'), 531 'ssl_key_password' => getRequest('ssl_key_password'), 532 'verify_peer' => (int) getRequest('verify_peer'), 533 'verify_host' => (int) getRequest('verify_host'), 534 'authtype' => getRequest('http_authtype', HTTPTEST_AUTH_NONE), 535 'username' => getRequest('http_username', ''), 536 'password' => getRequest('http_password', '') 537 ]; 538 $item = prepareItemHttpAgentFormData($http_item) + $item; 539 } 540 541 if ($db_item['type'] == $item['type']) { 542 $item = CArrayHelper::unsetEqualValues($item, $db_item); 543 } 544 545 $item['itemid'] = $itemId; 546 547 if ($db_item['preprocessing'] !== $preprocessing) { 548 $item['preprocessing'] = $preprocessing; 549 } 550 551 $compare = function($arr, $arr2) { 552 return (array_combine(array_column($arr, 'name'), array_column($arr, 'value')) == 553 array_combine(array_column($arr2, 'name'), array_column($arr2, 'value')) 554 ); 555 }; 556 if (getRequest('type') == ITEM_TYPE_SCRIPT && $db_item['type'] == getRequest('type') 557 && $compare($db_item['parameters'], $item['parameters'])) { 558 unset($item['parameters']); 559 } 560 561 CArrayHelper::sort($db_item['tags'], ['tag', 'value']); 562 CArrayHelper::sort($tags, ['tag', 'value']); 563 if (array_values($db_item['tags']) !== array_values($tags)) { 564 $item['tags'] = $tags; 565 } 566 567 $result = API::ItemPrototype()->update($item); 568 } 569 else { 570 if (getRequest('type') == ITEM_TYPE_HTTPAGENT) { 571 $http_item = [ 572 'timeout' => getRequest('timeout', DB::getDefault('items', 'timeout')), 573 'url' => getRequest('url'), 574 'query_fields' => getRequest('query_fields', []), 575 'posts' => getRequest('posts'), 576 'status_codes' => getRequest('status_codes', DB::getDefault('items', 'status_codes')), 577 'follow_redirects' => (int) getRequest('follow_redirects'), 578 'post_type' => (int) getRequest('post_type'), 579 'http_proxy' => getRequest('http_proxy'), 580 'headers' => getRequest('headers', []), 581 'retrieve_mode' => (int) getRequest('retrieve_mode'), 582 'request_method' => (int) getRequest('request_method'), 583 'output_format' => (int) getRequest('output_format'), 584 'allow_traps' => (int) getRequest('allow_traps', HTTPCHECK_ALLOW_TRAPS_OFF), 585 'ssl_cert_file' => getRequest('ssl_cert_file'), 586 'ssl_key_file' => getRequest('ssl_key_file'), 587 'ssl_key_password' => getRequest('ssl_key_password'), 588 'verify_peer' => (int) getRequest('verify_peer'), 589 'verify_host' => (int) getRequest('verify_host'), 590 'authtype' => getRequest('http_authtype', HTTPTEST_AUTH_NONE), 591 'username' => getRequest('http_username', ''), 592 'password' => getRequest('http_password', '') 593 ]; 594 $item = prepareItemHttpAgentFormData($http_item) + $item; 595 } 596 597 if ($preprocessing) { 598 $item['preprocessing'] = $preprocessing; 599 } 600 601 $item['tags'] = $tags; 602 603 $result = API::ItemPrototype()->create($item); 604 } 605 } 606 607 $result = DBend($result); 608 609 if (hasRequest('add')) { 610 show_messages($result, _('Item prototype added'), _('Cannot add item prototype')); 611 } 612 else { 613 show_messages($result, _('Item prototype updated'), _('Cannot update item prototype')); 614 } 615 616 if ($result) { 617 unset($_REQUEST['itemid'], $_REQUEST['form']); 618 uncheckTableRows(getRequest('parent_discoveryid')); 619 } 620} 621elseif (hasRequest('action') && hasRequest('group_itemid') 622 && str_in_array(getRequest('action'), ['itemprototype.massenable', 'itemprototype.massdisable'])) { 623 $itemids = getRequest('group_itemid'); 624 $status = (getRequest('action') == 'itemprototype.massenable') ? ITEM_STATUS_ACTIVE : ITEM_STATUS_DISABLED; 625 626 $item_prototypes = []; 627 foreach ($itemids as $itemid) { 628 $item_prototypes[] = ['itemid' => $itemid, 'status' => $status]; 629 } 630 631 $result = (bool) API::ItemPrototype()->update($item_prototypes); 632 633 if ($result) { 634 uncheckTableRows(getRequest('parent_discoveryid')); 635 } 636 637 $updated = count($itemids); 638 639 $messageSuccess = _n('Item prototype updated', 'Item prototypes updated', $updated); 640 $messageFailed = _n('Cannot update item prototype', 'Cannot update item prototypes', $updated); 641 642 show_messages($result, $messageSuccess, $messageFailed); 643} 644elseif (hasRequest('action') && getRequest('action') === 'itemprototype.massdelete' && hasRequest('group_itemid')) { 645 DBstart(); 646 647 $result = API::ItemPrototype()->delete(getRequest('group_itemid')); 648 $result = DBend($result); 649 650 if ($result) { 651 uncheckTableRows(getRequest('parent_discoveryid')); 652 } 653 show_messages($result, _('Item prototypes deleted'), _('Cannot delete item prototypes')); 654} 655elseif (hasRequest('action') && hasRequest('group_itemid') 656 && in_array(getRequest('action'), ['itemprototype.massdiscover.enable', 'itemprototype.massdiscover.disable'])) { 657 $itemids = getRequest('group_itemid'); 658 $discover = (getRequest('action') == 'itemprototype.massdiscover.enable') ? ITEM_DISCOVER : ITEM_NO_DISCOVER; 659 660 $item_prototypes = []; 661 foreach ($itemids as $itemid) { 662 $item_prototypes[] = ['itemid' => $itemid, 'discover' => $discover]; 663 } 664 665 $result = (bool) API::ItemPrototype()->update($item_prototypes); 666 667 if ($result) { 668 uncheckTableRows(getRequest('parent_discoveryid')); 669 } 670 671 $updated = count($itemids); 672 673 $messageSuccess = _n('Item prototype updated', 'Item prototypes updated', $updated); 674 $messageFailed = _n('Cannot update item prototype', 'Cannot update item prototypes', $updated); 675 676 show_messages($result, $messageSuccess, $messageFailed); 677} 678 679/* 680 * Display 681 */ 682if (hasRequest('form') || (hasRequest('clone') && getRequest('itemid') != 0)) { 683 $itemPrototype = []; 684 $has_errors = false; 685 686 if (hasRequest('itemid') && !hasRequest('clone')) { 687 $itemPrototype = API::ItemPrototype()->get([ 688 'itemids' => getRequest('itemid'), 689 'output' => [ 690 'itemid', 'type', 'snmp_oid', 'hostid', 'name', 'key_', 'delay', 'history', 'trends', 'status', 691 'value_type', 'trapper_hosts', 'units', 'logtimefmt', 'templateid', 'valuemapid', 'params', 692 'ipmi_sensor', 'authtype', 'username', 'password', 'publickey', 'privatekey', 'interfaceid', 693 'description', 'jmx_endpoint', 'master_itemid', 'timeout', 'url', 'query_fields', 'parameters', 'posts', 694 'status_codes', 'follow_redirects', 'post_type', 'http_proxy', 'headers', 'retrieve_mode', 695 'request_method', 'output_format', 'ssl_cert_file', 'ssl_key_file', 'ssl_key_password', 'verify_peer', 696 'verify_host', 'allow_traps', 'discover' 697 ], 698 'selectDiscoveryRule' => ['itemid', 'templateid'], 699 'selectPreprocessing' => ['type', 'params', 'error_handler', 'error_handler_params'], 700 'selectTags' => ['tag', 'value'] 701 ]); 702 $itemPrototype = reset($itemPrototype); 703 704 foreach ($itemPrototype['preprocessing'] as &$step) { 705 if ($step['type'] == ZBX_PREPROC_SCRIPT) { 706 $step['params'] = [$step['params'], '']; 707 } 708 else { 709 $step['params'] = explode("\n", $step['params']); 710 } 711 } 712 unset($step); 713 714 if ($itemPrototype['type'] != ITEM_TYPE_JMX) { 715 $itemPrototype['jmx_endpoint'] = ZBX_DEFAULT_JMX_ENDPOINT; 716 } 717 718 if (getRequest('type', $itemPrototype['type']) == ITEM_TYPE_DEPENDENT) { 719 $master_prototypes = API::Item()->get([ 720 'output' => ['itemid', 'hostid', 'name', 'key_'], 721 'itemids' => [getRequest('master_itemid', $itemPrototype['master_itemid'])], 722 'hostids' => [$itemPrototype['hostid']], 723 'webitems' => true 724 ]) 725 + API::ItemPrototype()->get([ 726 'output' => ['itemid', 'hostid', 'name', 'key_'], 727 'itemids' => getRequest('master_itemid', $itemPrototype['master_itemid']) 728 ]); 729 730 if ($master_prototypes) { 731 $itemPrototype['master_item'] = reset($master_prototypes); 732 } 733 } 734 } 735 elseif (getRequest('master_itemid')) { 736 $master_prototypes = API::Item()->get([ 737 'output' => ['itemid', 'hostid', 'name', 'key_'], 738 'itemids' => getRequest('master_itemid'), 739 'webitems' => true 740 ]) 741 + API::ItemPrototype()->get([ 742 'output' => ['itemid', 'hostid', 'name', 'key_'], 743 'itemids' => getRequest('master_itemid') 744 ]); 745 746 if ($master_prototypes) { 747 $itemPrototype['master_item'] = reset($master_prototypes); 748 } 749 else { 750 show_messages(false, '', _('No permissions to referred object or it does not exist!')); 751 $has_errors = true; 752 } 753 } 754 755 $form_action = (hasRequest('clone') && getRequest('itemid') != 0) ? 'clone' : getRequest('form'); 756 $data = getItemFormData($itemPrototype, ['form' => $form_action]); 757 $data['preprocessing_test_type'] = CControllerPopupItemTestEdit::ZBX_TEST_TYPE_ITEM_PROTOTYPE; 758 $data['preprocessing_types'] = CItemPrototype::SUPPORTED_PREPROCESSING_TYPES; 759 $data['trends_default'] = DB::getDefault('items', 'trends'); 760 761 $data['display_interfaces'] = $data['hostid'] 762 ? (bool) API::Host()->get([ 763 'countOutput' => true, 764 'hostids' => $data['hostid'], 765 'filter' => [ 766 'status' => [HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED] 767 ] 768 ]) 769 : false; 770 771 $history_in_seconds = timeUnitToSeconds($data['history']); 772 if (!getRequest('form_refresh') && $history_in_seconds !== null && $history_in_seconds == ITEM_NO_STORAGE_VALUE) { 773 $data['history_mode'] = getRequest('history_mode', ITEM_STORAGE_OFF); 774 $data['history'] = DB::getDefault('items', 'history'); 775 } 776 else { 777 $data['history_mode'] = getRequest('history_mode', ITEM_STORAGE_CUSTOM); 778 } 779 780 $trends_in_seconds = timeUnitToSeconds($data['trends']); 781 if (!getRequest('form_refresh') && $trends_in_seconds !== null && $trends_in_seconds == ITEM_NO_STORAGE_VALUE) { 782 $data['trends_mode'] = getRequest('trends_mode', ITEM_STORAGE_OFF); 783 $data['trends'] = $data['trends_default']; 784 } 785 else { 786 $data['trends_mode'] = getRequest('trends_mode', ITEM_STORAGE_CUSTOM); 787 } 788 789 // render view 790 if (!$has_errors) { 791 echo (new CView('configuration.item.prototype.edit', $data))->getOutput(); 792 } 793} 794else { 795 $prefix = (getRequest('context') === 'host') ? 'web.hosts.' : 'web.templates.'; 796 797 $sortField = getRequest('sort', CProfile::get($prefix.$page['file'].'.sort', 'name')); 798 $sortOrder = getRequest('sortorder', CProfile::get($prefix.$page['file'].'.sortorder', ZBX_SORT_UP)); 799 800 CProfile::update($prefix.$page['file'].'.sort', $sortField, PROFILE_TYPE_STR); 801 CProfile::update($prefix.$page['file'].'.sortorder', $sortOrder, PROFILE_TYPE_STR); 802 803 $data = [ 804 'form' => getRequest('form'), 805 'parent_discoveryid' => getRequest('parent_discoveryid'), 806 'hostid' => $discoveryRule['hostid'], 807 'sort' => $sortField, 808 'sortorder' => $sortOrder, 809 'context' => getRequest('context') 810 ]; 811 812 $limit = CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1; 813 $data['items'] = API::ItemPrototype()->get([ 814 'discoveryids' => $data['parent_discoveryid'], 815 'output' => API_OUTPUT_EXTEND, 816 'editable' => true, 817 'selectTags' => ['tag', 'value'], 818 'sortfield' => $sortField, 819 'limit' => $limit 820 ]); 821 822 $data['items'] = expandItemNamesWithMasterItems($data['items'], 'itemprototypes'); 823 824 switch ($sortField) { 825 case 'delay': 826 orderItemsByDelay($data['items'], $sortOrder, ['usermacros' => true, 'lldmacros' => true]); 827 break; 828 829 case 'history': 830 orderItemsByHistory($data['items'], $sortOrder); 831 break; 832 833 case 'trends': 834 orderItemsByTrends($data['items'], $sortOrder); 835 break; 836 837 default: 838 order_result($data['items'], $sortField, $sortOrder); 839 } 840 841 // pager 842 if (hasRequest('page')) { 843 $page_num = getRequest('page'); 844 } 845 elseif (isRequestMethod('get') && !hasRequest('cancel')) { 846 $page_num = 1; 847 } 848 else { 849 $page_num = CPagerHelper::loadPage($page['file']); 850 } 851 852 CPagerHelper::savePage($page['file'], $page_num); 853 854 $data['paging'] = CPagerHelper::paginate($page_num, $data['items'], $sortOrder, 855 (new CUrl('disc_prototypes.php')) 856 ->setArgument('parent_discoveryid', $data['parent_discoveryid']) 857 ->setArgument('context', $data['context']) 858 ); 859 860 $data['parent_templates'] = getItemParentTemplates($data['items'], ZBX_FLAG_DISCOVERY_PROTOTYPE); 861 $data['allowed_ui_conf_templates'] = CWebUser::checkAccess(CRoleHelper::UI_CONFIGURATION_TEMPLATES); 862 863 $data['tags'] = makeTags($data['items'], true, 'itemid', ZBX_TAG_COUNT_DEFAULT); 864 865 // render view 866 echo (new CView('configuration.item.prototype.list', $data))->getOutput(); 867} 868 869require_once dirname(__FILE__).'/include/page_footer.php'; 870