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/forms.inc.php';
24
25$page['title'] = _('Configuration of hosts');
26$page['file'] = 'hosts.php';
27$page['type'] = detect_page_type(PAGE_TYPE_HTML);
28$page['scripts'] = ['multiselect.js', 'textareaflexible.js', 'class.cviewswitcher.js', 'class.cverticalaccordion.js',
29	'inputsecret.js', 'macrovalue.js', 'class.tab-indicators.js', 'class.tagfilteritem.js'
30];
31
32require_once dirname(__FILE__).'/include/page_header.php';
33
34// VAR	TYPE	OPTIONAL	FLAGS	VALIDATION	EXCEPTION
35$fields = [
36	'hosts' =>					[T_ZBX_INT, O_OPT, P_SYS,			DB_ID,		null],
37	'groups' =>					[T_ZBX_STR, O_OPT, null,			NOT_EMPTY,	'isset({add}) || isset({update})'],
38	'hostids' =>				[T_ZBX_INT, O_OPT, P_SYS,			DB_ID,		null],
39	'groupids' =>				[T_ZBX_INT, O_OPT, P_SYS,			DB_ID,		null],
40	'hostid' =>					[T_ZBX_INT, O_OPT, P_SYS,			DB_ID,		'isset({form}) && {form} == "update"'],
41	'clone_hostid' =>			[T_ZBX_INT, O_OPT, P_SYS,			DB_ID,
42									'isset({form}) && ({form} == "clone" || {form} == "full_clone")'
43								],
44	'host' =>					[T_ZBX_STR, O_OPT, null,			NOT_EMPTY,	'isset({add}) || isset({update})',
45									_('Host name')
46								],
47	'visiblename' =>			[T_ZBX_STR, O_OPT, null,			null,		'isset({add}) || isset({update})'],
48	'description' =>			[T_ZBX_STR, O_OPT, null,			null,		null],
49	'proxy_hostid' =>			[T_ZBX_INT, O_OPT, P_SYS,		    DB_ID,		null],
50	'status' =>					[T_ZBX_INT, O_OPT, null,
51									IN([HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED]), null
52								],
53	'interfaces' =>				[T_ZBX_STR, O_OPT, null,			null,		null],
54	'mainInterfaces' =>			[T_ZBX_INT, O_OPT, null,			DB_ID,		null],
55	'tags' =>					[T_ZBX_STR, O_OPT, null,			null,		null],
56	'templates' =>				[T_ZBX_INT, O_OPT, null,			DB_ID,		null],
57	'add_templates' =>			[T_ZBX_INT, O_OPT, null,			DB_ID,		null],
58	'templates_rem' =>			[T_ZBX_STR, O_OPT, P_SYS|P_ACT,		null,		null],
59	'clear_templates' =>		[T_ZBX_INT, O_OPT, null,			DB_ID,		null],
60	'ipmi_authtype' =>			[T_ZBX_INT, O_OPT, null,			BETWEEN(-1, 6), null],
61	'ipmi_privilege' =>			[T_ZBX_INT, O_OPT, null,			BETWEEN(0, 5), null],
62	'ipmi_username' =>			[T_ZBX_STR, O_OPT, null,			null,		null],
63	'ipmi_password' =>			[T_ZBX_STR, O_OPT, null,			null,		null],
64	'tls_connect' =>			[T_ZBX_INT, O_OPT, null,
65									IN([HOST_ENCRYPTION_NONE, HOST_ENCRYPTION_PSK, HOST_ENCRYPTION_CERTIFICATE]),
66									null
67								],
68	'tls_accept' =>				[T_ZBX_INT, O_OPT, null,
69									BETWEEN(0,
70										(HOST_ENCRYPTION_NONE | HOST_ENCRYPTION_PSK | HOST_ENCRYPTION_CERTIFICATE)
71									),
72									null
73								],
74	'tls_subject' =>			[T_ZBX_STR, O_OPT, null,			null,		null],
75	'tls_issuer' =>				[T_ZBX_STR, O_OPT, null,			null,		null],
76	'tls_psk_identity' =>		[T_ZBX_STR, O_OPT, null,			null,		null],
77	'tls_psk' =>				[T_ZBX_STR, O_OPT, null,			null,		null],
78	'psk_edit_mode' =>			[T_ZBX_INT, O_OPT, null,			IN([0,1]),	null],
79	'flags' =>					[T_ZBX_INT, O_OPT, null,
80									IN([ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_CREATED]), null
81								],
82	'inventory_mode' =>			[T_ZBX_INT, O_OPT, null,
83									IN(HOST_INVENTORY_DISABLED.','.HOST_INVENTORY_MANUAL.','.HOST_INVENTORY_AUTOMATIC),
84									null
85								],
86	'host_inventory' =>			[T_ZBX_STR, O_OPT, P_UNSET_EMPTY,	null,		null],
87	'macros' =>					[T_ZBX_STR, O_OPT, P_SYS,			null,		null],
88	'visible' =>				[T_ZBX_STR, O_OPT, null,			null,		null],
89	'show_inherited_macros' =>	[T_ZBX_INT, O_OPT, null, IN([0,1]), null],
90	'valuemaps' => 				[T_ZBX_STR, O_OPT, null,		null,	null],
91	// actions
92	'action' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT,
93									IN('"host.export","host.massdelete","host.massdisable", "host.massenable"'),
94									null
95								],
96	'unlink' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT,		null,		null],
97	'unlink_and_clear' =>		[T_ZBX_STR, O_OPT, P_SYS|P_ACT,		null,		null],
98	'add' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT,		null,		null],
99	'update' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT,		null,		null],
100	'clone' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT,		null,		null],
101	'full_clone' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT,		null,		null],
102	'delete' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT,		null,		null],
103	'cancel' =>					[T_ZBX_STR, O_OPT, P_SYS,			null,		null],
104	'form' =>					[T_ZBX_STR, O_OPT, P_SYS,			null,		null],
105	'form_refresh' =>			[T_ZBX_INT, O_OPT, null,			null,		null],
106	// filter
107	'filter_set' =>				[T_ZBX_STR, O_OPT, P_SYS,			null,		null],
108	'filter_rst' =>				[T_ZBX_STR, O_OPT, P_SYS,			null,		null],
109	'filter_host' =>			[T_ZBX_STR, O_OPT, null,			null,		null],
110	'filter_templates' =>		[T_ZBX_INT, O_OPT, null,			DB_ID,		null],
111	'filter_groups' =>			[T_ZBX_INT, O_OPT, null,			DB_ID,		null],
112	'filter_ip' =>				[T_ZBX_STR, O_OPT, null,			null,		null],
113	'filter_dns' =>				[T_ZBX_STR, O_OPT, null,			null,		null],
114	'filter_port' =>			[T_ZBX_STR, O_OPT, null,			null,		null],
115	'filter_monitored_by' =>	[T_ZBX_INT, O_OPT, null,
116									IN([ZBX_MONITORED_BY_ANY, ZBX_MONITORED_BY_SERVER, ZBX_MONITORED_BY_PROXY]),
117									null
118								],
119	'filter_proxyids' =>		[T_ZBX_INT, O_OPT, null,			DB_ID,		null],
120	'filter_evaltype' =>		[T_ZBX_INT, O_OPT, null,
121									IN([TAG_EVAL_TYPE_AND_OR, TAG_EVAL_TYPE_OR]),
122									null
123								],
124	'filter_tags' =>			[T_ZBX_STR, O_OPT, null,			null,		null],
125	// sort and sortorder
126	'sort' =>					[T_ZBX_STR, O_OPT, P_SYS, IN('"name","status"'),						null],
127	'sortorder' =>				[T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'),	null]
128];
129check_fields($fields);
130
131/*
132 * Permissions
133 */
134if (getRequest('hostid')) {
135	$hosts = API::Host()->get([
136		'output' => [],
137		'hostids' => getRequest('hostid'),
138		'editable' => true
139	]);
140
141	if (!$hosts) {
142		access_deny();
143	}
144}
145
146/*
147 * Filter
148 */
149if (hasRequest('filter_set')) {
150	CProfile::update('web.hosts.filter_ip', getRequest('filter_ip', ''), PROFILE_TYPE_STR);
151	CProfile::update('web.hosts.filter_dns', getRequest('filter_dns', ''), PROFILE_TYPE_STR);
152	CProfile::update('web.hosts.filter_host', getRequest('filter_host', ''), PROFILE_TYPE_STR);
153	CProfile::update('web.hosts.filter_port', getRequest('filter_port', ''), PROFILE_TYPE_STR);
154	CProfile::update('web.hosts.filter_monitored_by', getRequest('filter_monitored_by', ZBX_MONITORED_BY_ANY),
155		PROFILE_TYPE_INT
156	);
157	CProfile::updateArray('web.hosts.filter_templates', getRequest('filter_templates', []), PROFILE_TYPE_ID);
158	CProfile::updateArray('web.hosts.filter_groups', getRequest('filter_groups', []), PROFILE_TYPE_ID);
159	CProfile::updateArray('web.hosts.filter_proxyids', getRequest('filter_proxyids', []), PROFILE_TYPE_ID);
160	CProfile::update('web.hosts.filter.evaltype', getRequest('filter_evaltype', TAG_EVAL_TYPE_AND_OR),
161		PROFILE_TYPE_INT
162	);
163
164	$filter_tags = ['tags' => [], 'values' => [], 'operators' => []];
165	foreach (getRequest('filter_tags', []) as $filter_tag) {
166		if ($filter_tag['tag'] === '' && $filter_tag['value'] === '') {
167			continue;
168		}
169
170		$filter_tags['tags'][] = $filter_tag['tag'];
171		$filter_tags['values'][] = $filter_tag['value'];
172		$filter_tags['operators'][] = $filter_tag['operator'];
173	}
174	CProfile::updateArray('web.hosts.filter.tags.tag', $filter_tags['tags'], PROFILE_TYPE_STR);
175	CProfile::updateArray('web.hosts.filter.tags.value', $filter_tags['values'], PROFILE_TYPE_STR);
176	CProfile::updateArray('web.hosts.filter.tags.operator', $filter_tags['operators'], PROFILE_TYPE_INT);
177}
178elseif (hasRequest('filter_rst')) {
179	DBstart();
180	CProfile::delete('web.hosts.filter_ip');
181	CProfile::delete('web.hosts.filter_dns');
182	CProfile::delete('web.hosts.filter_host');
183	CProfile::delete('web.hosts.filter_port');
184	CProfile::delete('web.hosts.filter_monitored_by');
185	CProfile::deleteIdx('web.hosts.filter_templates');
186	CProfile::deleteIdx('web.hosts.filter_groups');
187	CProfile::deleteIdx('web.hosts.filter_proxyids');
188	CProfile::delete('web.hosts.filter.evaltype');
189	CProfile::deleteIdx('web.hosts.filter.tags.tag');
190	CProfile::deleteIdx('web.hosts.filter.tags.value');
191	CProfile::deleteIdx('web.hosts.filter.tags.operator');
192	DBend();
193}
194
195$filter = [
196	'ip' => CProfile::get('web.hosts.filter_ip', ''),
197	'dns' => CProfile::get('web.hosts.filter_dns', ''),
198	'host' => CProfile::get('web.hosts.filter_host', ''),
199	'templates' => CProfile::getArray('web.hosts.filter_templates', []),
200	'groups' => CProfile::getArray('web.hosts.filter_groups', []),
201	'port' => CProfile::get('web.hosts.filter_port', ''),
202	'monitored_by' => CProfile::get('web.hosts.filter_monitored_by', ZBX_MONITORED_BY_ANY),
203	'proxyids' => CProfile::getArray('web.hosts.filter_proxyids', []),
204	'evaltype' => CProfile::get('web.hosts.filter.evaltype', TAG_EVAL_TYPE_AND_OR),
205	'tags' => []
206];
207
208foreach (CProfile::getArray('web.hosts.filter.tags.tag', []) as $i => $tag) {
209	$filter['tags'][] = [
210		'tag' => $tag,
211		'value' => CProfile::get('web.hosts.filter.tags.value', null, $i),
212		'operator' => CProfile::get('web.hosts.filter.tags.operator', null, $i)
213	];
214}
215CArrayHelper::sort($filter['tags'], ['tag', 'value', 'operator']);
216
217$tags = getRequest('tags', []);
218foreach ($tags as $key => $tag) {
219	// remove empty new tag lines
220	if ($tag['tag'] === '' && $tag['value'] === '') {
221		unset($tags[$key]);
222		continue;
223	}
224
225	// remove inherited tags
226	if (array_key_exists('type', $tag) && !($tag['type'] & ZBX_PROPERTY_OWN)) {
227		unset($tags[$key]);
228	}
229	else {
230		unset($tags[$key]['type']);
231	}
232}
233
234// Remove inherited macros data (actions: 'add', 'update' and 'form').
235$macros = cleanInheritedMacros(getRequest('macros', []));
236
237// Remove empty new macro lines.
238$macros = array_filter($macros, function($macro) {
239	$keys = array_flip(['hostmacroid', 'macro', 'value', 'description']);
240
241	return (bool) array_filter(array_intersect_key($macro, $keys));
242});
243
244/*
245 * Actions
246 */
247if (hasRequest('unlink') || hasRequest('unlink_and_clear')) {
248	$_REQUEST['clear_templates'] = getRequest('clear_templates', []);
249
250	$unlinkTemplates = [];
251
252	if (isset($_REQUEST['unlink'])) {
253		// templates_rem for old style removal in massupdate form
254		if (isset($_REQUEST['templates_rem'])) {
255			$unlinkTemplates = array_keys($_REQUEST['templates_rem']);
256		}
257		elseif (is_array($_REQUEST['unlink'])) {
258			$unlinkTemplates = array_keys($_REQUEST['unlink']);
259		}
260	}
261	else {
262		$unlinkTemplates = array_keys($_REQUEST['unlink_and_clear']);
263
264		$_REQUEST['clear_templates'] = array_merge($_REQUEST['clear_templates'], $unlinkTemplates);
265	}
266
267	foreach ($unlinkTemplates as $templateId) {
268		unset($_REQUEST['templates'][array_search($templateId, $_REQUEST['templates'])]);
269	}
270}
271elseif (hasRequest('hostid') && (hasRequest('clone') || hasRequest('full_clone'))) {
272	$_REQUEST['form'] = hasRequest('clone') ? 'clone' : 'full_clone';
273
274	$groups = getRequest('groups', []);
275	$groupids = [];
276
277	// Remove inaccessible groups from request, but leave "new".
278	foreach ($groups as $group) {
279		if (!is_array($group)) {
280			$groupids[] = $group;
281		}
282	}
283
284	if ($groupids) {
285		$groups_allowed = API::HostGroup()->get([
286			'output' => [],
287			'groupids' => $groupids,
288			'editable' => true,
289			'preservekeys' => true
290		]);
291
292		foreach ($groups as $idx => $group) {
293			if (!is_array($group) && !array_key_exists($group, $groups_allowed)) {
294				unset($groups[$idx]);
295			}
296		}
297
298		$_REQUEST['groups'] = $groups;
299	}
300
301	if (hasRequest('interfaces')) {
302		$interfaceid = 1;
303		foreach ($_REQUEST['interfaces'] as &$interface) {
304			$interface['interfaceid'] = (string) $interfaceid++;
305			unset($interface['items']);
306		}
307		unset($interface);
308	}
309
310	if (hasRequest('clone') || hasRequest('full_clone')) {
311		$_REQUEST['clone_hostid'] = $_REQUEST['hostid'];
312	}
313
314	if ($macros && in_array(ZBX_MACRO_TYPE_SECRET, array_column($macros, 'type'))) {
315		// Reset macro type and value.
316		$macros = array_map(function($value) {
317			return ($value['type'] == ZBX_MACRO_TYPE_SECRET)
318				? ['value' => '', 'type' => ZBX_MACRO_TYPE_TEXT] + $value
319				: $value;
320		}, $macros);
321
322		warning(_('The cloned host contains user defined macros with type "Secret text". The value and type of these macros were reset.'));
323	}
324
325	$macros = array_map(function($macro) {
326		return array_diff_key($macro, array_flip(['hostmacroid']));
327	}, $macros);
328
329	unset($_REQUEST['hostid'], $_REQUEST['flags']);
330}
331elseif (hasRequest('add') || hasRequest('update')) {
332	try {
333		DBstart();
334
335		$hostId = getRequest('hostid', 0);
336
337		if ($hostId != 0) {
338			$create = false;
339
340			$msgOk = _('Host updated');
341			$msgFail = _('Cannot update host');
342
343			$dbHost = API::Host()->get([
344				'output' => ['hostid', 'host', 'name', 'status', 'description', 'proxy_hostid', 'ipmi_authtype',
345					'ipmi_privilege', 'ipmi_username', 'ipmi_password', 'tls_connect', 'tls_accept', 'tls_issuer',
346					'tls_subject', 'flags'
347				],
348				'hostids' => $hostId,
349				'editable' => true
350			]);
351			$dbHost = reset($dbHost);
352		}
353		else {
354			$create = true;
355
356			$msgOk = _('Host added');
357			$msgFail = _('Cannot add host');
358		}
359
360		// host data
361		if (!$create && $dbHost['flags'] == ZBX_FLAG_DISCOVERY_CREATED) {
362			$host = [
363				'hostid' => $hostId,
364				'status' => getRequest('status', HOST_STATUS_NOT_MONITORED),
365				'description' => getRequest('description', ''),
366				'inventory' => (getRequest('inventory_mode') == HOST_INVENTORY_DISABLED)
367					? []
368					: getRequest('host_inventory', [])
369			];
370		}
371		else {
372			// Linked templates.
373			$templates = [];
374
375			foreach (array_merge(getRequest('templates', []), getRequest('add_templates', [])) as $templateid) {
376				$templates[] = ['templateid' => $templateid];
377			}
378
379			// interfaces
380			$interfaces = getRequest('interfaces', []);
381
382			foreach ($interfaces as $key => $interface) {
383				// Process SNMP interface fields.
384				if ($interface['type'] == INTERFACE_TYPE_SNMP) {
385					if (!array_key_exists('details', $interface)) {
386						$interface['details'] = [];
387					}
388
389					$interfaces[$key]['details']['bulk'] = array_key_exists('bulk', $interface['details'])
390						? SNMP_BULK_ENABLED
391						: SNMP_BULK_DISABLED;
392				}
393
394				if ($interface['isNew']) {
395					unset($interfaces[$key]['interfaceid']);
396				}
397
398				unset($interfaces[$key]['isNew']);
399				$interfaces[$key]['main'] = 0;
400			}
401
402			$mainInterfaces = getRequest('mainInterfaces', []);
403			foreach ([INTERFACE_TYPE_AGENT, INTERFACE_TYPE_SNMP, INTERFACE_TYPE_JMX, INTERFACE_TYPE_IPMI] as $type) {
404				if (array_key_exists($type, $mainInterfaces) && array_key_exists($mainInterfaces[$type], $interfaces)) {
405					$interfaces[$mainInterfaces[$type]]['main'] = INTERFACE_PRIMARY;
406				}
407			}
408
409			// Add new group.
410			$groups = getRequest('groups', []);
411			$new_groups = [];
412
413			foreach ($groups as $idx => $group) {
414				if (is_array($group) && array_key_exists('new', $group)) {
415					$new_groups[] = ['name' => $group['new']];
416					unset($groups[$idx]);
417				}
418			}
419
420			if ($new_groups) {
421				$new_groupid = API::HostGroup()->create($new_groups);
422
423				if (!$new_groupid) {
424					throw new Exception();
425				}
426
427				$groups = array_merge($groups, $new_groupid['groupids']);
428			}
429
430			// Host data.
431			$host = [
432				'host' => getRequest('host'),
433				'name' => getRequest('visiblename'),
434				'status' => getRequest('status', HOST_STATUS_NOT_MONITORED),
435				'description' => getRequest('description'),
436				'proxy_hostid' => getRequest('proxy_hostid', 0),
437				'ipmi_authtype' => getRequest('ipmi_authtype'),
438				'ipmi_privilege' => getRequest('ipmi_privilege'),
439				'ipmi_username' => getRequest('ipmi_username'),
440				'ipmi_password' => getRequest('ipmi_password'),
441				'tls_connect' => getRequest('tls_connect', HOST_ENCRYPTION_NONE),
442				'tls_accept' => getRequest('tls_accept', HOST_ENCRYPTION_NONE),
443				'groups' => zbx_toObject($groups, 'groupid'),
444				'templates' => $templates,
445				'interfaces' => $interfaces,
446				'tags' => $tags,
447				'macros' => $macros,
448				'inventory_mode' => getRequest('inventory_mode'),
449				'inventory' => (getRequest('inventory_mode') == HOST_INVENTORY_DISABLED)
450					? []
451					: getRequest('host_inventory', [])
452			];
453
454			if ($host['tls_connect'] == HOST_ENCRYPTION_PSK || ($host['tls_accept'] & HOST_ENCRYPTION_PSK)) {
455				// Add values to PSK fields from cloned host.
456				if ($create && (getRequest('form', '') === 'clone' || getRequest('form', '') === 'full_clone')
457						&& getRequest('clone_hostid', 0) != 0) {
458					$clone_hosts = API::Host()->get([
459						'output' => ['tls_psk_identity', 'tls_psk'],
460						'hostids' => getRequest('clone_hostid'),
461						'editable' => true
462					]);
463					$clone_host = reset($clone_hosts);
464
465					$host['tls_psk_identity'] = $clone_host['tls_psk_identity'];
466					$host['tls_psk'] = $clone_host['tls_psk'];
467				}
468
469				if (hasRequest('tls_psk_identity')) {
470					$host['tls_psk_identity'] = getRequest('tls_psk_identity');
471				}
472
473				if (hasRequest('tls_psk')) {
474					$host['tls_psk'] = getRequest('tls_psk');
475				}
476			}
477
478			if ($host['tls_connect'] == HOST_ENCRYPTION_CERTIFICATE
479					|| ($host['tls_accept'] & HOST_ENCRYPTION_CERTIFICATE)) {
480				$host['tls_issuer'] = getRequest('tls_issuer', '');
481				$host['tls_subject'] = getRequest('tls_subject', '');
482			}
483
484			if (!$create) {
485				$host['templates_clear'] = zbx_toObject(getRequest('clear_templates', []), 'templateid');
486			}
487		}
488
489		if ($create) {
490			$hostIds = API::Host()->create($host);
491
492			if ($hostIds) {
493				$hostId = reset($hostIds['hostids']);
494			}
495			else {
496				throw new Exception();
497			}
498		}
499		else {
500			$host['hostid'] = $hostId;
501
502			if (!API::Host()->update($host)) {
503				throw new Exception();
504			}
505		}
506
507		$valuemaps = getRequest('valuemaps', []);
508		$ins_valuemaps = [];
509		$upd_valuemaps = [];
510		$del_valuemapids = [];
511
512		if ((getRequest('form', '') === 'full_clone' || getRequest('form', '') === 'clone')
513				&& getRequest('clone_hostid', 0) != 0) {
514			foreach ($valuemaps as &$valuemap) {
515				unset($valuemap['valuemapid']);
516			}
517			unset($valuemap);
518		}
519		else if (hasRequest('update')) {
520			$del_valuemapids = API::ValueMap()->get([
521				'output' => [],
522				'hostids' => $hostId,
523				'preservekeys' => true
524			]);
525		}
526
527		foreach ($valuemaps as $valuemap) {
528			if (array_key_exists('valuemapid', $valuemap)) {
529				$upd_valuemaps[] = $valuemap;
530				unset($del_valuemapids[$valuemap['valuemapid']]);
531			}
532			else {
533				$ins_valuemaps[] = $valuemap + ['hostid' => $hostId];
534			}
535		}
536
537		if ($upd_valuemaps && !API::ValueMap()->update($upd_valuemaps)) {
538			throw new Exception();
539		}
540
541		if ($ins_valuemaps && !API::ValueMap()->create($ins_valuemaps)) {
542			throw new Exception();
543		}
544
545		if ($del_valuemapids && !API::ValueMap()->delete(array_keys($del_valuemapids))) {
546			throw new Exception();
547		}
548
549		// full clone
550		if (getRequest('form', '') === 'full_clone' && getRequest('clone_hostid', 0) != 0) {
551			$srcHostId = getRequest('clone_hostid');
552
553			/*
554			 * First copy web scenarios with web items, so that later regular items can use web item as their master
555			 * item.
556			 */
557			if (!copyHttpTests($srcHostId, $hostId)) {
558				throw new Exception();
559			}
560
561			if (!copyItems($srcHostId, $hostId)) {
562				throw new Exception();
563			}
564
565			// copy triggers
566			$dbTriggers = API::Trigger()->get([
567				'output' => ['triggerid'],
568				'hostids' => $srcHostId,
569				'inherited' => false,
570				'filter' => ['flags' => ZBX_FLAG_DISCOVERY_NORMAL]
571			]);
572
573			if ($dbTriggers && !copyTriggersToHosts(zbx_objectValues($dbTriggers, 'triggerid'), $hostId, $srcHostId)) {
574				throw new Exception();
575			}
576
577			// copy discovery rules
578			$dbDiscoveryRules = API::DiscoveryRule()->get([
579				'output' => ['itemid'],
580				'hostids' => $srcHostId,
581				'inherited' => false
582			]);
583
584			if ($dbDiscoveryRules) {
585				$copyDiscoveryRules = API::DiscoveryRule()->copy([
586					'discoveryids' => zbx_objectValues($dbDiscoveryRules, 'itemid'),
587					'hostids' => [$hostId]
588				]);
589
590				if (!$copyDiscoveryRules) {
591					throw new Exception();
592				}
593			}
594
595			// copy graphs
596			$dbGraphs = API::Graph()->get([
597				'output' => API_OUTPUT_EXTEND,
598				'selectHosts' => ['hostid'],
599				'selectItems' => ['type'],
600				'hostids' => $srcHostId,
601				'filter' => ['flags' => ZBX_FLAG_DISCOVERY_NORMAL],
602				'inherited' => false
603			]);
604
605			foreach ($dbGraphs as $dbGraph) {
606				if (count($dbGraph['hosts']) > 1) {
607					continue;
608				}
609
610				if (httpItemExists($dbGraph['items'])) {
611					continue;
612				}
613
614				if (!copyGraphToHost($dbGraph['graphid'], $hostId)) {
615					throw new Exception();
616				}
617			}
618		}
619
620		$result = DBend(true);
621
622		if ($result) {
623			uncheckTableRows();
624		}
625		show_messages($result, $msgOk, $msgFail);
626
627		unset($_REQUEST['form'], $_REQUEST['hostid']);
628	}
629	catch (Exception $e) {
630		DBend(false);
631		show_messages(false, $msgOk, $msgFail);
632	}
633}
634elseif (hasRequest('delete') && hasRequest('hostid')) {
635	DBstart();
636
637	$result = API::Host()->delete([getRequest('hostid')]);
638	$result = DBend($result);
639
640	if ($result) {
641		unset($_REQUEST['form'], $_REQUEST['hostid']);
642		uncheckTableRows();
643	}
644	show_messages($result, _('Host deleted'), _('Cannot delete host'));
645
646	unset($_REQUEST['delete']);
647}
648elseif (hasRequest('hosts') && hasRequest('action') && getRequest('action') === 'host.massdelete') {
649	DBstart();
650
651	$result = API::Host()->delete(getRequest('hosts'));
652	$result = DBend($result);
653
654	if ($result) {
655		uncheckTableRows();
656	}
657	else {
658		$hostids = API::Host()->get([
659			'output' => [],
660			'hostids' => getRequest('hosts'),
661			'editable' => true
662		]);
663		uncheckTableRows(getRequest('hostid'), zbx_objectValues($hostids, 'hostid'));
664	}
665	show_messages($result, _('Host deleted'), _('Cannot delete host'));
666}
667elseif (hasRequest('hosts') && hasRequest('action') && str_in_array(getRequest('action'), ['host.massenable', 'host.massdisable'])) {
668	$enable = (getRequest('action') === 'host.massenable');
669	$status = $enable ? TRIGGER_STATUS_ENABLED : TRIGGER_STATUS_DISABLED;
670
671	$actHosts = API::Host()->get([
672		'hostids' => getRequest('hosts'),
673		'editable' => true,
674		'templated_hosts' => true,
675		'output' => ['hostid']
676	]);
677
678	if ($actHosts) {
679		foreach ($actHosts as &$host) {
680			$host['status'] = $status;
681		}
682		unset($host);
683
684		$result = (bool) API::Host()->update($actHosts);
685
686		if ($result) {
687			uncheckTableRows();
688		}
689
690		$updated = count($actHosts);
691
692		$messageSuccess = $enable
693			? _n('Host enabled', 'Hosts enabled', $updated)
694			: _n('Host disabled', 'Hosts disabled', $updated);
695		$messageFailed = $enable
696			? _n('Cannot enable host', 'Cannot enable hosts', $updated)
697			: _n('Cannot disable host', 'Cannot disable hosts', $updated);
698
699		show_messages($result, $messageSuccess, $messageFailed);
700	}
701}
702
703/*
704 * Display
705 */
706if (hasRequest('form')) {
707	$data = [
708		// Common & auxiliary
709		'form' => getRequest('form', ''),
710		'hostid' => getRequest('hostid', 0),
711		'clone_hostid' => getRequest('clone_hostid', 0),
712		'flags' => getRequest('flags', ZBX_FLAG_DISCOVERY_NORMAL),
713
714		// Host
715		'host' => getRequest('host', ''),
716		'visiblename' => getRequest('visiblename', ''),
717		'interfaces' => getRequest('interfaces', []),
718		'mainInterfaces' => getRequest('mainInterfaces', []),
719		'description' => getRequest('description', ''),
720		'proxy_hostid' => getRequest('proxy_hostid', 0),
721		'status' => getRequest('status', HOST_STATUS_NOT_MONITORED),
722
723		// Templates
724		'templates' => getRequest('templates', []),
725		'add_templates' => [],
726		'clear_templates' => getRequest('clear_templates', []),
727		'original_templates' => [],
728		'linked_templates' => [],
729		'parent_templates' => [],
730
731		// IPMI
732		'ipmi_authtype' => getRequest('ipmi_authtype', IPMI_AUTHTYPE_DEFAULT),
733		'ipmi_privilege' => getRequest('ipmi_privilege', IPMI_PRIVILEGE_USER),
734		'ipmi_username' => getRequest('ipmi_username', ''),
735		'ipmi_password' => getRequest('ipmi_password', ''),
736
737		// Tags
738		'tags' => $tags,
739
740		// Macros
741		'macros' => $macros,
742		'show_inherited_macros' => getRequest('show_inherited_macros', 0),
743
744		// Host inventory
745		'inventory_mode' => getRequest('inventory_mode', CSettingsHelper::get(CSettingsHelper::DEFAULT_INVENTORY_MODE)),
746		'host_inventory' => getRequest('host_inventory', []),
747		'inventory_items' => [],
748
749		// Encryption
750		'tls_connect' => getRequest('tls_connect', HOST_ENCRYPTION_NONE),
751		'tls_accept' => getRequest('tls_accept', HOST_ENCRYPTION_NONE),
752		'tls_issuer' => getRequest('tls_issuer', ''),
753		'tls_subject' => getRequest('tls_subject', ''),
754		'tls_psk_identity' => getRequest('tls_psk_identity', ''),
755		'tls_psk' => getRequest('tls_psk', ''),
756		'psk_edit_mode' => getRequest('psk_edit_mode', 1),
757
758		// Valuemap
759		'valuemaps' => array_values(getRequest('valuemaps', []))
760	];
761
762	if (!hasRequest('form_refresh')) {
763		if ($data['hostid'] != 0) {
764			$dbHosts = API::Host()->get([
765				'output' => ['hostid', 'proxy_hostid', 'host', 'name', 'status', 'ipmi_authtype', 'ipmi_privilege',
766					'ipmi_username', 'ipmi_password', 'flags', 'description', 'tls_connect', 'tls_accept', 'tls_issuer',
767					'tls_subject', 'inventory_mode'
768				],
769				'selectGroups' => ['groupid'],
770				'selectParentTemplates' => ['templateid'],
771				'selectMacros' => ['hostmacroid', 'macro', 'value', 'description', 'type'],
772				'selectDiscoveryRule' => ['itemid', 'name'],
773				'selectHostDiscovery' => ['parent_hostid'],
774				'selectInventory' => API_OUTPUT_EXTEND,
775				'selectTags' => ['tag', 'value'],
776				'selectValueMaps' => ['valuemapid', 'name', 'mappings'],
777				'hostids' => [$data['hostid']]
778			]);
779			$dbHost = reset($dbHosts);
780
781			$data['flags'] = $dbHost['flags'];
782			if ($data['flags'] == ZBX_FLAG_DISCOVERY_CREATED) {
783				$data['discoveryRule'] = $dbHost['discoveryRule'];
784				$data['hostDiscovery'] = $dbHost['hostDiscovery'];
785			}
786
787			// Host
788			$data['host'] = $dbHost['host'];
789			$data['visiblename'] = $dbHost['name'];
790			$data['interfaces'] = API::HostInterface()->get([
791				'output' => API_OUTPUT_EXTEND,
792				'selectItems' => ['itemid'],
793				'hostids' => [$data['hostid']],
794				'sortfield' => 'interfaceid'
795			]);
796			$data['description'] = $dbHost['description'];
797			$data['proxy_hostid'] = $dbHost['proxy_hostid'];
798			$data['status'] = $dbHost['status'];
799
800			// Templates
801			$data['templates'] = zbx_objectValues($dbHost['parentTemplates'], 'templateid');
802			$data['original_templates'] = array_combine($data['templates'], $data['templates']);
803
804			// IPMI
805			$data['ipmi_authtype'] = $dbHost['ipmi_authtype'];
806			$data['ipmi_privilege'] = $dbHost['ipmi_privilege'];
807			$data['ipmi_username'] = $dbHost['ipmi_username'];
808			$data['ipmi_password'] = $dbHost['ipmi_password'];
809
810			// Tags
811			$data['tags'] = $dbHost['tags'];
812
813			// Macros
814			$data['macros'] = $dbHost['macros'];
815
816			// Interfaces
817			foreach ($data['interfaces'] as &$interface) {
818				$interface['items'] = (bool) $interface['items'];
819			}
820			unset($interface);
821
822			// Host inventory
823			$data['inventory_mode'] = $dbHost['inventory_mode'];
824			$data['host_inventory'] = $dbHost['inventory'];
825
826			// Encryption
827			$data['tls_connect'] = $dbHost['tls_connect'];
828			$data['tls_accept'] = $dbHost['tls_accept'];
829			$data['tls_issuer'] = $dbHost['tls_issuer'];
830			$data['tls_subject'] = $dbHost['tls_subject'];
831
832			if ($dbHost['tls_connect'] == HOST_ENCRYPTION_PSK || ($dbHost['tls_accept'] & HOST_ENCRYPTION_PSK)) {
833				$data['psk_edit_mode'] = 0;
834			}
835
836			// display empty visible name if equal to host name
837			if ($data['host'] === $data['visiblename']) {
838				$data['visiblename'] = '';
839			}
840
841			// Valuemap
842			order_result($dbHost['valuemaps'], 'name');
843			$data['valuemaps'] = array_values($dbHost['valuemaps']);
844
845			$groups = zbx_objectValues($dbHost['groups'], 'groupid');
846		}
847		else {
848			$groups = getRequest('groupids', []);
849
850			$data['status'] = HOST_STATUS_MONITORED;
851		}
852	}
853	else {
854		if ($data['hostid'] != 0) {
855			$dbHosts = API::Host()->get([
856				'output' => ['flags'],
857				'selectParentTemplates' => ['templateid'],
858				'selectDiscoveryRule' => ['itemid', 'name'],
859				'selectHostDiscovery' => ['parent_hostid'],
860				'hostids' => [$data['hostid']]
861			]);
862			$dbHost = reset($dbHosts);
863
864			$data['flags'] = $dbHost['flags'];
865			if ($data['flags'] == ZBX_FLAG_DISCOVERY_CREATED) {
866				$data['discoveryRule'] = $dbHost['discoveryRule'];
867				$data['hostDiscovery'] = $dbHost['hostDiscovery'];
868			}
869
870			$templateids = zbx_objectValues($dbHost['parentTemplates'], 'templateid');
871			$data['original_templates'] = array_combine($templateids, $templateids);
872		}
873
874		foreach ([INTERFACE_TYPE_AGENT, INTERFACE_TYPE_SNMP, INTERFACE_TYPE_JMX, INTERFACE_TYPE_IPMI] as $type) {
875			if (array_key_exists($type, $data['mainInterfaces'])) {
876				$interfaceid = $data['mainInterfaces'][$type];
877				$data['interfaces'][$interfaceid]['main'] = '1';
878			}
879		}
880		$data['interfaces'] = array_values($data['interfaces']);
881
882		$groups = getRequest('groups', []);
883	}
884
885	$data['readonly'] = ($data['flags'] == ZBX_FLAG_DISCOVERY_CREATED);
886
887	if ($data['hostid'] != 0) {
888		// get items that populate host inventory fields
889		$data['inventory_items'] = API::Item()->get([
890			'output' => ['inventory_link', 'itemid', 'hostid', 'name', 'key_'],
891			'hostids' => [$dbHost['hostid']],
892			'filter' => ['inventory_link' => array_keys(getHostInventories())]
893		]);
894		$data['inventory_items'] = zbx_toHash($data['inventory_items'], 'inventory_link');
895		$data['inventory_items'] = CMacrosResolverHelper::resolveItemNames($data['inventory_items']);
896	}
897
898	if ($data['flags'] == ZBX_FLAG_DISCOVERY_CREATED) {
899		if ($data['proxy_hostid'] != 0) {
900			$data['proxies'] = API::Proxy()->get([
901				'output' => ['host'],
902				'proxyids' => [$data['proxy_hostid']],
903				'preservekeys' => true
904			]);
905		}
906		else {
907			$data['proxies'] = [];
908		}
909	}
910	else {
911		$data['proxies'] = API::Proxy()->get([
912			'output' => ['host'],
913			'preservekeys' => true
914		]);
915		order_result($data['proxies'], 'host');
916	}
917
918	foreach ($data['proxies'] as &$proxy) {
919		$proxy = $proxy['host'];
920	}
921	unset($proxy);
922
923	// tags
924	if (!$data['tags']) {
925		$data['tags'][] = ['tag' => '', 'value' => ''];
926	}
927	else {
928		CArrayHelper::sort($data['tags'], ['tag', 'value']);
929	}
930
931	// Add inherited macros to host macros.
932	if ($data['show_inherited_macros']) {
933		$data['macros'] = mergeInheritedMacros($data['macros'], getInheritedMacros(
934			array_merge($data['templates'], getRequest('add_templates', []))
935		));
936	}
937
938	// Sort only after inherited macros are added. Otherwise the list will look chaotic.
939	$data['macros'] = array_values(order_macros($data['macros'], 'macro'));
940
941	if (!$data['macros'] && !$data['readonly']) {
942		$macro = ['macro' => '', 'value' => '', 'description' => '', 'type' => ZBX_MACRO_TYPE_TEXT];
943
944		if ($data['show_inherited_macros']) {
945			$macro['inherited_type'] = ZBX_PROPERTY_OWN;
946		}
947
948		$data['macros'][] = $macro;
949	}
950
951	$groupids = [];
952
953	foreach ($groups as $group) {
954		if (is_array($group) && array_key_exists('new', $group)) {
955			continue;
956		}
957
958		$groupids[] = $group;
959	}
960
961	// Groups with R and RW permissions.
962	$groups_all = $groupids
963		? API::HostGroup()->get([
964			'output' => ['name'],
965			'groupids' => $groupids,
966			'preservekeys' => true
967		])
968		: [];
969
970	// Groups with RW permissions.
971	$groups_rw = $groupids && (CWebUser::getType() != USER_TYPE_SUPER_ADMIN)
972		? API::HostGroup()->get([
973			'output' => [],
974			'groupids' => $groupids,
975			'editable' => true,
976			'preservekeys' => true
977		])
978		: [];
979
980	$data['groups_ms'] = [];
981
982	// Prepare data for multiselect.
983	foreach ($groups as $group) {
984		if (is_array($group) && array_key_exists('new', $group)) {
985			$data['groups_ms'][] = [
986				'id' => $group['new'],
987				'name' => $group['new'].' ('._x('new', 'new element in multiselect').')',
988				'isNew' => true
989			];
990		}
991		elseif (array_key_exists($group, $groups_all)) {
992			$data['groups_ms'][] = [
993				'id' => $group,
994				'name' => $groups_all[$group]['name'],
995				'disabled' => (CWebUser::getType() != USER_TYPE_SUPER_ADMIN) && !array_key_exists($group, $groups_rw)
996			];
997		}
998	}
999	CArrayHelper::sort($data['groups_ms'], ['name']);
1000
1001	// Add already linked and new templates.
1002	$request_add_templates = getRequest('add_templates', []);
1003
1004	if ($data['templates'] || $request_add_templates) {
1005		$templates = API::Template()->get([
1006			'output' => ['templateid', 'name'],
1007			'templateids' => array_merge($data['templates'], $request_add_templates),
1008			'preservekeys' => true
1009		]);
1010
1011		$data['linked_templates'] = array_intersect_key($templates, array_flip($data['templates']));
1012		CArrayHelper::sort($data['linked_templates'], ['name']);
1013
1014		$data['add_templates'] = array_intersect_key($templates, array_flip($request_add_templates));
1015
1016		foreach ($data['add_templates'] as &$template) {
1017			$template = CArrayHelper::renameKeys($template, ['templateid' => 'id']);
1018		}
1019		unset($template);
1020
1021		if ($data['templates']) {
1022			$data['writable_templates'] = API::Template()->get([
1023				'output' => ['templateid'],
1024				'templateids' => $data['templates'],
1025				'editable' => true,
1026				'preservekeys' => true
1027			]);
1028		}
1029	}
1030
1031	// This data is used in common.template.edit.js.php.
1032	$data['macros_tab'] = [
1033		'linked_templates' => array_map('strval', array_keys($data['linked_templates'])),
1034		'add_templates' => array_map('strval', array_keys($data['add_templates']))
1035	];
1036
1037	$data['allowed_ui_conf_templates'] = CWebUser::checkAccess(CRoleHelper::UI_CONFIGURATION_TEMPLATES);
1038
1039	$hostView = new CView('configuration.host.edit', $data);
1040}
1041else {
1042	$sortField = getRequest('sort', CProfile::get('web.'.$page['file'].'.sort', 'name'));
1043	$sortOrder = getRequest('sortorder', CProfile::get('web.'.$page['file'].'.sortorder', ZBX_SORT_UP));
1044
1045	CProfile::update('web.'.$page['file'].'.sort', $sortField, PROFILE_TYPE_STR);
1046	CProfile::update('web.'.$page['file'].'.sortorder', $sortOrder, PROFILE_TYPE_STR);
1047
1048	// Get host groups.
1049	$filter['groups'] = $filter['groups']
1050		? CArrayHelper::renameObjectsKeys(API::HostGroup()->get([
1051			'output' => ['groupid', 'name'],
1052			'groupids' => $filter['groups'],
1053			'editable' => true,
1054			'preservekeys' => true
1055		]), ['groupid' => 'id'])
1056		: [];
1057
1058	$filter_groupids = $filter['groups'] ? array_keys($filter['groups']) : null;
1059	if ($filter_groupids) {
1060		$filter_groupids = getSubGroups($filter_groupids);
1061	}
1062
1063	// Get templates.
1064	$filter['templates'] = $filter['templates']
1065		? CArrayHelper::renameObjectsKeys(API::Template()->get([
1066			'output' => ['templateid', 'name'],
1067			'templateids' => $filter['templates'],
1068			'preservekeys' => true
1069		]), ['templateid' => 'id'])
1070		: [];
1071
1072	switch ($filter['monitored_by']) {
1073		case ZBX_MONITORED_BY_ANY:
1074			$proxyids = null;
1075			break;
1076
1077		case ZBX_MONITORED_BY_PROXY:
1078			$proxyids = $filter['proxyids']
1079				? $filter['proxyids']
1080				: array_keys(API::Proxy()->get([
1081					'output' => [],
1082					'preservekeys' => true
1083				]));
1084			break;
1085
1086		case ZBX_MONITORED_BY_SERVER:
1087			$proxyids = 0;
1088			break;
1089	}
1090
1091	// Select hosts.
1092	$limit = CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1;
1093	$hosts = API::Host()->get([
1094		'output' => ['hostid', $sortField],
1095		'evaltype' => $filter['evaltype'],
1096		'tags' => $filter['tags'],
1097		'groupids' => $filter_groupids,
1098		'templateids' => $filter['templates'] ? array_keys($filter['templates']) : null,
1099		'editable' => true,
1100		'sortfield' => $sortField,
1101		'limit' => $limit,
1102		'search' => [
1103			'name' => ($filter['host'] === '') ? null : $filter['host'],
1104			'ip' => ($filter['ip'] === '') ? null : $filter['ip'],
1105			'dns' => ($filter['dns'] === '') ? null : $filter['dns']
1106		],
1107		'filter' => [
1108			'port' => ($filter['port'] === '') ? null : $filter['port']
1109		],
1110		'proxyids' => $proxyids
1111	]);
1112
1113	order_result($hosts, $sortField, $sortOrder);
1114
1115	// pager
1116	if (hasRequest('page')) {
1117		$page_num = getRequest('page');
1118	}
1119	elseif (isRequestMethod('get') && !hasRequest('cancel')) {
1120		$page_num = 1;
1121	}
1122	else {
1123		$page_num = CPagerHelper::loadPage($page['file']);
1124	}
1125
1126	CPagerHelper::savePage($page['file'], $page_num);
1127
1128	$pagingLine = CPagerHelper::paginate($page_num, $hosts, $sortOrder, new CUrl('hosts.php'));
1129
1130	$hosts = API::Host()->get([
1131		'output' => API_OUTPUT_EXTEND,
1132		'selectParentTemplates' => ['templateid', 'name'],
1133		'selectInterfaces' => API_OUTPUT_EXTEND,
1134		'selectItems' => API_OUTPUT_COUNT,
1135		'selectDiscoveries' => API_OUTPUT_COUNT,
1136		'selectTriggers' => API_OUTPUT_COUNT,
1137		'selectGraphs' => API_OUTPUT_COUNT,
1138		'selectHttpTests' => API_OUTPUT_COUNT,
1139		'selectDiscoveryRule' => ['itemid', 'name'],
1140		'selectHostDiscovery' => ['ts_delete'],
1141		'selectTags' => ['tag', 'value'],
1142		'hostids' => zbx_objectValues($hosts, 'hostid'),
1143		'preservekeys' => true
1144	]);
1145	order_result($hosts, $sortField, $sortOrder);
1146
1147	// selecting linked templates to templates linked to hosts
1148	$templateids = [];
1149
1150	foreach ($hosts as $host) {
1151		$templateids = array_merge($templateids, zbx_objectValues($host['parentTemplates'], 'templateid'));
1152	}
1153
1154	$templateids = array_keys(array_flip($templateids));
1155
1156	$templates = API::Template()->get([
1157		'output' => ['templateid', 'name'],
1158		'selectParentTemplates' => ['templateid', 'name'],
1159		'templateids' => $templateids,
1160		'preservekeys' => true
1161	]);
1162
1163	// selecting writable templates IDs
1164	$writable_templates = [];
1165	if ($templateids) {
1166		foreach ($templates as $template) {
1167			$templateids = array_merge($templateids, zbx_objectValues($template['parentTemplates'], 'templateid'));
1168		}
1169
1170		$writable_templates = API::Template()->get([
1171			'output' => ['templateid'],
1172			'templateids' => array_keys(array_flip($templateids)),
1173			'editable' => true,
1174			'preservekeys' => true
1175		]);
1176	}
1177
1178	// Get proxy host IDs that are not 0 and maintenance IDs.
1179	$proxyHostIds = [];
1180	$maintenanceids = [];
1181
1182	foreach ($hosts as &$host) {
1183		// Sort interfaces to be listed starting with one selected as 'main'.
1184		CArrayHelper::sort($host['interfaces'], [
1185			['field' => 'main', 'order' => ZBX_SORT_DOWN]
1186		]);
1187
1188		if ($host['proxy_hostid']) {
1189			$proxyHostIds[$host['proxy_hostid']] = $host['proxy_hostid'];
1190		}
1191
1192		if ($host['status'] == HOST_STATUS_MONITORED && $host['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) {
1193			$maintenanceids[$host['maintenanceid']] = true;
1194		}
1195	}
1196	unset($host);
1197
1198	$proxies = [];
1199	if ($proxyHostIds) {
1200		$proxies = API::Proxy()->get([
1201			'proxyids' => $proxyHostIds,
1202			'output' => ['host'],
1203			'preservekeys' => true
1204		]);
1205	}
1206
1207	// Prepare data for multiselect and remove unexisting proxies.
1208	$proxies_ms = [];
1209	if ($filter['proxyids']) {
1210		$filter_proxies = API::Proxy()->get([
1211			'output' => ['proxyid', 'host'],
1212			'proxyids' => $filter['proxyids']
1213		]);
1214
1215		$proxies_ms = CArrayHelper::renameObjectsKeys($filter_proxies, ['proxyid' => 'id', 'host' => 'name']);
1216	}
1217
1218	$db_maintenances = [];
1219
1220	if ($maintenanceids) {
1221		$db_maintenances = API::Maintenance()->get([
1222			'output' => ['name', 'description'],
1223			'maintenanceids' => array_keys($maintenanceids),
1224			'preservekeys' => true
1225		]);
1226	}
1227
1228	$data = [
1229		'hosts' => $hosts,
1230		'paging' => $pagingLine,
1231		'page' => $page_num,
1232		'filter' => $filter,
1233		'sortField' => $sortField,
1234		'sortOrder' => $sortOrder,
1235		'templates' => $templates,
1236		'maintenances' => $db_maintenances,
1237		'writable_templates' => $writable_templates,
1238		'proxies' => $proxies,
1239		'proxies_ms' => $proxies_ms,
1240		'profileIdx' => 'web.hosts.filter',
1241		'active_tab' => CProfile::get('web.hosts.filter.active', 1),
1242		'tags' => makeTags($hosts, true, 'hostid', ZBX_TAG_COUNT_DEFAULT, $filter['tags']),
1243		'config' => [
1244			'max_in_table' => CSettingsHelper::get(CSettingsHelper::MAX_IN_TABLE)
1245		],
1246		'allowed_ui_conf_templates' => CWebUser::checkAccess(CRoleHelper::UI_CONFIGURATION_TEMPLATES)
1247	];
1248
1249	$hostView = new CView('configuration.host.list', $data);
1250}
1251
1252echo $hostView->getOutput();
1253
1254require_once dirname(__FILE__).'/include/page_footer.php';
1255