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