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