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' 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 _('Update interval') 61 ], 62 'delay_flex' => [T_ZBX_STR, O_OPT, null, null, null], 63 'status' => [T_ZBX_INT, O_OPT, null, IN([ITEM_STATUS_ACTIVE, ITEM_STATUS_DISABLED]), null], 64 'discover' => [T_ZBX_INT, O_OPT, null, IN([ZBX_PROTOTYPE_DISCOVER, ZBX_PROTOTYPE_NO_DISCOVER]), null], 65 'type' => [T_ZBX_INT, O_OPT, null, 66 IN([-1, ITEM_TYPE_ZABBIX, ITEM_TYPE_TRAPPER, ITEM_TYPE_SIMPLE, 67 ITEM_TYPE_INTERNAL, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_AGGREGATE, 68 ITEM_TYPE_EXTERNAL, ITEM_TYPE_DB_MONITOR, ITEM_TYPE_IPMI, ITEM_TYPE_SSH, 69 ITEM_TYPE_TELNET, ITEM_TYPE_JMX, ITEM_TYPE_CALCULATED, ITEM_TYPE_SNMPTRAP, 70 ITEM_TYPE_DEPENDENT, ITEM_TYPE_HTTPAGENT, ITEM_TYPE_SNMP 71 ]), 72 'isset({add}) || isset({update})' 73 ], 74 'value_type' => [T_ZBX_INT, O_OPT, null, IN('0,1,2,3,4'), 'isset({add}) || isset({update})'], 75 'valuemapid' => [T_ZBX_INT, O_OPT, null, DB_ID, 76 '(isset({add}) || isset({update})) && isset({value_type})'. 77 ' && '.IN(ITEM_VALUE_TYPE_FLOAT.','.ITEM_VALUE_TYPE_UINT64, 'value_type') 78 ], 79 'authtype' => [T_ZBX_INT, O_OPT, null, IN(ITEM_AUTHTYPE_PASSWORD.','.ITEM_AUTHTYPE_PUBLICKEY), 80 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_SSH 81 ], 82 'username' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 83 '(isset({add}) || isset({update})) && isset({type})'. 84 ' && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_TELNET, 'type'), 85 _('User name') 86 ], 87 'password' => [T_ZBX_STR, O_OPT, null, null, 88 '(isset({add}) || isset({update})) && isset({type})'. 89 ' && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_TELNET, 'type') 90 ], 91 'publickey' => [T_ZBX_STR, O_OPT, null, null, 92 '(isset({add}) || isset({update})) && isset({type})'. 93 ' && {type} == '.ITEM_TYPE_SSH.' && {authtype} == '.ITEM_AUTHTYPE_PUBLICKEY 94 ], 95 'privatekey' => [T_ZBX_STR, O_OPT, null, null, 96 '(isset({add}) || isset({update})) && isset({type})'. 97 ' && {type} == '.ITEM_TYPE_SSH.' && {authtype} == '.ITEM_AUTHTYPE_PUBLICKEY 98 ], 99 $paramsFieldName => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 100 '(isset({add}) || isset({update})) && isset({type})'. 101 ' && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_DB_MONITOR.','.ITEM_TYPE_TELNET.','. 102 ITEM_TYPE_CALCULATED, 'type' 103 ), 104 getParamFieldLabelByType(getRequest('type', 0)) 105 ], 106 'snmp_oid' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 107 '(isset({add}) || isset({update})) && isset({type})'. 108 ' && {type} == '.ITEM_TYPE_SNMP, 109 _('SNMP OID') 110 ], 111 'ipmi_sensor' => [T_ZBX_STR, O_OPT, P_NO_TRIM, null, 112 '(isset({add}) || isset({update})) && isset({type})'. 113 ' && {type} == '.ITEM_TYPE_IPMI, 114 _('IPMI sensor') 115 ], 116 'trapper_hosts' => [T_ZBX_STR, O_OPT, null, null, 117 '(isset({add}) || isset({update})) && isset({type})'. 118 ' && {type} == '.ITEM_TYPE_TRAPPER 119 ], 120 'units' => [T_ZBX_STR, O_OPT, null, null, 121 '(isset({add}) || isset({update})) && isset({value_type})'. 122 ' && '.IN(ITEM_VALUE_TYPE_FLOAT.','.ITEM_VALUE_TYPE_UINT64, 'value_type') 123 ], 124 'logtimefmt' => [T_ZBX_STR, O_OPT, null, null, 125 '(isset({add}) || isset({update})) && isset({value_type})'. 126 ' && {value_type} == '.ITEM_VALUE_TYPE_LOG 127 ], 128 'preprocessing' => [T_ZBX_STR, O_OPT, P_NO_TRIM, null, null], 129 'group_itemid' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 130 'new_application' => [T_ZBX_STR, O_OPT, null, null, 'isset({add}) || isset({update})'], 131 'new_application_prototype' => [T_ZBX_STR, O_OPT, null, null, 132 '(isset({add}) || isset({update})) && isset({parent_discoveryid})' 133 ], 134 'applications' => [T_ZBX_STR, O_OPT, null, null, null], 135 'application_prototypes' => [T_ZBX_STR, O_OPT, null, null, null], 136 'massupdate_app_action' => [T_ZBX_INT, O_OPT, null, 137 IN([ZBX_ACTION_ADD, ZBX_ACTION_REPLACE, ZBX_ACTION_REMOVE]), 138 null 139 ], 140 'massupdate_app_prot_action' => [T_ZBX_INT, O_OPT, null, 141 IN([ZBX_ACTION_ADD, ZBX_ACTION_REPLACE, ZBX_ACTION_REMOVE]), 142 null 143 ], 144 'history_mode' => [T_ZBX_INT, O_OPT, null, IN([ITEM_STORAGE_OFF, ITEM_STORAGE_CUSTOM]), null], 145 'history' => [T_ZBX_STR, O_OPT, null, null, 146 '(isset({add}) || isset({update}))'. 147 ' && isset({history_mode}) && {history_mode}=='.ITEM_STORAGE_CUSTOM, 148 _('History storage period') 149 ], 150 'trends_mode' => [T_ZBX_INT, O_OPT, null, IN([ITEM_STORAGE_OFF, ITEM_STORAGE_CUSTOM]), null], 151 'trends' => [T_ZBX_STR, O_OPT, null, null, 152 '(isset({add}) || isset({update}))'. 153 ' && isset({trends_mode}) && {trends_mode}=='.ITEM_STORAGE_CUSTOM. 154 ' && isset({value_type})'. 155 ' && '.IN(ITEM_VALUE_TYPE_FLOAT.','.ITEM_VALUE_TYPE_UINT64, 'value_type'), 156 _('Trend storage period') 157 ], 158 'jmx_endpoint' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 159 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_JMX 160 ], 161 'timeout' => [T_ZBX_TU, O_OPT, P_ALLOW_USER_MACRO|P_ALLOW_LLD_MACRO, null, 162 '(isset({add}) || isset({update})) && isset({type})'. 163 ' && {type} == '.ITEM_TYPE_HTTPAGENT, 164 _('Timeout') 165 ], 166 'url' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 167 '(isset({add}) || isset({update})) && isset({type})'. 168 ' && {type} == '.ITEM_TYPE_HTTPAGENT, 169 _('URL') 170 ], 171 'query_fields' => [T_ZBX_STR, O_OPT, null, null, null], 172 'posts' => [T_ZBX_STR, O_OPT, null, null, null], 173 'status_codes' => [T_ZBX_STR, O_OPT, null, null, null], 174 'follow_redirects' => [T_ZBX_INT, O_OPT, null, 175 IN([HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF, HTTPTEST_STEP_FOLLOW_REDIRECTS_ON]), 176 null 177 ], 178 'post_type' => [T_ZBX_INT, O_OPT, null, 179 IN([ZBX_POSTTYPE_RAW, ZBX_POSTTYPE_JSON, ZBX_POSTTYPE_XML]), 180 null 181 ], 182 'http_proxy' => [T_ZBX_STR, O_OPT, null, null, null], 183 'headers' => [T_ZBX_STR, O_OPT, null, null, null], 184 'retrieve_mode' => [T_ZBX_INT, O_OPT, null, 185 IN([HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, HTTPTEST_STEP_RETRIEVE_MODE_HEADERS, 186 HTTPTEST_STEP_RETRIEVE_MODE_BOTH 187 ]), 188 null 189 ], 190 'request_method' => [T_ZBX_INT, O_OPT, null, 191 IN([HTTPCHECK_REQUEST_GET, HTTPCHECK_REQUEST_POST, HTTPCHECK_REQUEST_PUT, 192 HTTPCHECK_REQUEST_HEAD 193 ]), 194 null 195 ], 196 'output_format' => [T_ZBX_INT, O_OPT, null, IN([HTTPCHECK_STORE_RAW, HTTPCHECK_STORE_JSON]), null], 197 'allow_traps' => [T_ZBX_INT, O_OPT, null, 198 IN([HTTPCHECK_ALLOW_TRAPS_OFF, HTTPCHECK_ALLOW_TRAPS_ON]), 199 null 200 ], 201 'ssl_cert_file' => [T_ZBX_STR, O_OPT, null, null, null], 202 'ssl_key_file' => [T_ZBX_STR, O_OPT, null, null, null], 203 'ssl_key_password' => [T_ZBX_STR, O_OPT, null, null, null], 204 'verify_peer' => [T_ZBX_INT, O_OPT, null, 205 IN([HTTPTEST_VERIFY_PEER_OFF, HTTPTEST_VERIFY_PEER_ON]), 206 null 207 ], 208 'verify_host' => [T_ZBX_INT, O_OPT, null, 209 IN([HTTPTEST_VERIFY_HOST_OFF, HTTPTEST_VERIFY_HOST_ON]), 210 null 211 ], 212 'http_authtype' => [T_ZBX_INT, O_OPT, null, 213 IN([HTTPTEST_AUTH_NONE, HTTPTEST_AUTH_BASIC, HTTPTEST_AUTH_NTLM, 214 HTTPTEST_AUTH_KERBEROS 215 ]), 216 null 217 ], 218 'http_username' => [T_ZBX_STR, O_OPT, null, null, 219 '(isset({add}) || isset({update})) && isset({http_authtype})'. 220 ' && ({http_authtype} == '.HTTPTEST_AUTH_BASIC. 221 ' || {http_authtype} == '.HTTPTEST_AUTH_NTLM. 222 ' || {http_authtype} == '.HTTPTEST_AUTH_KERBEROS. 223 ')', 224 _('Username') 225 ], 226 'http_password' => [T_ZBX_STR, O_OPT, null, null, 227 '(isset({add}) || isset({update})) && isset({http_authtype})'. 228 ' && ({http_authtype} == '.HTTPTEST_AUTH_BASIC. 229 ' || {http_authtype} == '.HTTPTEST_AUTH_NTLM. 230 ' || {http_authtype} == '.HTTPTEST_AUTH_KERBEROS. 231 ')', 232 _('Password') 233 ], 234 'visible' => [T_ZBX_STR, O_OPT, null, null, null], 235 // actions 236 'action' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, 237 IN('"itemprototype.massdelete","itemprototype.massdisable",'. 238 '"itemprototype.massenable","itemprototype.massupdateform"' 239 ), 240 null 241 ], 242 'add' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 243 'update' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 244 'clone' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 245 'delete' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 246 'massupdate' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 247 'cancel' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 248 'form' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 249 'form_refresh' => [T_ZBX_INT, O_OPT, null, null, null], 250 // filter 251 'filter_set' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 252 // sort and sortorder 253 'sort' => [T_ZBX_STR, O_OPT, P_SYS, 254 IN('"delay","history","key_","name","status","trends","type","discover"'), null 255 ], 256 'sortorder' => [T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'), null] 257]; 258$valid_input = check_fields($fields); 259 260$_REQUEST['params'] = getRequest($paramsFieldName, ''); 261unset($_REQUEST[$paramsFieldName]); 262 263// permissions 264$discoveryRule = API::DiscoveryRule()->get([ 265 'output' => ['hostid'], 266 'itemids' => getRequest('parent_discoveryid'), 267 'editable' => true 268]); 269$discoveryRule = reset($discoveryRule); 270if (!$discoveryRule) { 271 access_deny(); 272} 273 274$itemPrototypeId = getRequest('itemid'); 275if ($itemPrototypeId) { 276 $item_prorotypes = API::ItemPrototype()->get([ 277 'output' => [], 278 'itemids' => $itemPrototypeId, 279 'editable' => true 280 ]); 281 282 if (!$item_prorotypes) { 283 access_deny(); 284 } 285} 286 287// Convert CR+LF to LF in preprocessing script. 288if (hasRequest('preprocessing')) { 289 foreach ($_REQUEST['preprocessing'] as &$step) { 290 if ($step['type'] == ZBX_PREPROC_SCRIPT) { 291 $step['params'][0] = CRLFtoLF($step['params'][0]); 292 } 293 } 294 unset($step); 295} 296 297/* 298 * Actions 299 */ 300if (hasRequest('delete') && hasRequest('itemid')) { 301 DBstart(); 302 $result = API::ItemPrototype()->delete([getRequest('itemid')]); 303 $result = DBend($result); 304 305 if ($result) { 306 uncheckTableRows(getRequest('parent_discoveryid')); 307 } 308 show_messages($result, _('Item prototype deleted'), _('Cannot delete item prototype')); 309 310 unset($_REQUEST['itemid'], $_REQUEST['form']); 311} 312elseif (isset($_REQUEST['clone']) && isset($_REQUEST['itemid'])) { 313 unset($_REQUEST['itemid']); 314 $_REQUEST['form'] = 'clone'; 315} 316elseif (hasRequest('add') || hasRequest('update')) { 317 $applications = getRequest('applications', []); 318 $application = reset($applications); 319 if ($application == 0) { 320 array_shift($applications); 321 } 322 323 $result = true; 324 DBstart(); 325 326 if (!zbx_empty($_REQUEST['new_application'])) { 327 $new_appid = API::Application()->create([ 328 'name' => $_REQUEST['new_application'], 329 'hostid' => $discoveryRule['hostid'] 330 ]); 331 if ($new_appid) { 332 $new_appid = reset($new_appid['applicationids']); 333 $applications[$new_appid] = $new_appid; 334 } 335 else { 336 $result = false; 337 } 338 } 339 340 $delay = getRequest('delay', DB::getDefault('items', 'delay')); 341 $type = getRequest('type', ITEM_TYPE_ZABBIX); 342 343 /* 344 * "delay_flex" is a temporary field that collects flexible and scheduling intervals separated by a semicolon. 345 * In the end, custom intervals together with "delay" are stored in the "delay" variable. 346 */ 347 if ($type != ITEM_TYPE_TRAPPER && $type != ITEM_TYPE_SNMPTRAP && hasRequest('delay_flex')) { 348 $intervals = []; 349 $simple_interval_parser = new CSimpleIntervalParser([ 350 'usermacros' => true, 351 'lldmacros' => true 352 ]); 353 $time_period_parser = new CTimePeriodParser([ 354 'usermacros' => true, 355 'lldmacros' => true 356 ]); 357 $scheduling_interval_parser = new CSchedulingIntervalParser([ 358 'usermacros' => true, 359 'lldmacros' => true 360 ]); 361 362 foreach (getRequest('delay_flex') as $interval) { 363 if ($interval['type'] == ITEM_DELAY_FLEXIBLE) { 364 if ($interval['delay'] === '' && $interval['period'] === '') { 365 continue; 366 } 367 368 if ($simple_interval_parser->parse($interval['delay']) != CParser::PARSE_SUCCESS) { 369 $result = false; 370 info(_s('Invalid interval "%1$s".', $interval['delay'])); 371 break; 372 } 373 elseif ($time_period_parser->parse($interval['period']) != CParser::PARSE_SUCCESS) { 374 $result = false; 375 info(_s('Invalid interval "%1$s".', $interval['period'])); 376 break; 377 } 378 379 $intervals[] = $interval['delay'].'/'.$interval['period']; 380 } 381 else { 382 if ($interval['schedule'] === '') { 383 continue; 384 } 385 386 if ($scheduling_interval_parser->parse($interval['schedule']) != CParser::PARSE_SUCCESS) { 387 $result = false; 388 info(_s('Invalid interval "%1$s".', $interval['schedule'])); 389 break; 390 } 391 392 $intervals[] = $interval['schedule']; 393 } 394 } 395 396 if ($intervals) { 397 $delay .= ';'.implode(';', $intervals); 398 } 399 } 400 401 if ($result) { 402 $application_prototypes = getRequest('application_prototypes', []); 403 $application_prototype = reset($application_prototypes); 404 405 if ($application_prototype === '0') { 406 array_shift($application_prototypes); 407 } 408 409 if ($application_prototypes) { 410 foreach ($application_prototypes as &$application_prototype) { 411 $application_prototype = ['name' => $application_prototype]; 412 } 413 unset($application_prototype); 414 } 415 416 $new_application_prototype = getRequest('new_application_prototype', ''); 417 if ($new_application_prototype !== '') { 418 $application_prototypes[] = ['name' => $new_application_prototype]; 419 } 420 421 $preprocessing = getRequest('preprocessing', []); 422 423 foreach ($preprocessing as &$step) { 424 switch ($step['type']) { 425 case ZBX_PREPROC_MULTIPLIER: 426 case ZBX_PREPROC_PROMETHEUS_TO_JSON: 427 $step['params'] = trim($step['params'][0]); 428 break; 429 430 case ZBX_PREPROC_RTRIM: 431 case ZBX_PREPROC_LTRIM: 432 case ZBX_PREPROC_TRIM: 433 case ZBX_PREPROC_XPATH: 434 case ZBX_PREPROC_JSONPATH: 435 case ZBX_PREPROC_VALIDATE_REGEX: 436 case ZBX_PREPROC_VALIDATE_NOT_REGEX: 437 case ZBX_PREPROC_ERROR_FIELD_JSON: 438 case ZBX_PREPROC_ERROR_FIELD_XML: 439 case ZBX_PREPROC_THROTTLE_TIMED_VALUE: 440 case ZBX_PREPROC_SCRIPT: 441 $step['params'] = $step['params'][0]; 442 break; 443 444 case ZBX_PREPROC_VALIDATE_RANGE: 445 case ZBX_PREPROC_PROMETHEUS_PATTERN: 446 foreach ($step['params'] as &$param) { 447 $param = trim($param); 448 } 449 unset($param); 450 451 $step['params'] = implode("\n", $step['params']); 452 break; 453 454 case ZBX_PREPROC_REGSUB: 455 case ZBX_PREPROC_ERROR_FIELD_REGEX: 456 case ZBX_PREPROC_STR_REPLACE: 457 $step['params'] = implode("\n", $step['params']); 458 break; 459 460 // ZBX-16642 461 case ZBX_PREPROC_CSV_TO_JSON: 462 if (!array_key_exists(2, $step['params'])) { 463 $step['params'][2] = ZBX_PREPROC_CSV_NO_HEADER; 464 } 465 $step['params'] = implode("\n", $step['params']); 466 break; 467 468 default: 469 $step['params'] = ''; 470 } 471 472 $step += [ 473 'error_handler' => ZBX_PREPROC_FAIL_DEFAULT, 474 'error_handler_params' => '' 475 ]; 476 } 477 unset($step); 478 479 $item = [ 480 'name' => getRequest('name'), 481 'description' => getRequest('description'), 482 'key_' => getRequest('key'), 483 'hostid' => $discoveryRule['hostid'], 484 'interfaceid' => getRequest('interfaceid'), 485 'delay' => $delay, 486 'status' => getRequest('status', ITEM_STATUS_DISABLED), 487 'discover' => getRequest('discover', ZBX_PROTOTYPE_DISCOVER), 488 'type' => getRequest('type'), 489 'snmp_oid' => getRequest('snmp_oid'), 490 'value_type' => getRequest('value_type'), 491 'trapper_hosts' => getRequest('trapper_hosts'), 492 'history' => (getRequest('history_mode', ITEM_STORAGE_CUSTOM) == ITEM_STORAGE_OFF) 493 ? ITEM_NO_STORAGE_VALUE 494 : getRequest('history'), 495 'units' => getRequest('units'), 496 'logtimefmt' => getRequest('logtimefmt'), 497 'valuemapid' => getRequest('valuemapid'), 498 'authtype' => getRequest('authtype'), 499 'username' => getRequest('username'), 500 'password' => getRequest('password'), 501 'publickey' => getRequest('publickey'), 502 'privatekey' => getRequest('privatekey'), 503 'params' => getRequest('params'), 504 'ipmi_sensor' => getRequest('ipmi_sensor'), 505 'ruleid' => getRequest('parent_discoveryid') 506 ]; 507 508 if ($item['type'] == ITEM_TYPE_JMX) { 509 $item['jmx_endpoint'] = getRequest('jmx_endpoint', ''); 510 } 511 512 if ($item['value_type'] == ITEM_VALUE_TYPE_FLOAT || $item['value_type'] == ITEM_VALUE_TYPE_UINT64) { 513 $item['trends'] = (getRequest('trends_mode', ITEM_STORAGE_CUSTOM) == ITEM_STORAGE_OFF) 514 ? ITEM_NO_STORAGE_VALUE 515 : getRequest('trends'); 516 } 517 518 if ($item['type'] == ITEM_TYPE_DEPENDENT) { 519 $item['master_itemid'] = getRequest('master_itemid'); 520 } 521 522 if (hasRequest('update')) { 523 $itemId = getRequest('itemid'); 524 525 $db_item = API::ItemPrototype()->get([ 526 'output' => ['type', 'snmp_oid', 'hostid', 'name', 'key_', 'delay', 'history', 527 'trends', 'status', 'value_type', 'trapper_hosts', 'units', 528 'logtimefmt', 'templateid', 'valuemapid', 'params', 'ipmi_sensor', 'authtype', 'username', 529 'password', 'publickey', 'privatekey', 'interfaceid', 'description', 'jmx_endpoint', 530 'master_itemid', 'timeout', 'url', 'query_fields', 'posts', 'status_codes', 'follow_redirects', 531 'post_type', 'http_proxy', 'headers', 'retrieve_mode', 'request_method', 'output_format', 532 'ssl_cert_file', 'ssl_key_file', 'ssl_key_password', 'verify_peer', 'verify_host', 'allow_traps', 533 'discover' 534 ], 535 'selectApplications' => ['applicationid'], 536 'selectApplicationPrototypes' => ['name'], 537 'selectPreprocessing' => ['type', 'params', 'error_handler', 'error_handler_params'], 538 'itemids' => [$itemId] 539 ]); 540 541 $db_item = $db_item[0]; 542 543 if ($item['type'] == ITEM_TYPE_HTTPAGENT) { 544 $http_item = [ 545 'timeout' => getRequest('timeout', DB::getDefault('items', 'timeout')), 546 'url' => getRequest('url'), 547 'query_fields' => getRequest('query_fields', []), 548 'posts' => getRequest('posts'), 549 'status_codes' => getRequest('status_codes', DB::getDefault('items', 'status_codes')), 550 'follow_redirects' => (int) getRequest('follow_redirects'), 551 'post_type' => (int) getRequest('post_type'), 552 'http_proxy' => getRequest('http_proxy'), 553 'headers' => getRequest('headers', []), 554 'retrieve_mode' => (int) getRequest('retrieve_mode'), 555 'request_method' => (int) getRequest('request_method'), 556 'output_format' => (int) getRequest('output_format'), 557 'allow_traps' => (int) getRequest('allow_traps', HTTPCHECK_ALLOW_TRAPS_OFF), 558 'ssl_cert_file' => getRequest('ssl_cert_file'), 559 'ssl_key_file' => getRequest('ssl_key_file'), 560 'ssl_key_password' => getRequest('ssl_key_password'), 561 'verify_peer' => (int) getRequest('verify_peer'), 562 'verify_host' => (int) getRequest('verify_host'), 563 'authtype' => getRequest('http_authtype', HTTPTEST_AUTH_NONE), 564 'username' => getRequest('http_username', ''), 565 'password' => getRequest('http_password', '') 566 ]; 567 $item = prepareItemHttpAgentFormData($http_item) + $item; 568 } 569 570 $item = CArrayHelper::unsetEqualValues($item, $db_item); 571 $item['itemid'] = $itemId; 572 573 $db_item['applications'] = zbx_objectValues($db_item['applications'], 'applicationid'); 574 575 // compare applications 576 natsort($db_item['applications']); 577 natsort($applications); 578 579 if (array_values($db_item['applications']) !== array_values($applications)) { 580 $item['applications'] = $applications; 581 } 582 583 // compare application prototypes 584 $db_application_prototype_names = zbx_objectValues($db_item['applicationPrototypes'], 'name'); 585 natsort($db_application_prototype_names); 586 587 $application_prototype_names = zbx_objectValues($application_prototypes, 'name'); 588 natsort($application_prototype_names); 589 590 if (array_values($db_application_prototype_names) !== array_values($application_prototype_names)) { 591 $item['applicationPrototypes'] = $application_prototypes; 592 } 593 594 if ($db_item['preprocessing'] !== $preprocessing) { 595 $item['preprocessing'] = $preprocessing; 596 } 597 598 $result = API::ItemPrototype()->update($item); 599 } 600 else { 601 $item['applications'] = $applications; 602 $item['applicationPrototypes'] = $application_prototypes; 603 604 if (getRequest('type') == ITEM_TYPE_HTTPAGENT) { 605 $http_item = [ 606 'timeout' => getRequest('timeout', DB::getDefault('items', 'timeout')), 607 'url' => getRequest('url'), 608 'query_fields' => getRequest('query_fields', []), 609 'posts' => getRequest('posts'), 610 'status_codes' => getRequest('status_codes', DB::getDefault('items', 'status_codes')), 611 'follow_redirects' => (int) getRequest('follow_redirects'), 612 'post_type' => (int) getRequest('post_type'), 613 'http_proxy' => getRequest('http_proxy'), 614 'headers' => getRequest('headers', []), 615 'retrieve_mode' => (int) getRequest('retrieve_mode'), 616 'request_method' => (int) getRequest('request_method'), 617 'output_format' => (int) getRequest('output_format'), 618 'allow_traps' => (int) getRequest('allow_traps', HTTPCHECK_ALLOW_TRAPS_OFF), 619 'ssl_cert_file' => getRequest('ssl_cert_file'), 620 'ssl_key_file' => getRequest('ssl_key_file'), 621 'ssl_key_password' => getRequest('ssl_key_password'), 622 'verify_peer' => (int) getRequest('verify_peer'), 623 'verify_host' => (int) getRequest('verify_host'), 624 'authtype' => getRequest('http_authtype', HTTPTEST_AUTH_NONE), 625 'username' => getRequest('http_username', ''), 626 'password' => getRequest('http_password', '') 627 ]; 628 $item = prepareItemHttpAgentFormData($http_item) + $item; 629 } 630 631 if ($preprocessing) { 632 $item['preprocessing'] = $preprocessing; 633 } 634 635 $result = API::ItemPrototype()->create($item); 636 } 637 } 638 639 $result = DBend($result); 640 641 if (hasRequest('add')) { 642 show_messages($result, _('Item prototype added'), _('Cannot add item prototype')); 643 } 644 else { 645 show_messages($result, _('Item prototype updated'), _('Cannot update item prototype')); 646 } 647 648 if ($result) { 649 unset($_REQUEST['itemid'], $_REQUEST['form']); 650 uncheckTableRows(getRequest('parent_discoveryid')); 651 } 652} 653elseif (hasRequest('action') && hasRequest('group_itemid') 654 && str_in_array(getRequest('action'), ['itemprototype.massenable', 'itemprototype.massdisable'])) { 655 $itemids = getRequest('group_itemid'); 656 $status = (getRequest('action') == 'itemprototype.massenable') ? ITEM_STATUS_ACTIVE : ITEM_STATUS_DISABLED; 657 658 $item_prototypes = []; 659 foreach ($itemids as $itemid) { 660 $item_prototypes[] = ['itemid' => $itemid, 'status' => $status]; 661 } 662 663 $result = (bool) API::ItemPrototype()->update($item_prototypes); 664 665 if ($result) { 666 uncheckTableRows(getRequest('parent_discoveryid')); 667 } 668 669 $updated = count($itemids); 670 671 $messageSuccess = _n('Item prototype updated', 'Item prototypes updated', $updated); 672 $messageFailed = _n('Cannot update item prototype', 'Cannot update item prototypes', $updated); 673 674 show_messages($result, $messageSuccess, $messageFailed); 675} 676elseif (hasRequest('action') && getRequest('action') === 'itemprototype.massdelete' && hasRequest('group_itemid')) { 677 DBstart(); 678 679 $result = API::ItemPrototype()->delete(getRequest('group_itemid')); 680 $result = DBend($result); 681 682 if ($result) { 683 uncheckTableRows(getRequest('parent_discoveryid')); 684 } 685 show_messages($result, _('Item prototypes deleted'), _('Cannot delete item prototypes')); 686} 687elseif ($valid_input && hasRequest('massupdate') && hasRequest('group_itemid')) { 688 $visible = getRequest('visible', []); 689 $item_prototypeids = getRequest('group_itemid'); 690 $result = true; 691 692 $applications = getRequest('applications', []); 693 $applicationids = []; 694 695 $application_prototypes = getRequest('application_prototypes', []); 696 $application_prototypeids = []; 697 698 if (isset($visible['delay'])) { 699 $delay = getRequest('delay', DB::getDefault('items', 'delay')); 700 701 if (hasRequest('delay_flex')) { 702 $intervals = []; 703 $simple_interval_parser = new CSimpleIntervalParser(['usermacros' => true]); 704 $time_period_parser = new CTimePeriodParser(['usermacros' => true]); 705 $scheduling_interval_parser = new CSchedulingIntervalParser(['usermacros' => true]); 706 707 foreach (getRequest('delay_flex') as $interval) { 708 if ($interval['type'] == ITEM_DELAY_FLEXIBLE) { 709 if ($interval['delay'] === '' && $interval['period'] === '') { 710 continue; 711 } 712 713 if ($simple_interval_parser->parse($interval['delay']) != CParser::PARSE_SUCCESS) { 714 $result = false; 715 info(_s('Invalid interval "%1$s".', $interval['delay'])); 716 break; 717 } 718 elseif ($time_period_parser->parse($interval['period']) != CParser::PARSE_SUCCESS) { 719 $result = false; 720 info(_s('Invalid interval "%1$s".', $interval['period'])); 721 break; 722 } 723 724 $intervals[] = $interval['delay'].'/'.$interval['period']; 725 } 726 else { 727 if ($interval['schedule'] === '') { 728 continue; 729 } 730 731 if ($scheduling_interval_parser->parse($interval['schedule']) != CParser::PARSE_SUCCESS) { 732 $result = false; 733 info(_s('Invalid interval "%1$s".', $interval['schedule'])); 734 break; 735 } 736 737 $intervals[] = $interval['schedule']; 738 } 739 } 740 741 if ($intervals) { 742 $delay .= ';'.implode(';', $intervals); 743 } 744 } 745 } 746 else { 747 $delay = null; 748 } 749 750 if ($result) { 751 try { 752 DBstart(); 753 754 // Collect submitted applications and create new applications if necessary. 755 if (array_key_exists('applications', $visible)) { 756 $massupdate_app_action = getRequest('massupdate_app_action'); 757 758 if ($massupdate_app_action == ZBX_ACTION_ADD || $massupdate_app_action == ZBX_ACTION_REPLACE) { 759 $new_applications = []; 760 761 foreach ($applications as $application) { 762 if (is_array($application) && array_key_exists('new', $application)) { 763 $new_applications[] = [ 764 'name' => $application['new'], 765 'hostid' => getRequest('hostid') 766 ]; 767 } 768 else { 769 $applicationids[] = $application; 770 } 771 } 772 773 if ($new_applications) { 774 if ($new_application = API::Application()->create($new_applications)) { 775 $applicationids = array_merge($applicationids, $new_application['applicationids']); 776 } 777 else { 778 throw new Exception(); 779 } 780 } 781 } 782 else { 783 foreach ($applications as $application) { 784 $applicationids[] = $application; 785 } 786 } 787 } 788 789 // Collect submitted application prototypes. 790 if (array_key_exists('applicationPrototypes', $visible)) { 791 $massupdate_app_prot_action = getRequest('massupdate_app_prot_action'); 792 793 if ($massupdate_app_prot_action == ZBX_ACTION_ADD 794 || $massupdate_app_prot_action == ZBX_ACTION_REPLACE) { 795 $new_application_prototypes = []; 796 797 foreach ($application_prototypes as $application_prototype) { 798 if (is_array($application_prototype) && array_key_exists('new', $application_prototype)) { 799 $new_application_prototypes[] = [ 800 'name' => $application_prototype['new'] 801 ]; 802 } 803 else { 804 $application_prototypeids[] = $application_prototype; 805 } 806 } 807 } 808 else { 809 foreach ($application_prototypes as $application_prototype) { 810 $application_prototypeids[] = $application_prototype; 811 } 812 } 813 } 814 815 $item_prototypes = API::ItemPrototype()->get([ 816 'output' => ['itemid', 'type'], 817 'selectApplications' => ['applicationid'], 818 'selectApplicationPrototypes' => ['application_prototypeid', 'name'], 819 'itemids' => $item_prototypeids, 820 'preservekeys' => true 821 ]); 822 823 $item_prototypes_to_update = []; 824 825 if ($item_prototypes) { 826 $item_prototype = [ 827 'interfaceid' => getRequest('interfaceid'), 828 'description' => getRequest('description'), 829 'delay' => $delay, 830 'history' => (getRequest('history_mode', ITEM_STORAGE_CUSTOM) == ITEM_STORAGE_OFF) 831 ? ITEM_NO_STORAGE_VALUE 832 : getRequest('history'), 833 'type' => getRequest('type'), 834 'snmp_oid' => getRequest('snmp_oid'), 835 'value_type' => getRequest('value_type'), 836 'trapper_hosts' => getRequest('trapper_hosts'), 837 'units' => getRequest('units'), 838 'trends' => (getRequest('trends_mode', ITEM_STORAGE_CUSTOM) == ITEM_STORAGE_OFF) 839 ? ITEM_NO_STORAGE_VALUE 840 : getRequest('trends'), 841 'logtimefmt' => getRequest('logtimefmt'), 842 'valuemapid' => getRequest('valuemapid'), 843 'authtype' => getRequest('authtype'), 844 'jmx_endpoint' => getRequest('jmx_endpoint'), 845 'username' => getRequest('username'), 846 'password' => getRequest('password'), 847 'publickey' => getRequest('publickey'), 848 'privatekey' => getRequest('privatekey'), 849 'applications' => [], 850 'applicationPrototypes' => [], 851 'status' => getRequest('status'), 852 'discover' => getRequest('discover'), 853 'master_itemid' => getRequest('master_itemid'), 854 'url' => getRequest('url'), 855 'post_type' => getRequest('post_type'), 856 'posts' => getRequest('posts'), 857 'headers' => getRequest('headers', []), 858 'allow_traps' => getRequest('allow_traps', HTTPCHECK_ALLOW_TRAPS_OFF), 859 'preprocessing' => [] 860 ]; 861 862 if ($item_prototype['headers']) { 863 $headers = []; 864 865 foreach ($item_prototype['headers']['name'] as $index => $key) { 866 if (array_key_exists($index, $item_prototype['headers']['value'])) { 867 $headers[$key] = $item_prototype['headers']['value'][$index]; 868 } 869 } 870 871 // Ignore single row if it is empty. 872 if (count($headers) == 1 && $key === '' && $item_prototype['headers']['value'][$index] === '') { 873 $headers = []; 874 } 875 876 $item_prototype['headers'] = $headers; 877 } 878 879 if (hasRequest('preprocessing')) { 880 $preprocessing = getRequest('preprocessing'); 881 882 foreach ($preprocessing as &$step) { 883 switch ($step['type']) { 884 case ZBX_PREPROC_MULTIPLIER: 885 case ZBX_PREPROC_PROMETHEUS_TO_JSON: 886 $step['params'] = trim($step['params'][0]); 887 break; 888 889 case ZBX_PREPROC_RTRIM: 890 case ZBX_PREPROC_LTRIM: 891 case ZBX_PREPROC_TRIM: 892 case ZBX_PREPROC_XPATH: 893 case ZBX_PREPROC_JSONPATH: 894 case ZBX_PREPROC_VALIDATE_REGEX: 895 case ZBX_PREPROC_VALIDATE_NOT_REGEX: 896 case ZBX_PREPROC_ERROR_FIELD_JSON: 897 case ZBX_PREPROC_ERROR_FIELD_XML: 898 case ZBX_PREPROC_THROTTLE_TIMED_VALUE: 899 case ZBX_PREPROC_SCRIPT: 900 $step['params'] = $step['params'][0]; 901 break; 902 903 case ZBX_PREPROC_VALIDATE_RANGE: 904 case ZBX_PREPROC_PROMETHEUS_PATTERN: 905 foreach ($step['params'] as &$param) { 906 $param = trim($param); 907 } 908 unset($param); 909 910 $step['params'] = implode("\n", $step['params']); 911 break; 912 913 case ZBX_PREPROC_REGSUB: 914 case ZBX_PREPROC_ERROR_FIELD_REGEX: 915 case ZBX_PREPROC_STR_REPLACE: 916 $step['params'] = implode("\n", $step['params']); 917 break; 918 919 // ZBX-16642 920 case ZBX_PREPROC_CSV_TO_JSON: 921 if (!array_key_exists(2, $step['params'])) { 922 $step['params'][2] = ZBX_PREPROC_CSV_NO_HEADER; 923 } 924 $step['params'] = implode("\n", $step['params']); 925 break; 926 927 default: 928 $step['params'] = ''; 929 } 930 931 $step += [ 932 'error_handler' => ZBX_PREPROC_FAIL_DEFAULT, 933 'error_handler_params' => '' 934 ]; 935 } 936 unset($step); 937 938 $item_prototype['preprocessing'] = $preprocessing; 939 } 940 941 // Check "visible" for differences and update only necessary fields. 942 $item_prototype = array_intersect_key($item_prototype, $visible); 943 944 foreach ($item_prototypeids as $item_prototypeid) { 945 if (array_key_exists($item_prototypeid, $item_prototypes)) { 946 if ($item_prototype) { 947 // Process applications. 948 if (array_key_exists('applications', $visible)) { 949 if ($applicationids) { 950 // If there are existing applications submitted. 951 $db_applicationids = zbx_objectValues( 952 $item_prototypes[$item_prototypeid]['applications'], 953 'applicationid' 954 ); 955 956 switch ($massupdate_app_action) { 957 case ZBX_ACTION_ADD: 958 $upd_applicationids = array_merge($applicationids, $db_applicationids); 959 break; 960 961 case ZBX_ACTION_REPLACE: 962 $upd_applicationids = $applicationids; 963 break; 964 965 case ZBX_ACTION_REMOVE: 966 $upd_applicationids = array_diff($db_applicationids, $applicationids); 967 break; 968 } 969 970 /* 971 * $upd_applicationids now contains new and existing application IDs depending on 972 * operation we want to perform. 973 */ 974 $item_prototype['applications'] = array_keys(array_flip($upd_applicationids)); 975 } 976 else { 977 /* 978 * No applications were submitted in form. In case we want to replace applications, 979 * leave $item['applications'] empty, remove it otherwise. 980 */ 981 if ($massupdate_app_action == ZBX_ACTION_ADD 982 || $massupdate_app_action == ZBX_ACTION_REMOVE) { 983 unset($item_prototype['applications']); 984 } 985 } 986 } 987 988 // Process application prototypes. 989 if (array_key_exists('applicationPrototypes', $visible)) { 990 $ex_application_prototypes 991 = $item_prototypes[$item_prototypeid]['applicationPrototypes']; 992 $ex_application_prototypeids = zbx_objectValues($ex_application_prototypes, 993 'application_prototypeid' 994 ); 995 $upd_application_prototypeids = []; 996 $application_prototypes = []; 997 998 switch ($massupdate_app_prot_action) { 999 case ZBX_ACTION_ADD: 1000 // Append submitted existing application prototypes. 1001 if ($application_prototypeids) { 1002 $upd_application_prototypeids = array_unique( 1003 array_merge($application_prototypeids, $ex_application_prototypeids) 1004 ); 1005 } 1006 1007 // Append new application prototypes. 1008 if ($new_application_prototypes) { 1009 foreach ($new_application_prototypes as $new_application_prototype) { 1010 if (!in_array($new_application_prototype['name'], 1011 zbx_objectValues($application_prototypes, 'name'))) { 1012 $application_prototypes[] = $new_application_prototype; 1013 } 1014 } 1015 } 1016 1017 // Append already existing application prototypes so that they are not deleted. 1018 if (($upd_application_prototypeids || $new_application_prototypes) 1019 && $ex_application_prototypes) { 1020 foreach ($ex_application_prototypes as $db_application_prototype) { 1021 $application_prototypes[] = $db_application_prototype; 1022 } 1023 } 1024 break; 1025 1026 case ZBX_ACTION_REPLACE: 1027 if ($application_prototypeids) { 1028 $upd_application_prototypeids = $application_prototypeids; 1029 } 1030 1031 if ($new_application_prototypes) { 1032 foreach ($new_application_prototypes as $new_application_prototype) { 1033 if (!in_array($new_application_prototype['name'], 1034 zbx_objectValues($application_prototypes, 'name'))) { 1035 $application_prototypes[] = $new_application_prototype; 1036 } 1037 } 1038 } 1039 break; 1040 1041 case ZBX_ACTION_REMOVE: 1042 if ($application_prototypeids) { 1043 $upd_application_prototypeids = array_diff($ex_application_prototypeids, 1044 $application_prototypeids 1045 ); 1046 } 1047 break; 1048 } 1049 1050 /* 1051 * There might be added an existing application prototype that belongs to the discovery 1052 * rule, not just chosen application prototypes ($ex_application_prototypes). 1053 */ 1054 if ($upd_application_prototypeids) { 1055 // Collect existing application prototype names. Those are required by API. 1056 $db_application_prototypes = DBfetchArray(DBselect( 1057 'SELECT ap.application_prototypeid,ap.name'. 1058 ' FROM application_prototype ap'. 1059 ' WHERE '.dbConditionId('ap.application_prototypeid', 1060 $upd_application_prototypeids 1061 ) 1062 )); 1063 1064 // Append those application prototypes to update list. 1065 foreach ($db_application_prototypes as $db_application_prototype) { 1066 if (!in_array($db_application_prototype['application_prototypeid'], 1067 zbx_objectValues($application_prototypes, 1068 'application_prototypeid'))) { 1069 $application_prototypes[] = $db_application_prototype; 1070 } 1071 } 1072 } 1073 1074 if ($application_prototypes) { 1075 $item_prototype['applicationPrototypes'] = $application_prototypes; 1076 } 1077 else { 1078 if ($massupdate_app_prot_action == ZBX_ACTION_REPLACE) { 1079 $item_prototype['applicationPrototypes'] = []; 1080 } 1081 else { 1082 unset($item_prototype['applicationPrototypes']); 1083 } 1084 } 1085 } 1086 1087 $item_prototypes_to_update[] = ['itemid' => $item_prototypeid] + $item_prototype; 1088 } 1089 } 1090 } 1091 } 1092 1093 if ($item_prototypes_to_update) { 1094 foreach ($item_prototypes_to_update as &$update_item_prototype) { 1095 $type = array_key_exists('type', $update_item_prototype) 1096 ? $update_item_prototype['type'] 1097 : $item_prototypes[$update_item_prototype['itemid']]['type']; 1098 1099 if ($type != ITEM_TYPE_JMX) { 1100 unset($update_item_prototype['jmx_endpoint']); 1101 } 1102 } 1103 unset($update_item_prototype); 1104 1105 $result = API::ItemPrototype()->update($item_prototypes_to_update); 1106 } 1107 } 1108 catch (Exception $e) { 1109 $result = false; 1110 } 1111 1112 $result = DBend($result); 1113 } 1114 1115 if ($result) { 1116 unset($_REQUEST['group_itemid'], $_REQUEST['massupdate'], $_REQUEST['form']); 1117 uncheckTableRows(getRequest('parent_discoveryid')); 1118 } 1119 show_messages($result, _('Item prototypes updated'), _('Cannot update item prototypes')); 1120} 1121 1122if (hasRequest('action') && getRequest('action') !== 'itemprototype.massupdateform' && hasRequest('group_itemid') 1123 && !$result) { 1124 $item_prototypes = API::ItemPrototype()->get([ 1125 'itemids' => getRequest('group_itemid'), 1126 'output' => [], 1127 'editable' => true 1128 ]); 1129 uncheckTableRows(getRequest('parent_discoveryid'), zbx_objectValues($item_prototypes, 'itemid')); 1130} 1131 1132/* 1133 * Display 1134 */ 1135if (isset($_REQUEST['form'])) { 1136 $itemPrototype = []; 1137 $has_errors = false; 1138 1139 if (hasRequest('itemid')) { 1140 $itemPrototype = API::ItemPrototype()->get([ 1141 'itemids' => getRequest('itemid'), 1142 'output' => [ 1143 'itemid', 'type', 'snmp_oid', 'hostid', 'name', 'key_', 'delay', 'history', 1144 'trends', 'status', 'value_type', 'trapper_hosts', 'units', 'logtimefmt', 'templateid', 1145 'valuemapid', 'params', 'ipmi_sensor', 'authtype', 'username', 'password', 'publickey', 'privatekey', 1146 'interfaceid', 'description', 'jmx_endpoint', 'master_itemid', 'timeout', 'url', 'query_fields', 1147 'posts', 'status_codes', 'follow_redirects', 'post_type', 'http_proxy', 'headers', 'retrieve_mode', 1148 'request_method', 'output_format', 'ssl_cert_file', 'ssl_key_file', 'ssl_key_password', 1149 'verify_peer', 'verify_host', 'allow_traps', 'discover' 1150 ], 1151 'selectPreprocessing' => ['type', 'params', 'error_handler', 'error_handler_params'] 1152 ]); 1153 $itemPrototype = reset($itemPrototype); 1154 1155 foreach ($itemPrototype['preprocessing'] as &$step) { 1156 if ($step['type'] == ZBX_PREPROC_SCRIPT) { 1157 $step['params'] = [$step['params'], '']; 1158 } 1159 else { 1160 $step['params'] = explode("\n", $step['params']); 1161 } 1162 } 1163 unset($step); 1164 1165 if ($itemPrototype['type'] != ITEM_TYPE_JMX) { 1166 $itemPrototype['jmx_endpoint'] = ZBX_DEFAULT_JMX_ENDPOINT; 1167 } 1168 1169 if (getRequest('type', $itemPrototype['type']) == ITEM_TYPE_DEPENDENT) { 1170 $master_prototypes = API::Item()->get([ 1171 'output' => ['itemid', 'hostid', 'name', 'key_'], 1172 'itemids' => [getRequest('master_itemid', $itemPrototype['master_itemid'])], 1173 'hostids' => [$itemPrototype['hostid']], 1174 'webitems' => true 1175 ]) 1176 + API::ItemPrototype()->get([ 1177 'output' => ['itemid', 'hostid', 'name', 'key_'], 1178 'itemids' => getRequest('master_itemid', $itemPrototype['master_itemid']) 1179 ]); 1180 1181 if ($master_prototypes) { 1182 $itemPrototype['master_item'] = reset($master_prototypes); 1183 } 1184 } 1185 } 1186 elseif (getRequest('master_itemid')) { 1187 $master_prototypes = API::Item()->get([ 1188 'output' => ['itemid', 'hostid', 'name', 'key_'], 1189 'itemids' => getRequest('master_itemid'), 1190 'webitems' => true 1191 ]) 1192 + API::ItemPrototype()->get([ 1193 'output' => ['itemid', 'hostid', 'name', 'key_'], 1194 'itemids' => getRequest('master_itemid') 1195 ]); 1196 1197 if ($master_prototypes) { 1198 $itemPrototype['master_item'] = reset($master_prototypes); 1199 } 1200 else { 1201 show_messages(false, '', _('No permissions to referred object or it does not exist!')); 1202 $has_errors = true; 1203 } 1204 } 1205 1206 $data = getItemFormData($itemPrototype); 1207 $data['config'] = select_config(); 1208 $data['preprocessing_test_type'] = CControllerPopupItemTestEdit::ZBX_TEST_TYPE_ITEM_PROTOTYPE; 1209 $data['preprocessing_types'] = CItemPrototype::$supported_preprocessing_types; 1210 $data['trends_default'] = DB::getDefault('items', 'trends'); 1211 1212 $history_in_seconds = timeUnitToSeconds($data['history']); 1213 if (!getRequest('form_refresh') && $history_in_seconds !== null && $history_in_seconds == ITEM_NO_STORAGE_VALUE) { 1214 $data['history_mode'] = getRequest('history_mode', ITEM_STORAGE_OFF); 1215 $data['history'] = DB::getDefault('items', 'history'); 1216 } 1217 else { 1218 $data['history_mode'] = getRequest('history_mode', ITEM_STORAGE_CUSTOM); 1219 } 1220 1221 $trends_in_seconds = timeUnitToSeconds($data['trends']); 1222 if (!getRequest('form_refresh') && $trends_in_seconds !== null && $trends_in_seconds == ITEM_NO_STORAGE_VALUE) { 1223 $data['trends_mode'] = getRequest('trends_mode', ITEM_STORAGE_OFF); 1224 $data['trends'] = $data['trends_default']; 1225 } 1226 else { 1227 $data['trends_mode'] = getRequest('trends_mode', ITEM_STORAGE_CUSTOM); 1228 } 1229 1230 // render view 1231 if (!$has_errors) { 1232 echo (new CView('configuration.item.prototype.edit', $data))->getOutput(); 1233 } 1234} 1235elseif (((hasRequest('action') && getRequest('action') === 'itemprototype.massupdateform') || hasRequest('massupdate')) 1236 && hasRequest('group_itemid')) { 1237 $data = [ 1238 'form' => getRequest('form'), 1239 'action' => 'itemprototype.massupdateform', 1240 'hostid' => getRequest('hostid', 0), 1241 'parent_discoveryid' => getRequest('parent_discoveryid'), 1242 'item_prototypeids' => getRequest('group_itemid', []), 1243 'description' => getRequest('description', ''), 1244 'delay' => getRequest('delay', ZBX_ITEM_DELAY_DEFAULT), 1245 'delay_flex' => getRequest('delay_flex', []), 1246 'history' => getRequest('history', DB::getDefault('items', 'history')), 1247 'status' => getRequest('status', 0), 1248 'discover' => getRequest('discover', DB::getDefault('items', 'discover')), 1249 'type' => getRequest('type', 0), 1250 'interfaceid' => getRequest('interfaceid', 0), 1251 'value_type' => getRequest('value_type', ITEM_VALUE_TYPE_UINT64), 1252 'trapper_hosts' => getRequest('trapper_hosts', ''), 1253 'units' => getRequest('units', ''), 1254 'authtype' => getRequest('authtype', ''), 1255 'jmx_endpoint' => getRequest('jmx_endpoint', ''), 1256 'username' => getRequest('username', ''), 1257 'password' => getRequest('password', ''), 1258 'publickey' => getRequest('publickey', ''), 1259 'privatekey' => getRequest('privatekey', ''), 1260 'valuemapid' => getRequest('valuemapid', 0), 1261 'trends' => getRequest('trends', DB::getDefault('items', 'trends')), 1262 'applications' => [], 1263 'application_prototypes' => [], 1264 'logtimefmt' => getRequest('logtimefmt', ''), 1265 'preprocessing' => getRequest('preprocessing', []), 1266 'initial_item_type' => null, 1267 'multiple_interface_types' => false, 1268 'visible' => getRequest('visible', []), 1269 'master_itemid' => getRequest('master_itemid', 0), 1270 'url' => getRequest('url', ''), 1271 'post_type' => getRequest('post_type', DB::getDefault('items', 'post_type')), 1272 'posts' => getRequest('posts', ''), 1273 'headers' => getRequest('headers', []), 1274 'allow_traps' => getRequest('allow_traps', HTTPCHECK_ALLOW_TRAPS_OFF), 1275 'massupdate_app_action' => getRequest('massupdate_app_action', ZBX_ACTION_ADD), 1276 'massupdate_app_prot_action' => getRequest('massupdate_app_prot_action', ZBX_ACTION_ADD), 1277 'preprocessing_test_type' => CControllerPopupItemTestEdit::ZBX_TEST_TYPE_ITEM_PROTOTYPE, 1278 'preprocessing_types' => CItemPrototype::$supported_preprocessing_types, 1279 'preprocessing_script_maxlength' => DB::getFieldLength('item_preproc', 'params') 1280 ]; 1281 1282 foreach ($data['preprocessing'] as &$step) { 1283 $step += [ 1284 'error_handler' => ZBX_PREPROC_FAIL_DEFAULT, 1285 'error_handler_params' => '' 1286 ]; 1287 } 1288 unset($step); 1289 1290 if (hasRequest('applications')) { 1291 $applicationids = []; 1292 1293 foreach (getRequest('applications') as $application) { 1294 if (is_array($application) && array_key_exists('new', $application)) { 1295 $data['applications'][] = [ 1296 'id' => $application['new'], 1297 'name' => $application['new'].' ('._x('new', 'new element in multiselect').')', 1298 'isNew' => true 1299 ]; 1300 } 1301 else { 1302 $applicationids[] = $application; 1303 } 1304 } 1305 1306 $data['applications'] = array_merge($data['applications'], $applicationids 1307 ? CArrayHelper::renameObjectsKeys(API::Application()->get([ 1308 'output' => ['applicationid', 'name'], 1309 'applicationids' => $applicationids 1310 ]), ['applicationid' => 'id']) 1311 : []); 1312 } 1313 1314 if (hasRequest('application_prototypes')) { 1315 $application_prototypeids = []; 1316 1317 foreach (getRequest('application_prototypes') as $application_prototype) { 1318 if (is_array($application_prototype) && array_key_exists('new', $application_prototype)) { 1319 $data['application_prototypes'][] = [ 1320 'id' => $application_prototype['new'], 1321 'name' => $application_prototype['new'].' ('._x('new', 'new element in multiselect').')', 1322 'isNew' => true 1323 ]; 1324 } 1325 else { 1326 $application_prototypeids[] = $application_prototype; 1327 } 1328 } 1329 1330 $data['application_prototypes'] = array_merge($data['application_prototypes'], $application_prototypeids 1331 ? CArrayHelper::renameObjectsKeys( 1332 DBfetchArray(DBselect( 1333 'SELECT ap.application_prototypeid,ap.name'. 1334 ' FROM application_prototype ap'. 1335 ' WHERE '.dbConditionId('ap.application_prototypeid', $application_prototypeids) 1336 )), ['application_prototypeid' => 'id']) 1337 : []); 1338 } 1339 1340 if ($data['headers']) { 1341 $headers = []; 1342 1343 foreach ($data['headers']['name'] as $index => $key) { 1344 if (array_key_exists($index, $data['headers']['value'])) { 1345 $headers[] = [$key => $data['headers']['value'][$index]]; 1346 } 1347 } 1348 1349 // Ignore single row if it is empty. 1350 if (count($headers) == 1 && $key === '' && $data['headers']['value'][$index] === '') { 1351 $headers = []; 1352 } 1353 1354 $data['headers'] = $headers; 1355 } 1356 1357 // hosts 1358 $data['hosts'] = API::Host()->get([ 1359 'output' => ['hostid'], 1360 'itemids' => $data['item_prototypeids'], 1361 'selectInterfaces' => ['interfaceid', 'main', 'type', 'useip', 'ip', 'dns', 'port', 'details'] 1362 ]); 1363 1364 $data['display_interfaces'] = true; 1365 1366 $templates = API::Template()->get([ 1367 'output' => ['templateid'], 1368 'itemids' => $data['item_prototypeids'] 1369 ]); 1370 1371 if ($templates) { 1372 $data['display_interfaces'] = false; 1373 1374 if ($data['hostid'] == 0) { 1375 // If selected from filter without 'hostid'. 1376 $templates = reset($templates); 1377 $data['hostid'] = $templates['templateid']; 1378 } 1379 } 1380 1381 if ($data['display_interfaces']) { 1382 $data['hosts'] = reset($data['hosts']); 1383 1384 // Sort interfaces to be listed starting with one selected as 'main'. 1385 CArrayHelper::sort($data['hosts']['interfaces'], [ 1386 ['field' => 'main', 'order' => ZBX_SORT_DOWN] 1387 ]); 1388 1389 // If selected from filter without 'hostid'. 1390 if ($data['hostid'] == 0) { 1391 $data['hostid'] = $data['hosts']['hostid']; 1392 } 1393 1394 // Set the initial chosen interface to one of the interfaces the items use. 1395 $item_prototypes = API::ItemPrototype()->get([ 1396 'output' => ['itemid', 'type', 'name'], 1397 'itemids' => $data['item_prototypeids'] 1398 ]); 1399 $used_interface_types = []; 1400 1401 foreach ($item_prototypes as $item_prototype) { 1402 $used_interface_types[$item_prototype['type']] = itemTypeInterface($item_prototype['type']); 1403 } 1404 1405 $initial_type = min(array_keys($used_interface_types)); 1406 $data['type'] = (getRequest('type') !== null) ? $data['type'] : $initial_type; 1407 $data['initial_item_type'] = $initial_type; 1408 $data['multiple_interface_types'] = (count(array_unique($used_interface_types)) > 1); 1409 } 1410 1411 if ($data['master_itemid'] != 0) { 1412 $master_prototypes = API::Item()->get([ 1413 'output' => ['itemid', 'hostid', 'name', 'key_'], 1414 'selectHosts' => ['name'], 1415 'itemids' => [$data['master_itemid']], 1416 'hostids' => [$data['hostid']], 1417 'webitems' => true 1418 ]) 1419 + API::ItemPrototype()->get([ 1420 'output' => ['itemid', 'hostid', 'name', 'key_'], 1421 'selectHosts' => ['name'], 1422 'itemids' => getRequest('master_itemid', $data['master_itemid']) 1423 ]); 1424 1425 if ($master_prototypes) { 1426 $data['master_itemname'] = $master_prototypes[0]['name']; 1427 $data['master_hostname'] = $master_prototypes[0]['hosts'][0]['name']; 1428 } 1429 else { 1430 $data['master_itemid'] = 0; 1431 show_messages(false, '', _('No permissions to referred object or it does not exist!')); 1432 } 1433 } 1434 1435 // item types 1436 $data['itemTypes'] = item_type2str(); 1437 unset($data['itemTypes'][ITEM_TYPE_HTTPTEST]); 1438 1439 // valuemap 1440 $data['valuemaps'] = API::ValueMap()->get([ 1441 'output' => ['valuemapid', 'name'] 1442 ]); 1443 CArrayHelper::sort($data['valuemaps'], ['name']); 1444 1445 if (!$data['delay_flex']) { 1446 $data['delay_flex'][] = ['delay' => '', 'period' => '', 'type' => ITEM_DELAY_FLEXIBLE]; 1447 } 1448 1449 $data['jmx_endpoint'] = ZBX_DEFAULT_JMX_ENDPOINT; 1450 1451 $history_in_seconds = timeUnitToSeconds($data['history']); 1452 if (!getRequest('form_refresh') && $history_in_seconds !== null && $history_in_seconds == ITEM_NO_STORAGE_VALUE) { 1453 $data['history_mode'] = getRequest('history_mode', ITEM_STORAGE_OFF); 1454 $data['history'] = DB::getDefault('items', 'history'); 1455 } 1456 else { 1457 $data['history_mode'] = getRequest('history_mode', ITEM_STORAGE_CUSTOM); 1458 } 1459 1460 $trends_in_seconds = timeUnitToSeconds($data['trends']); 1461 if (!getRequest('form_refresh') && $trends_in_seconds !== null && $trends_in_seconds == ITEM_NO_STORAGE_VALUE) { 1462 $data['trends_mode'] = getRequest('trends_mode', ITEM_STORAGE_OFF); 1463 $data['trends'] = DB::getDefault('items', 'trends'); 1464 } 1465 else { 1466 $data['trends_mode'] = getRequest('trends_mode', ITEM_STORAGE_CUSTOM); 1467 } 1468 1469 echo (new CView('configuration.item.prototype.massupdate', $data))->getOutput(); 1470} 1471else { 1472 $sortField = getRequest('sort', CProfile::get('web.'.$page['file'].'.sort', 'name')); 1473 $sortOrder = getRequest('sortorder', CProfile::get('web.'.$page['file'].'.sortorder', ZBX_SORT_UP)); 1474 1475 CProfile::update('web.'.$page['file'].'.sort', $sortField, PROFILE_TYPE_STR); 1476 CProfile::update('web.'.$page['file'].'.sortorder', $sortOrder, PROFILE_TYPE_STR); 1477 1478 $config = select_config(); 1479 1480 $data = [ 1481 'form' => getRequest('form'), 1482 'parent_discoveryid' => getRequest('parent_discoveryid'), 1483 'hostid' => $discoveryRule['hostid'], 1484 'sort' => $sortField, 1485 'sortorder' => $sortOrder 1486 ]; 1487 1488 $data['items'] = API::ItemPrototype()->get([ 1489 'discoveryids' => $data['parent_discoveryid'], 1490 'output' => API_OUTPUT_EXTEND, 1491 'editable' => true, 1492 'selectApplications' => API_OUTPUT_EXTEND, 1493 'sortfield' => $sortField, 1494 'limit' => $config['search_limit'] + 1 1495 ]); 1496 1497 $data['items'] = expandItemNamesWithMasterItems($data['items'], 'itemprototypes'); 1498 1499 switch ($sortField) { 1500 case 'delay': 1501 orderItemsByDelay($data['items'], $sortOrder, ['usermacros' => true, 'lldmacros' => true]); 1502 break; 1503 1504 case 'history': 1505 orderItemsByHistory($data['items'], $sortOrder); 1506 break; 1507 1508 case 'trends': 1509 orderItemsByTrends($data['items'], $sortOrder); 1510 break; 1511 1512 default: 1513 order_result($data['items'], $sortField, $sortOrder); 1514 } 1515 1516 // pager 1517 if (hasRequest('page')) { 1518 $page_num = getRequest('page'); 1519 } 1520 elseif (isRequestMethod('get') && !hasRequest('cancel')) { 1521 $page_num = 1; 1522 } 1523 else { 1524 $page_num = CPagerHelper::loadPage($page['file']); 1525 } 1526 1527 CPagerHelper::savePage($page['file'], $page_num); 1528 1529 $data['paging'] = CPagerHelper::paginate($page_num, $data['items'], $sortOrder, 1530 (new CUrl('disc_prototypes.php'))->setArgument('parent_discoveryid', $data['parent_discoveryid']) 1531 ); 1532 1533 $data['parent_templates'] = getItemParentTemplates($data['items'], ZBX_FLAG_DISCOVERY_PROTOTYPE); 1534 1535 // render view 1536 echo (new CView('configuration.item.prototype.list', $data))->getOutput(); 1537} 1538 1539require_once dirname(__FILE__).'/include/page_footer.php'; 1540